summaryrefslogtreecommitdiff
path: root/chromium/cc
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2022-09-29 16:16:15 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2022-11-09 10:04:06 +0000
commita95a7417ad456115a1ef2da4bb8320531c0821f1 (patch)
treeedcd59279e486d2fd4a8f88a7ed025bcf925c6e6 /chromium/cc
parent33fc33aa94d4add0878ec30dc818e34e1dd3cc2a (diff)
downloadqtwebengine-chromium-a95a7417ad456115a1ef2da4bb8320531c0821f1.tar.gz
BASELINE: Update Chromium to 106.0.5249.126
Change-Id: Ib0bb21c437a7d1686e21c33f2d329f2ac425b7ab Reviewed-on: https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/438936 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/cc')
-rw-r--r--chromium/cc/BUILD.gn8
-rw-r--r--chromium/cc/OWNERS3
-rw-r--r--chromium/cc/animation/animation_host_unittest.cc13
-rw-r--r--chromium/cc/animation/animation_unittest.cc23
-rw-r--r--chromium/cc/animation/element_animations.cc7
-rw-r--r--chromium/cc/animation/element_animations_unittest.cc11
-rw-r--r--chromium/cc/animation/keyframe_model.cc25
-rw-r--r--chromium/cc/animation/keyframe_model.h6
-rw-r--r--chromium/cc/animation/scroll_offset_animation_curve_factory.cc2
-rw-r--r--chromium/cc/animation/scroll_timeline.cc82
-rw-r--r--chromium/cc/animation/scroll_timeline.h78
-rw-r--r--chromium/cc/animation/scroll_timeline_unittest.cc216
-rw-r--r--chromium/cc/animation/worklet_animation_unittest.cc2
-rw-r--r--chromium/cc/base/BUILD.gn1
-rw-r--r--chromium/cc/base/features.cc15
-rw-r--r--chromium/cc/base/features.h6
-rw-r--r--chromium/cc/base/math_util.cc2
-rw-r--r--chromium/cc/base/rtree.h3
-rw-r--r--chromium/cc/base/synced_property.h95
-rw-r--r--chromium/cc/input/compositor_input_interfaces.h7
-rw-r--r--chromium/cc/input/input_handler.cc (renamed from chromium/cc/input/threaded_input_handler.cc)274
-rw-r--r--chromium/cc/input/input_handler.h467
-rw-r--r--chromium/cc/input/main_thread_scrolling_reason.cc12
-rw-r--r--chromium/cc/input/main_thread_scrolling_reason.h42
-rw-r--r--chromium/cc/input/scroll_utils.cc10
-rw-r--r--chromium/cc/input/scroll_utils.h7
-rw-r--r--chromium/cc/input/scrollbar_animation_controller.cc8
-rw-r--r--chromium/cc/input/scrollbar_animation_controller.h10
-rw-r--r--chromium/cc/input/scrollbar_animation_controller_unittest.cc63
-rw-r--r--chromium/cc/input/single_scrollbar_animation_controller_thinning.cc73
-rw-r--r--chromium/cc/input/single_scrollbar_animation_controller_thinning.h9
-rw-r--r--chromium/cc/input/single_scrollbar_animation_controller_thinning_unittest.cc145
-rw-r--r--chromium/cc/input/threaded_input_handler.h472
-rw-r--r--chromium/cc/input/touch_action.h16
-rw-r--r--chromium/cc/layers/heads_up_display_layer_impl.cc135
-rw-r--r--chromium/cc/layers/heads_up_display_layer_impl.h4
-rw-r--r--chromium/cc/layers/layer.cc27
-rw-r--r--chromium/cc/layers/layer.h16
-rw-r--r--chromium/cc/layers/layer_impl.cc8
-rw-r--r--chromium/cc/layers/layer_impl_unittest.cc3
-rw-r--r--chromium/cc/layers/layer_unittest.cc2
-rw-r--r--chromium/cc/layers/nine_patch_generator.cc2
-rw-r--r--chromium/cc/layers/painted_overlay_scrollbar_layer.cc4
-rw-r--r--chromium/cc/layers/painted_overlay_scrollbar_layer_impl.cc11
-rw-r--r--chromium/cc/layers/painted_scrollbar_layer.cc2
-rw-r--r--chromium/cc/layers/painted_scrollbar_layer_impl.cc4
-rw-r--r--chromium/cc/layers/picture_layer_impl.cc32
-rw-r--r--chromium/cc/layers/picture_layer_impl_unittest.cc8
-rw-r--r--chromium/cc/layers/picture_layer_unittest.cc6
-rw-r--r--chromium/cc/layers/recording_source_unittest.cc4
-rw-r--r--chromium/cc/layers/render_surface_impl.cc5
-rw-r--r--chromium/cc/layers/render_surface_impl.h2
-rw-r--r--chromium/cc/layers/solid_color_layer_impl.cc5
-rw-r--r--chromium/cc/layers/solid_color_scrollbar_layer_impl.cc9
-rw-r--r--chromium/cc/layers/surface_layer_impl.cc42
-rw-r--r--chromium/cc/layers/texture_layer_impl.cc3
-rw-r--r--chromium/cc/layers/ui_resource_layer_impl.cc3
-rw-r--r--chromium/cc/layers/ui_resource_layer_unittest.cc33
-rw-r--r--chromium/cc/layers/video_layer_impl.cc1
-rw-r--r--chromium/cc/layers/video_layer_impl_unittest.cc1
-rw-r--r--chromium/cc/metrics/compositor_frame_reporter.cc572
-rw-r--r--chromium/cc/metrics/compositor_frame_reporter.h84
-rw-r--r--chromium/cc/metrics/compositor_frame_reporter_unittest.cc1522
-rw-r--r--chromium/cc/metrics/compositor_frame_reporting_controller.cc38
-rw-r--r--chromium/cc/metrics/compositor_frame_reporting_controller.h9
-rw-r--r--chromium/cc/metrics/compositor_timing_history.cc49
-rw-r--r--chromium/cc/metrics/dropped_frame_counter.cc7
-rw-r--r--chromium/cc/metrics/dropped_frame_counter.h5
-rw-r--r--chromium/cc/metrics/event_latency_tracing_recorder.cc99
-rw-r--r--chromium/cc/metrics/event_latency_tracing_recorder.h17
-rw-r--r--chromium/cc/metrics/event_metrics.cc5
-rw-r--r--chromium/cc/metrics/event_metrics.h9
-rw-r--r--chromium/cc/metrics/frame_info.cc4
-rw-r--r--chromium/cc/metrics/frame_sequence_metrics.cc30
-rw-r--r--chromium/cc/metrics/frame_sequence_metrics.h5
-rw-r--r--chromium/cc/metrics/frame_sequence_tracker_unittest.cc27
-rw-r--r--chromium/cc/metrics/ukm_smoothness_data.h1
-rw-r--r--chromium/cc/metrics/video_playback_roughness_reporter.cc14
-rw-r--r--chromium/cc/mojo_embedder/async_layer_tree_frame_sink.cc4
-rw-r--r--chromium/cc/mojo_embedder/async_layer_tree_frame_sink.h9
-rw-r--r--chromium/cc/mojom/BUILD.gn1
-rw-r--r--chromium/cc/mojom/DEPS1
-rw-r--r--chromium/cc/mojom/render_frame_metadata.mojom3
-rw-r--r--chromium/cc/mojom/render_frame_metadata_mojom_traits.cc5
-rw-r--r--chromium/cc/mojom/render_frame_metadata_mojom_traits.h4
-rw-r--r--chromium/cc/paint/display_item_list.h8
-rw-r--r--chromium/cc/paint/display_item_list_unittest.cc155
-rw-r--r--chromium/cc/paint/filter_operation.cc21
-rw-r--r--chromium/cc/paint/filter_operation.h10
-rw-r--r--chromium/cc/paint/filter_operations_unittest.cc71
-rw-r--r--chromium/cc/paint/image_transfer_cache_entry.cc9
-rw-r--r--chromium/cc/paint/image_transfer_cache_entry_unittest.cc8
-rw-r--r--chromium/cc/paint/oop_pixeltest.cc528
-rw-r--r--chromium/cc/paint/paint_cache.cc13
-rw-r--r--chromium/cc/paint/paint_cache.h13
-rw-r--r--chromium/cc/paint/paint_cache_unittest.cc26
-rw-r--r--chromium/cc/paint/paint_canvas.h6
-rw-r--r--chromium/cc/paint/paint_filter.cc63
-rw-r--r--chromium/cc/paint/paint_filter.h26
-rw-r--r--chromium/cc/paint/paint_filter_unittest.cc8
-rw-r--r--chromium/cc/paint/paint_flags.h7
-rw-r--r--chromium/cc/paint/paint_image.cc5
-rw-r--r--chromium/cc/paint/paint_image.h7
-rw-r--r--chromium/cc/paint/paint_image_builder.h4
-rw-r--r--chromium/cc/paint/paint_image_generator.h3
-rw-r--r--chromium/cc/paint/paint_op_buffer.cc19
-rw-r--r--chromium/cc/paint/paint_op_buffer.h33
-rw-r--r--chromium/cc/paint/paint_op_buffer_fuzzer.cc5
-rw-r--r--chromium/cc/paint/paint_op_buffer_serializer.cc9
-rw-r--r--chromium/cc/paint/paint_op_buffer_serializer.h2
-rw-r--r--chromium/cc/paint/paint_op_buffer_unittest.cc125
-rw-r--r--chromium/cc/paint/paint_op_helper_unittest.cc2
-rw-r--r--chromium/cc/paint/paint_op_perftest.cc2
-rw-r--r--chromium/cc/paint/paint_op_reader.cc28
-rw-r--r--chromium/cc/paint/paint_op_writer.cc16
-rw-r--r--chromium/cc/paint/paint_shader.cc47
-rw-r--r--chromium/cc/paint/paint_shader.h28
-rw-r--r--chromium/cc/paint/paint_worklet_input.cc2
-rw-r--r--chromium/cc/paint/paint_worklet_input.h4
-rw-r--r--chromium/cc/paint/record_paint_canvas.cc10
-rw-r--r--chromium/cc/paint/record_paint_canvas.h4
-rw-r--r--chromium/cc/paint/scoped_raster_flags.cc31
-rw-r--r--chromium/cc/paint/scoped_raster_flags.h26
-rw-r--r--chromium/cc/paint/scoped_raster_flags_unittest.cc25
-rw-r--r--chromium/cc/paint/skia_paint_canvas.cc26
-rw-r--r--chromium/cc/paint/skia_paint_canvas.h4
-rw-r--r--chromium/cc/paint/skia_paint_image_generator.cc4
-rw-r--r--chromium/cc/paint/skottie_wrapper_impl.cc2
-rw-r--r--chromium/cc/paint/solid_color_analyzer_unittest.cc12
-rw-r--r--chromium/cc/paint/target_color_params.cc11
-rw-r--r--chromium/cc/paint/target_color_params.h3
-rw-r--r--chromium/cc/raster/gpu_raster_buffer_provider.cc11
-rw-r--r--chromium/cc/raster/gpu_raster_buffer_provider.h6
-rw-r--r--chromium/cc/raster/raster_source.cc4
-rw-r--r--chromium/cc/raster/raster_source.h2
-rw-r--r--chromium/cc/raster/tile_task.cc10
-rw-r--r--chromium/cc/raster/tile_task.h4
-rw-r--r--chromium/cc/resources/scoped_ui_resource.h2
-rw-r--r--chromium/cc/resources/ui_resource_bitmap.cc6
-rw-r--r--chromium/cc/resources/ui_resource_bitmap.h2
-rw-r--r--chromium/cc/resources/ui_resource_manager.cc21
-rw-r--r--chromium/cc/resources/ui_resource_manager.h24
-rw-r--r--chromium/cc/scheduler/commit_earlyout_reason.h2
-rw-r--r--chromium/cc/scheduler/scheduler.h2
-rw-r--r--chromium/cc/tiles/gpu_image_decode_cache.cc32
-rw-r--r--chromium/cc/tiles/gpu_image_decode_cache.h1
-rw-r--r--chromium/cc/tiles/gpu_image_decode_cache_perftest.cc3
-rw-r--r--chromium/cc/tiles/gpu_image_decode_cache_unittest.cc3
-rw-r--r--chromium/cc/tiles/image_controller.cc209
-rw-r--r--chromium/cc/tiles/image_controller.h51
-rw-r--r--chromium/cc/tiles/image_controller_unittest.cc91
-rw-r--r--chromium/cc/tiles/image_decode_cache_utils.cc15
-rw-r--r--chromium/cc/tiles/image_decode_cache_utils.h4
-rw-r--r--chromium/cc/tiles/software_image_decode_cache.cc20
-rw-r--r--chromium/cc/tiles/software_image_decode_cache.h3
-rw-r--r--chromium/cc/tiles/software_image_decode_cache_unittest.cc4
-rw-r--r--chromium/cc/tiles/software_image_decode_cache_unittest_combinations.cc15
-rw-r--r--chromium/cc/tiles/software_image_decode_cache_utils.cc8
-rw-r--r--chromium/cc/tiles/software_image_decode_cache_utils.h3
-rw-r--r--chromium/cc/tiles/tile.cc4
-rw-r--r--chromium/cc/tiles/tile.h2
-rw-r--r--chromium/cc/tiles/tile_draw_info.cc2
-rw-r--r--chromium/cc/tiles/tile_draw_info.h8
-rw-r--r--chromium/cc/tiles/tile_manager.cc25
-rw-r--r--chromium/cc/tiles/tile_manager.h6
-rw-r--r--chromium/cc/tiles/tile_manager_settings.h1
-rw-r--r--chromium/cc/tiles/tile_manager_unittest.cc14
-rw-r--r--chromium/cc/trees/clip_expander.cc46
-rw-r--r--chromium/cc/trees/clip_expander.h44
-rw-r--r--chromium/cc/trees/clip_node.cc16
-rw-r--r--chromium/cc/trees/clip_node.h30
-rw-r--r--chromium/cc/trees/commit_state.h2
-rw-r--r--chromium/cc/trees/draw_properties_unittest.cc242
-rw-r--r--chromium/cc/trees/draw_property_utils.cc106
-rw-r--r--chromium/cc/trees/effect_node.cc3
-rw-r--r--chromium/cc/trees/layer_tree_host.cc12
-rw-r--r--chromium/cc/trees/layer_tree_host.h12
-rw-r--r--chromium/cc/trees/layer_tree_host_client.h11
-rw-r--r--chromium/cc/trees/layer_tree_host_impl.cc241
-rw-r--r--chromium/cc/trees/layer_tree_host_impl.h34
-rw-r--r--chromium/cc/trees/layer_tree_host_impl_unittest.cc349
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_filters.cc2
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest.cc214
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_scroll.cc120
-rw-r--r--chromium/cc/trees/layer_tree_impl.cc29
-rw-r--r--chromium/cc/trees/layer_tree_impl.h9
-rw-r--r--chromium/cc/trees/layer_tree_settings.cc2
-rw-r--r--chromium/cc/trees/layer_tree_settings.h5
-rw-r--r--chromium/cc/trees/occlusion_tracker_unittest.cc4
-rw-r--r--chromium/cc/trees/property_tree.cc67
-rw-r--r--chromium/cc/trees/property_tree.h24
-rw-r--r--chromium/cc/trees/property_tree_builder.cc37
-rw-r--r--chromium/cc/trees/property_tree_builder_unittest.cc34
-rw-r--r--chromium/cc/trees/proxy.h4
-rw-r--r--chromium/cc/trees/proxy_impl.cc7
-rw-r--r--chromium/cc/trees/proxy_main.cc8
-rw-r--r--chromium/cc/trees/proxy_main.h2
-rw-r--r--chromium/cc/trees/render_frame_metadata.h2
-rw-r--r--chromium/cc/trees/single_thread_proxy.cc11
-rw-r--r--chromium/cc/trees/single_thread_proxy.h2
-rw-r--r--chromium/cc/trees/transform_node.cc1
-rw-r--r--chromium/cc/trees/transform_node.h4
-rw-r--r--chromium/cc/trees/tree_synchronizer_unittest.cc4
203 files changed, 5978 insertions, 2962 deletions
diff --git a/chromium/cc/BUILD.gn b/chromium/cc/BUILD.gn
index e52844d44a8..d8b4ab2e4db 100644
--- a/chromium/cc/BUILD.gn
+++ b/chromium/cc/BUILD.gn
@@ -43,6 +43,7 @@ cc_component("cc") {
"input/browser_controls_offset_manager_client.h",
"input/browser_controls_state.h",
"input/compositor_input_interfaces.h",
+ "input/input_handler.cc",
"input/input_handler.h",
"input/layer_selection_bound.cc",
"input/layer_selection_bound.h",
@@ -74,8 +75,6 @@ cc_component("cc") {
"input/snap_fling_curve.h",
"input/snap_selection_strategy.cc",
"input/snap_selection_strategy.h",
- "input/threaded_input_handler.cc",
- "input/threaded_input_handler.h",
"input/touch_action.h",
"layers/append_quads_data.cc",
"layers/append_quads_data.h",
@@ -346,8 +345,6 @@ cc_component("cc") {
"trees/animation_options.h",
"trees/browser_controls_params.cc",
"trees/browser_controls_params.h",
- "trees/clip_expander.cc",
- "trees/clip_expander.h",
"trees/clip_node.cc",
"trees/clip_node.h",
"trees/commit_state.cc",
@@ -565,8 +562,6 @@ cc_test_static_library("test_support") {
"test/mock_latency_info_swap_promise_monitor.h",
"test/mock_layer_tree_mutator.cc",
"test/mock_layer_tree_mutator.h",
- "test/mock_mutator_host.cc",
- "test/mock_mutator_host.h",
"test/mock_occlusion_tracker.h",
"test/paint_op_helper.h",
"test/pixel_comparator.cc",
@@ -777,7 +772,6 @@ cc_test("cc_unittests") {
"resources/resource_pool_unittest.cc",
"scheduler/scheduler_state_machine_unittest.cc",
"scheduler/scheduler_unittest.cc",
- "test/mock_mutator_host_unittest.cc",
"tiles/checker_image_tracker_unittest.cc",
"tiles/decoded_image_tracker_unittest.cc",
"tiles/gpu_image_decode_cache_unittest.cc",
diff --git a/chromium/cc/OWNERS b/chromium/cc/OWNERS
index e695df24414..cac07ec5e8a 100644
--- a/chromium/cc/OWNERS
+++ b/chromium/cc/OWNERS
@@ -49,8 +49,7 @@ flackr@chromium.org
skobes@chromium.org
# metrics
-sadrul@chromium.org
-behdadb@chromium.org
+jonross@chromium.org
# paint
sunnyps@chromium.org
diff --git a/chromium/cc/animation/animation_host_unittest.cc b/chromium/cc/animation/animation_host_unittest.cc
index fa79bed6c24..bebb3bcbdc1 100644
--- a/chromium/cc/animation/animation_host_unittest.cc
+++ b/chromium/cc/animation/animation_host_unittest.cc
@@ -337,9 +337,7 @@ TEST_F(AnimationHostTest, LayerTreeMutatorUpdateReflectsScrollAnimations) {
// Create scroll timeline that links scroll animation and worklet animation
// together.
- std::vector<double> scroll_offsets;
- scroll_offsets.push_back(0);
- scroll_offsets.push_back(100);
+ ScrollTimeline::ScrollOffsets scroll_offsets(0, 100);
auto scroll_timeline = ScrollTimeline::Create(
element_id, ScrollTimeline::ScrollDown, scroll_offsets);
@@ -380,9 +378,7 @@ TEST_F(AnimationHostTest, TickScrollLinkedAnimation) {
// Create scroll timeline that links scroll animation and scroll-linked
// animation together.
- std::vector<double> scroll_offsets;
- scroll_offsets.push_back(0);
- scroll_offsets.push_back(100);
+ ScrollTimeline::ScrollOffsets scroll_offsets(0, 100);
auto scroll_timeline = ScrollTimeline::Create(
element_id_, ScrollTimeline::ScrollDown, scroll_offsets);
@@ -458,10 +454,7 @@ TEST_F(AnimationHostTest, ScrollTimelineOffsetUpdatedByScrollAnimation) {
timeline_->AttachAnimation(mock_scroll_animation);
host_impl_->AddToTicking(mock_scroll_animation);
- std::vector<double> scroll_offsets;
- scroll_offsets.push_back(0);
- scroll_offsets.push_back(100);
-
+ ScrollTimeline::ScrollOffsets scroll_offsets(0, 100);
auto scroll_timeline = ScrollTimeline::Create(
element_id_, ScrollTimeline::ScrollDown, scroll_offsets);
diff --git a/chromium/cc/animation/animation_unittest.cc b/chromium/cc/animation/animation_unittest.cc
index 42203ab3fb1..2d35841af50 100644
--- a/chromium/cc/animation/animation_unittest.cc
+++ b/chromium/cc/animation/animation_unittest.cc
@@ -7,6 +7,7 @@
#include <memory>
#include "base/strings/stringprintf.h"
+#include "base/test/gtest_util.h"
#include "base/time/time.h"
#include "cc/animation/animation_delegate.h"
#include "cc/animation/animation_host.h"
@@ -470,6 +471,28 @@ TEST_F(AnimationTest, AddRemoveAnimationToNonAttachedAnimation) {
element_id_, ElementListType::ACTIVE, TargetProperty::FILTER));
}
+using AnimationDeathTest = AnimationTest;
+
+TEST_F(AnimationDeathTest, RemoveAddInSameFrame) {
+ client_.RegisterElementId(element_id_, ElementListType::ACTIVE);
+ host_->AddAnimationTimeline(timeline_);
+ timeline_->AttachAnimation(animation_);
+ animation_->AttachElement(element_id_);
+
+ EXPECT_TRUE(client_.mutators_need_commit());
+ client_.set_mutators_need_commit(false);
+
+ const int keyframe_model_id =
+ AddOpacityTransitionToAnimation(animation_.get(), 1., .7f, .3f, false);
+ host_->PushPropertiesTo(host_impl_, client_.GetPropertyTrees());
+
+ animation_->RemoveKeyframeModel(keyframe_model_id);
+ AddOpacityTransitionToAnimation(animation_.get(), 1., .7f, .3f, false,
+ keyframe_model_id);
+ EXPECT_DCHECK_DEATH(
+ host_->PushPropertiesTo(host_impl_, client_.GetPropertyTrees()));
+}
+
TEST_F(AnimationTest, AddRemoveAnimationCausesSetNeedsCommit) {
client_.RegisterElementId(element_id_, ElementListType::ACTIVE);
host_->AddAnimationTimeline(timeline_);
diff --git a/chromium/cc/animation/element_animations.cc b/chromium/cc/animation/element_animations.cc
index 153e0997a4f..5473179a222 100644
--- a/chromium/cc/animation/element_animations.cc
+++ b/chromium/cc/animation/element_animations.cc
@@ -238,9 +238,10 @@ void ElementAnimations::OnColorAnimated(const SkColor& value,
gfx::KeyframeModel* keyframe_model) {
DCHECK_EQ(keyframe_model->TargetProperty(),
TargetProperty::CSS_CUSTOM_PROPERTY);
- OnCustomPropertyAnimated(PaintWorkletInput::PropertyValue(value),
- KeyframeModel::ToCcKeyframeModel(keyframe_model),
- target_property_id);
+ // TODO(crbug/1308932): Remove FromColor and make all SkColor4f.
+ OnCustomPropertyAnimated(
+ PaintWorkletInput::PropertyValue(SkColor4f::FromColor(value)),
+ KeyframeModel::ToCcKeyframeModel(keyframe_model), target_property_id);
}
void ElementAnimations::OnTransformAnimated(
diff --git a/chromium/cc/animation/element_animations_unittest.cc b/chromium/cc/animation/element_animations_unittest.cc
index 63d3e3d442b..d7d288e2ca5 100644
--- a/chromium/cc/animation/element_animations_unittest.cc
+++ b/chromium/cc/animation/element_animations_unittest.cc
@@ -1151,9 +1151,11 @@ TEST_F(ElementAnimationsTest, ScrollOffsetRemovalClearsScrollDelta) {
ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting(
target_value));
- int keyframe_model_id = 1;
+ int keyframe_model_id = AnimationIdProvider::NextKeyframeModelId();
+ int group_id = AnimationIdProvider::NextGroupId();
+
std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create(
- std::move(curve), keyframe_model_id, 0,
+ std::move(curve), keyframe_model_id, group_id,
KeyframeModel::TargetPropertyId(TargetProperty::SCROLL_OFFSET)));
keyframe_model->set_needs_synchronized_start_time(true);
animation_->AddKeyframeModel(std::move(keyframe_model));
@@ -1178,11 +1180,14 @@ TEST_F(ElementAnimationsTest, ScrollOffsetRemovalClearsScrollDelta) {
EXPECT_FALSE(animation_impl_->keyframe_effect()
->scroll_offset_animation_was_interrupted());
+ keyframe_model_id = AnimationIdProvider::NextKeyframeModelId();
+ group_id = AnimationIdProvider::NextGroupId();
+
// Now, test the 2-argument version of RemoveKeyframeModel.
curve = ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting(
target_value);
keyframe_model = KeyframeModel::Create(
- std::move(curve), keyframe_model_id, 0,
+ std::move(curve), keyframe_model_id, group_id,
KeyframeModel::TargetPropertyId(TargetProperty::SCROLL_OFFSET));
keyframe_model->set_needs_synchronized_start_time(true);
animation_->AddKeyframeModel(std::move(keyframe_model));
diff --git a/chromium/cc/animation/keyframe_model.cc b/chromium/cc/animation/keyframe_model.cc
index 95d6a7a651b..67a0be62093 100644
--- a/chromium/cc/animation/keyframe_model.cc
+++ b/chromium/cc/animation/keyframe_model.cc
@@ -20,6 +20,16 @@
namespace cc {
+namespace {
+#if DCHECK_IS_ON()
+int GetNextDebugId() {
+ static int g_nextDebugId = 0;
+ g_nextDebugId++;
+ return g_nextDebugId;
+}
+#endif
+} // namespace
+
// static
const KeyframeModel* KeyframeModel::ToCcKeyframeModel(
const gfx::KeyframeModel* keyframe_model) {
@@ -92,6 +102,9 @@ std::unique_ptr<KeyframeModel> KeyframeModel::CreateImplInstance(
to_return->set_fill_mode(fill_mode());
DCHECK(!to_return->is_controlling_instance_);
to_return->is_controlling_instance_ = true;
+#if DCHECK_IS_ON()
+ to_return->debug_id_ = debug_id_;
+#endif
return to_return;
}
@@ -104,12 +117,16 @@ KeyframeModel::KeyframeModel(std::unique_ptr<gfx::AnimationCurve> curve,
target_property_id.target_property_type()),
group_(group_id),
target_property_id_(std::move(target_property_id)),
+#if DCHECK_IS_ON()
+ debug_id_(GetNextDebugId()),
+#endif
needs_synchronized_start_time_(false),
received_finished_event_(false),
is_controlling_instance_(false),
is_impl_only_(false),
affects_active_elements_(true),
- affects_pending_elements_(true) {}
+ affects_pending_elements_(true) {
+}
KeyframeModel::~KeyframeModel() = default;
@@ -158,6 +175,12 @@ bool KeyframeModel::InEffect(base::TimeTicks monotonic_time) const {
}
void KeyframeModel::PushPropertiesTo(KeyframeModel* other) const {
+#if DCHECK_IS_ON()
+ DCHECK_EQ(debug_id_, other->debug_id_)
+ << "Attempted to push properties to a model with a mismatched debug id "
+ "(i.e., different keyframe models). This can happen when keyframe "
+ "model ids are reused.";
+#endif
other->element_id_ = element_id_;
if (run_state() == KeyframeModel::PAUSED ||
other->run_state() == KeyframeModel::PAUSED) {
diff --git a/chromium/cc/animation/keyframe_model.h b/chromium/cc/animation/keyframe_model.h
index 2c9edb9170d..8bc551f3dbe 100644
--- a/chromium/cc/animation/keyframe_model.h
+++ b/chromium/cc/animation/keyframe_model.h
@@ -8,6 +8,7 @@
#include <memory>
#include <string>
+#include "base/check.h"
#include "base/time/time.h"
#include "cc/animation/animation_export.h"
#include "cc/paint/element_id.h"
@@ -156,6 +157,11 @@ class CC_ANIMATION_EXPORT KeyframeModel : public gfx::KeyframeModel {
// value on.
ElementId element_id_;
+#if DCHECK_IS_ON()
+ // This id is unique, modulo overflow. Permits quick instance equality checks.
+ int debug_id_ = 0;
+#endif
+
bool needs_synchronized_start_time_;
bool received_finished_event_;
diff --git a/chromium/cc/animation/scroll_offset_animation_curve_factory.cc b/chromium/cc/animation/scroll_offset_animation_curve_factory.cc
index 761b54947f2..553bffed391 100644
--- a/chromium/cc/animation/scroll_offset_animation_curve_factory.cc
+++ b/chromium/cc/animation/scroll_offset_animation_curve_factory.cc
@@ -35,7 +35,7 @@ ScrollOffsetAnimationCurveFactory::CreateAnimation(
if (scroll_type == ScrollType::kAutoScroll)
return CreateLinearAnimation(target_value);
- if (base::FeatureList::IsEnabled(features::kImpulseScrollAnimations))
+ if (features::IsImpulseScrollAnimationEnabled())
return CreateImpulseAnimation(target_value);
return CreateEaseInOutAnimation(
diff --git a/chromium/cc/animation/scroll_timeline.cc b/chromium/cc/animation/scroll_timeline.cc
index f8d24815f2f..06f54a413a9 100644
--- a/chromium/cc/animation/scroll_timeline.cc
+++ b/chromium/cc/animation/scroll_timeline.cc
@@ -27,33 +27,23 @@ bool IsReverse(ScrollTimeline::ScrollDirection direction) {
direction == ScrollTimeline::ScrollLeft;
}
-bool ValidateScrollOffsets(const std::vector<double>& scroll_offsets) {
- return scroll_offsets.empty() || scroll_offsets.size() >= 2.0;
-}
-
} // namespace
-template double ComputeProgress<std::vector<double>>(
- double,
- const std::vector<double>&);
-
ScrollTimeline::ScrollTimeline(absl::optional<ElementId> scroller_id,
ScrollDirection direction,
- const std::vector<double> scroll_offsets,
+ absl::optional<ScrollOffsets> scroll_offsets,
int animation_timeline_id)
: AnimationTimeline(animation_timeline_id),
pending_id_(scroller_id),
direction_(direction),
- scroll_offsets_(scroll_offsets) {
- DCHECK(ValidateScrollOffsets(scroll_offsets_));
-}
+ pending_offsets_(scroll_offsets) {}
ScrollTimeline::~ScrollTimeline() = default;
scoped_refptr<ScrollTimeline> ScrollTimeline::Create(
absl::optional<ElementId> scroller_id,
ScrollTimeline::ScrollDirection direction,
- const std::vector<double> scroll_offsets) {
+ absl::optional<ScrollOffsets> scroll_offsets) {
return base::WrapRefCounted(
new ScrollTimeline(scroller_id, direction, scroll_offsets,
AnimationIdProvider::NextTimelineId()));
@@ -61,15 +51,16 @@ scoped_refptr<ScrollTimeline> ScrollTimeline::Create(
scoped_refptr<AnimationTimeline> ScrollTimeline::CreateImplInstance() const {
return base::WrapRefCounted(
- new ScrollTimeline(pending_id_, direction_, scroll_offsets_, id()));
+ new ScrollTimeline(pending_id_, direction_, pending_offsets_, id()));
}
bool ScrollTimeline::IsActive(const ScrollTree& scroll_tree,
bool is_active_tree) const {
// Blink passes empty scroll offsets when the timeline is inactive.
- if (scroll_offsets_.empty()) {
+ if ((is_active_tree && !active_offsets_) ||
+ (!is_active_tree && !pending_offsets_))
return false;
- }
+
// If pending tree with our scroller hasn't been activated, or the scroller
// has been removed (e.g. if it is no longer composited).
if ((is_active_tree && !active_id_) || (!is_active_tree && !pending_id_))
@@ -113,35 +104,26 @@ absl::optional<base::TimeTicks> ScrollTimeline::CurrentTime(
DCHECK_GE(max_offset, 0);
DCHECK_GE(current_offset, 0);
- DCHECK_GE(scroll_offsets_.size(), 2u);
- double resolved_start_scroll_offset = scroll_offsets_[0];
- double resolved_end_scroll_offset =
- scroll_offsets_[scroll_offsets_.size() - 1];
-
- // TODO(crbug.com/1060384): Once the spec has been updated to state what the
- // expected result is when startScrollOffset >= endScrollOffset, we might need
- // to add a special case here. See
- // https://github.com/WICG/scroll-animations/issues/20
-
- // 3. If current scroll offset is less than startScrollOffset:
- if (current_offset < resolved_start_scroll_offset) {
- return base::TimeTicks();
+ double start_offset = 0;
+ double end_offset = 0;
+ if (is_active_tree) {
+ DCHECK(active_offsets_);
+ start_offset = active_offsets_->start;
+ end_offset = active_offsets_->end;
+ } else {
+ DCHECK(pending_offsets_);
+ start_offset = pending_offsets_->start;
+ end_offset = pending_offsets_->end;
}
- // 4. If current scroll offset is greater than or equal to endScrollOffset:
- if (current_offset >= resolved_end_scroll_offset) {
- return base::TimeTicks() + base::Milliseconds(kScrollTimelineDurationMs);
- }
-
- // Otherwise,
- // 5.1 Let progress be a result of applying calculate scroll timeline progress
- // procedure for current scroll offset.
- // 5.2 The current time is the result of evaluating the following expression:
- // progress × timeline duration to get the percentage
+ // TODO(crbug.com/1338167): Update once
+ // github.com/w3c/csswg-drafts/issues/7401 is resolved.
+ double progress =
+ end_offset == start_offset
+ ? 1
+ : (current_offset - start_offset) / (end_offset - start_offset);
return base::TimeTicks() +
- base::Milliseconds(ComputeProgress<std::vector<double>>(
- current_offset, scroll_offsets_) *
- kScrollTimelineDurationMs);
+ base::Milliseconds(progress * kScrollTimelineDurationMs);
}
void ScrollTimeline::PushPropertiesTo(AnimationTimeline* impl_timeline) {
@@ -149,16 +131,12 @@ void ScrollTimeline::PushPropertiesTo(AnimationTimeline* impl_timeline) {
DCHECK(impl_timeline);
ScrollTimeline* scroll_timeline = ToScrollTimeline(impl_timeline);
scroll_timeline->pending_id_ = pending_id_;
- // TODO(smcgruer): This leads to incorrect behavior in the current design,
- // because we end up using the pending start/end scroll offset for the active
- // tree too. Instead we need to either split these (like pending_id_ and
- // active_id_) or have a ScrollTimeline per tree.
- scroll_timeline->scroll_offsets_ = scroll_offsets_;
- DCHECK(ValidateScrollOffsets(scroll_timeline->scroll_offsets_));
+ scroll_timeline->pending_offsets_ = pending_offsets_;
}
void ScrollTimeline::ActivateTimeline() {
active_id_ = pending_id_;
+ active_offsets_ = pending_offsets_;
for (auto& kv : id_to_animation_map_) {
auto& animation = kv.second;
if (animation->IsWorkletAnimation())
@@ -200,17 +178,15 @@ bool ScrollTimeline::TickScrollLinkedAnimations(
void ScrollTimeline::UpdateScrollerIdAndScrollOffsets(
absl::optional<ElementId> pending_id,
- const std::vector<double> scroll_offsets) {
- if (pending_id_ == pending_id && scroll_offsets_ == scroll_offsets) {
+ absl::optional<ScrollOffsets> pending_offsets) {
+ if (pending_id_ == pending_id && pending_offsets_ == pending_offsets)
return;
- }
// When the scroller id changes it will first be modified in the pending tree.
// Then later (when the pending tree is promoted to active)
// |ActivateTimeline| will be called and will set the |active_id_|.
pending_id_ = pending_id;
- scroll_offsets_ = scroll_offsets;
- DCHECK(ValidateScrollOffsets(scroll_offsets_));
+ pending_offsets_ = pending_offsets;
SetNeedsPushProperties();
}
diff --git a/chromium/cc/animation/scroll_timeline.h b/chromium/cc/animation/scroll_timeline.h
index a6548550235..482a874dc01 100644
--- a/chromium/cc/animation/scroll_timeline.h
+++ b/chromium/cc/animation/scroll_timeline.h
@@ -35,19 +35,31 @@ class CC_ANIMATION_EXPORT ScrollTimeline : public AnimationTimeline {
ScrollRight,
};
+ struct ScrollOffsets {
+ ScrollOffsets(double start_offset, double end_offset) {
+ start = start_offset;
+ end = end_offset;
+ }
+ bool operator==(const ScrollOffsets& other) const {
+ return start == other.start && end == other.end;
+ }
+ double start = 0;
+ double end = 0;
+ };
+
// 100% is represented as 100s or 100000ms. We store it here in Milliseconds
// because that is the time unit returned by functions like CurrentTime.
static constexpr double kScrollTimelineDurationMs = 100000;
ScrollTimeline(absl::optional<ElementId> scroller_id,
ScrollDirection direction,
- const std::vector<double> scroll_offsets,
+ absl::optional<ScrollOffsets> scroll_offsets,
int animation_timeline_id);
static scoped_refptr<ScrollTimeline> Create(
absl::optional<ElementId> scroller_id,
ScrollDirection direction,
- const std::vector<double> scroll_offsets);
+ absl::optional<ScrollOffsets> scroll_offsets);
// Create a copy of this ScrollTimeline intended for the impl thread in the
// compositor.
@@ -68,7 +80,7 @@ class CC_ANIMATION_EXPORT ScrollTimeline : public AnimationTimeline {
void UpdateScrollerIdAndScrollOffsets(
absl::optional<ElementId> scroller_id,
- const std::vector<double> scroll_offsets);
+ absl::optional<ScrollOffsets> scroll_offsets);
void PushPropertiesTo(AnimationTimeline* impl_timeline) override;
void ActivateTimeline() override;
@@ -82,14 +94,14 @@ class CC_ANIMATION_EXPORT ScrollTimeline : public AnimationTimeline {
absl::optional<ElementId> GetPendingIdForTest() const { return pending_id_; }
ScrollDirection GetDirectionForTest() const { return direction_; }
absl::optional<double> GetStartScrollOffsetForTest() const {
- if (scroll_offsets_.empty())
+ if (!pending_offsets_)
return absl::nullopt;
- return scroll_offsets_[0];
+ return pending_offsets_->start;
}
absl::optional<double> GetEndScrollOffsetForTest() const {
- if (scroll_offsets_.empty())
+ if (!pending_offsets_)
return absl::nullopt;
- return scroll_offsets_[1];
+ return pending_offsets_->end;
}
bool IsScrollTimeline() const override;
@@ -108,9 +120,8 @@ class CC_ANIMATION_EXPORT ScrollTimeline : public AnimationTimeline {
// it should base its current time on, and where the origin point is.
ScrollDirection direction_;
- // This defines scroll ranges of the scroller that the ScrollTimeline is
- // active within. If no ranges are defined the timeline is inactive.
- std::vector<double> scroll_offsets_;
+ absl::optional<ScrollOffsets> pending_offsets_;
+ absl::optional<ScrollOffsets> active_offsets_;
};
inline ScrollTimeline* ToScrollTimeline(AnimationTimeline* timeline) {
@@ -124,53 +135,6 @@ inline const ScrollTimeline* ToScrollTimeline(
return static_cast<const ScrollTimeline*>(timeline);
}
-// https://drafts.csswg.org/scroll-animations-1/#progress-calculation-algorithm
-template <typename T>
-double ComputeProgress(double current_offset, const T& resolved_offsets) {
- // 1. Let scroll offsets be the result of applying the procedure to resolve
- // scroll timeline offsets for scrollOffsets.
- DCHECK_GE(resolved_offsets.size(), 2u);
- // When start offset is greater than end offset, current time is calculated
- // outside of this method.
- DCHECK_LT(resolved_offsets[0], resolved_offsets[resolved_offsets.size() - 1]);
- // When animation is in before or after phase, current time is calculated
- // outside of this method.
- DCHECK_GE(current_offset, resolved_offsets[0]);
- DCHECK_LT(current_offset, resolved_offsets[resolved_offsets.size() - 1]);
- // Traverse scroll offsets from the back to find first interval that
- // contains the current offset. In case of overlapping offsets, last matching
- // interval in the list is used to calculate the current time. The rational
- // for choosing last matching offset is to be consistent with CSS property
- // overrides.
-
- // 2. Let offset index correspond to the position of the last offset in scroll
- // offsets whose value is less than or equal to offset and the value at the
- // following position greater than offset
- int offset_index;
- for (offset_index = resolved_offsets.size() - 2;
- offset_index > 0 && resolved_offsets[offset_index] > current_offset;
- offset_index--) {
- DCHECK_LT(current_offset, resolved_offsets[offset_index + 1]);
- }
- // 3. Let start offset be the offset value at position offset index in
- // scroll offsets.
- double start_offset = resolved_offsets[offset_index];
- // 4. Let end offset be the value of next offset in scroll offsets after
- // start offset.
- double end_offset = resolved_offsets[offset_index + 1];
- // 5. Let size be the number of offsets in scroll offsets.
- unsigned int size = resolved_offsets.size();
- // 6. Let offset weight be the result of evaluating 1 / (size - 1).
- double offset_weight = 1.0 / (size - 1);
- // 7. Let interval progress be the result of evaluating
- // (offset - start offset) / (end offset - start offset).
- double interval_progress =
- (current_offset - start_offset) / (end_offset - start_offset);
- // 8. Return the result of evaluating
- // (offset index + interval progress) × offset weight.
- return (offset_index + interval_progress) * offset_weight;
-}
-
} // namespace cc
#endif // CC_ANIMATION_SCROLL_TIMELINE_H_
diff --git a/chromium/cc/animation/scroll_timeline_unittest.cc b/chromium/cc/animation/scroll_timeline_unittest.cc
index 6d66c54cf6b..5318a05efe6 100644
--- a/chromium/cc/animation/scroll_timeline_unittest.cc
+++ b/chromium/cc/animation/scroll_timeline_unittest.cc
@@ -24,6 +24,12 @@ static constexpr double time_error_ms = 0.001;
#define EXPECT_SCROLL_TIMELINE_TIME_NEAR(expected, value) \
EXPECT_NEAR(expected, ToDouble(value), time_error_ms)
+#define EXPECT_SCROLL_TIMELINE_BEFORE_START(value) \
+ EXPECT_LT(ToDouble(value), 0);
+
+#define EXPECT_SCROLL_TIMELINE_AFTER_END(value) \
+ EXPECT_GT(ToDouble(value), ScrollTimeline::kScrollTimelineDurationMs);
+
void SetScrollOffset(PropertyTrees* property_trees,
ElementId scroller_id,
gfx::PointF offset) {
@@ -123,9 +129,7 @@ class ScrollTimelineTest : public ::testing::Test,
};
TEST_F(ScrollTimelineTest, BasicCurrentTimeCalculations) {
- std::vector<double> scroll_offsets;
- scroll_offsets.push_back(0);
- scroll_offsets.push_back(100);
+ ScrollTimeline::ScrollOffsets scroll_offsets(0, 100);
scoped_refptr<ScrollTimeline> vertical_timeline = ScrollTimeline::Create(
scroller_id(), ScrollTimeline::ScrollDown, scroll_offsets);
@@ -150,118 +154,6 @@ TEST_F(ScrollTimelineTest, BasicCurrentTimeCalculations) {
horizontal_timeline->CurrentTime(scroll_tree(), false));
}
-TEST_F(ScrollTimelineTest, MultipleScrollOffsetsCurrentTimeCalculations) {
- double scroll_size =
- content_size().height() - container_size().height(); // 400
-
- std::vector<double> scroll_offsets;
- scroll_offsets.push_back(0);
- scroll_offsets.push_back(100.0);
- scroll_offsets.push_back(250.0);
- scroll_offsets.push_back(scroll_size);
-
- scoped_refptr<ScrollTimeline> vertical_timeline = ScrollTimeline::Create(
- scroller_id(), ScrollTimeline::ScrollDown, scroll_offsets);
-
- unsigned int offset = 0;
- double w = 1.0 / 3.0; // offset weight
- double p = 0; // progress within the offset
-
- // Scale necessary to convert absolute unit times to progress based values
- double scale = ScrollTimeline::kScrollTimelineDurationMs / scroll_size;
-
- SetScrollOffset(&property_trees(), scroller_id(), gfx::PointF());
- EXPECT_SCROLL_TIMELINE_TIME_NEAR(
- (offset + p) * w * scroll_size * scale,
- vertical_timeline->CurrentTime(scroll_tree(), false));
-
- p = (70.0 - 0.0) / (100.0 - 0.0);
- SetScrollOffset(&property_trees(), scroller_id(), gfx::PointF(0, 70));
- EXPECT_SCROLL_TIMELINE_TIME_NEAR(
- (offset + p) * w * scroll_size * scale,
- vertical_timeline->CurrentTime(scroll_tree(), false));
-
- offset = 1;
- p = 0;
- SetScrollOffset(&property_trees(), scroller_id(), gfx::PointF(0, 100));
- EXPECT_SCROLL_TIMELINE_TIME_NEAR(
- (offset + p) * w * scroll_size * scale,
- vertical_timeline->CurrentTime(scroll_tree(), false));
-
- p = (150.0 - 100.0) / (250.0 - 100.0);
- SetScrollOffset(&property_trees(), scroller_id(), gfx::PointF(0, 150));
- EXPECT_SCROLL_TIMELINE_TIME_NEAR(
- (offset + p) * w * scroll_size * scale,
- vertical_timeline->CurrentTime(scroll_tree(), false));
-
- offset = 2;
- p = 0;
- SetScrollOffset(&property_trees(), scroller_id(), gfx::PointF(0, 250));
- EXPECT_SCROLL_TIMELINE_TIME_NEAR(
- (offset + p) * w * scroll_size * scale,
- vertical_timeline->CurrentTime(scroll_tree(), false));
-
- p = (350.0 - 250.0) / (400.0 - 250.0);
- SetScrollOffset(&property_trees(), scroller_id(), gfx::PointF(0, 350));
- EXPECT_SCROLL_TIMELINE_TIME_NEAR(
- (offset + p) * w * scroll_size * scale,
- vertical_timeline->CurrentTime(scroll_tree(), false));
-
- SetScrollOffset(&property_trees(), scroller_id(), gfx::PointF(0, 400));
- EXPECT_SCROLL_TIMELINE_TIME_NEAR(
- ScrollTimeline::kScrollTimelineDurationMs,
- vertical_timeline->CurrentTime(scroll_tree(), false));
-}
-
-TEST_F(ScrollTimelineTest, OverlappingScrollOffsets) {
- double scroll_size = 100.0;
-
- // Start offset is greater than end offset ==> animation progress is
- // either 0% or 100%.
- std::vector<double> scroll_offsets = {350.0, 200.0, 50.0};
-
- scoped_refptr<ScrollTimeline> vertical_timeline = ScrollTimeline::Create(
- scroller_id(), ScrollTimeline::ScrollDown, scroll_offsets);
-
- // Offset is less than start offset ==> current time is 0.
- SetScrollOffset(&property_trees(), scroller_id(), gfx::PointF(0, 300));
- EXPECT_SCROLL_TIMELINE_TIME_NEAR(
- 0, vertical_timeline->CurrentTime(scroll_tree(), false));
-
- // Scale necessary to convert absolute unit times to progress based values
- double scale = ScrollTimeline::kScrollTimelineDurationMs / scroll_size;
-
- // Offset is greater than end offset ==> current time is 100%.
- SetScrollOffset(&property_trees(), scroller_id(), gfx::PointF(0, 360));
- EXPECT_SCROLL_TIMELINE_TIME_NEAR(
- scroll_size * scale,
- vertical_timeline->CurrentTime(scroll_tree(), false));
-
- scroll_offsets = {0.0, 400.0, 200.0};
-
- vertical_timeline = ScrollTimeline::Create(
- scroller_id(), ScrollTimeline::ScrollDown, scroll_offsets);
-
- SetScrollOffset(&property_trees(), scroller_id(), gfx::PointF(0, 100));
- // Scroll offset is 25% of [0, 400) range, which maps to [0% 50%) of the
- // entire scroll range.
- EXPECT_SCROLL_TIMELINE_TIME_NEAR(
- scroll_size * 0.5 * 0.25 * scale,
- vertical_timeline->CurrentTime(scroll_tree(), false));
-
- scroll_offsets = {200.0, 0.0, 400.0};
-
- vertical_timeline = ScrollTimeline::Create(
- scroller_id(), ScrollTimeline::ScrollDown, scroll_offsets);
-
- SetScrollOffset(&property_trees(), scroller_id(), gfx::PointF(0, 300));
- // Scroll offset is 75% of [0, 400) range, which maps to [50% 100%) of the
- // entire scroll range.
- EXPECT_SCROLL_TIMELINE_TIME_NEAR(
- scroll_size * (0.5 + 0.5 * 0.75) * scale,
- vertical_timeline->CurrentTime(scroll_tree(), false));
-}
-
// This test ensures that the ScrollTimeline's active scroller id is correct. We
// had a few crashes caused by assuming that the id would be available in the
// active tree before the activation happened; see http://crbug.com/853231
@@ -283,9 +175,7 @@ TEST_F(ScrollTimelineTest, ActiveTimeIsSetOnlyAfterPromotion) {
container_size());
double scroll_size = content_size().height() - container_size().height();
- std::vector<double> scroll_offsets;
- scroll_offsets.push_back(0);
- scroll_offsets.push_back(scroll_size);
+ ScrollTimeline::ScrollOffsets scroll_offsets(0, scroll_size);
double halfwayY = scroll_size / 2.;
double expectedTime = 0.5 * ScrollTimeline::kScrollTimelineDurationMs;
@@ -321,9 +211,7 @@ TEST_F(ScrollTimelineTest, ActiveTimeIsSetOnlyAfterPromotion) {
TEST_F(ScrollTimelineTest, CurrentTimeIsAdjustedForPixelSnapping) {
double scroll_size = content_size().height() - container_size().height();
- std::vector<double> scroll_offsets;
- scroll_offsets.push_back(0);
- scroll_offsets.push_back(scroll_size);
+ ScrollTimeline::ScrollOffsets scroll_offsets(0, scroll_size);
scoped_refptr<ScrollTimeline> timeline = ScrollTimeline::Create(
scroller_id(), ScrollTimeline::ScrollDown, scroll_offsets);
@@ -346,21 +234,20 @@ TEST_F(ScrollTimelineTest, CurrentTimeIsAdjustedForPixelSnapping) {
TEST_F(ScrollTimelineTest, CurrentTimeHandlesStartScrollOffset) {
double scroll_size = content_size().height() - container_size().height();
const double start_scroll_offset = 20;
- std::vector<double> scroll_offsets;
- scroll_offsets.push_back(start_scroll_offset);
- scroll_offsets.push_back(scroll_size);
+ ScrollTimeline::ScrollOffsets scroll_offsets(start_scroll_offset,
+ scroll_size);
scoped_refptr<ScrollTimeline> timeline = ScrollTimeline::Create(
scroller_id(), ScrollTimeline::ScrollDown, scroll_offsets);
- // Unscrolled, the timeline should read a current time of 0 since the current
- // offset (0) will be less than the startScrollOffset.
+ // Unscrolled, the timeline should read a current time of < 0 since the
+ // current offset (0) will be less than the startScrollOffset.
SetScrollOffset(&property_trees(), scroller_id(), gfx::PointF());
- EXPECT_SCROLL_TIMELINE_TIME_NEAR(0,
- timeline->CurrentTime(scroll_tree(), false));
+ EXPECT_SCROLL_TIMELINE_BEFORE_START(
+ timeline->CurrentTime(scroll_tree(), false));
SetScrollOffset(&property_trees(), scroller_id(), gfx::PointF(0, 19));
- EXPECT_SCROLL_TIMELINE_TIME_NEAR(0,
- timeline->CurrentTime(scroll_tree(), false));
+ EXPECT_SCROLL_TIMELINE_BEFORE_START(
+ timeline->CurrentTime(scroll_tree(), false).value());
SetScrollOffset(&property_trees(), scroller_id(), gfx::PointF(0, 20));
EXPECT_SCROLL_TIMELINE_TIME_NEAR(0,
@@ -380,16 +267,13 @@ TEST_F(ScrollTimelineTest, CurrentTimeHandlesStartScrollOffset) {
TEST_F(ScrollTimelineTest, CurrentTimeHandlesEndScrollOffset) {
double scroll_size = content_size().height() - container_size().height();
const double end_scroll_offset = scroll_size - 20;
- std::vector<double> scroll_offsets;
- scroll_offsets.push_back(0); // should be absl::nullopt
- scroll_offsets.push_back(end_scroll_offset);
+ ScrollTimeline::ScrollOffsets scroll_offsets(0, end_scroll_offset);
scoped_refptr<ScrollTimeline> timeline = ScrollTimeline::Create(
scroller_id(), ScrollTimeline::ScrollDown, scroll_offsets);
SetScrollOffset(&property_trees(), scroller_id(),
gfx::PointF(0, scroll_size));
- EXPECT_SCROLL_TIMELINE_TIME_NEAR(ScrollTimeline::kScrollTimelineDurationMs,
- timeline->CurrentTime(scroll_tree(), false));
+ EXPECT_SCROLL_TIMELINE_AFTER_END(timeline->CurrentTime(scroll_tree(), false));
SetScrollOffset(&property_trees(), scroller_id(),
gfx::PointF(0, scroll_size - 20));
@@ -413,9 +297,8 @@ TEST_F(ScrollTimelineTest, CurrentTimeHandlesCombinedStartAndEndScrollOffset) {
double scroll_size = content_size().height() - container_size().height();
double start_scroll_offset = 20;
double end_scroll_offset = scroll_size - 50;
- std::vector<double> scroll_offsets;
- scroll_offsets.push_back(start_scroll_offset);
- scroll_offsets.push_back(end_scroll_offset);
+ ScrollTimeline::ScrollOffsets scroll_offsets(start_scroll_offset,
+ end_scroll_offset);
scoped_refptr<ScrollTimeline> timeline = ScrollTimeline::Create(
scroller_id(), ScrollTimeline::ScrollDown, scroll_offsets);
SetScrollOffset(&property_trees(), scroller_id(),
@@ -427,11 +310,15 @@ TEST_F(ScrollTimelineTest, CurrentTimeHandlesCombinedStartAndEndScrollOffset) {
}
TEST_F(ScrollTimelineTest, CurrentTimeHandlesEqualStartAndEndScrollOffset) {
- std::vector<double> scroll_offsets;
- scroll_offsets.push_back(20);
- scroll_offsets.push_back(20);
+ ScrollTimeline::ScrollOffsets scroll_offsets(20, 20);
scoped_refptr<ScrollTimeline> timeline = ScrollTimeline::Create(
scroller_id(), ScrollTimeline::ScrollDown, scroll_offsets);
+
+ SetScrollOffset(&property_trees(), scroller_id(), gfx::PointF(0, 20));
+
+ EXPECT_SCROLL_TIMELINE_TIME_NEAR(ScrollTimeline::kScrollTimelineDurationMs,
+ timeline->CurrentTime(scroll_tree(), false));
+
SetScrollOffset(&property_trees(), scroller_id(), gfx::PointF(0, 150));
EXPECT_SCROLL_TIMELINE_TIME_NEAR(ScrollTimeline::kScrollTimelineDurationMs,
@@ -440,19 +327,22 @@ TEST_F(ScrollTimelineTest, CurrentTimeHandlesEqualStartAndEndScrollOffset) {
TEST_F(ScrollTimelineTest,
CurrentTimeHandlesStartOffsetLargerThanEndScrollOffset) {
- std::vector<double> scroll_offsets;
- scroll_offsets.push_back(50);
- scroll_offsets.push_back(10);
+ ScrollTimeline::ScrollOffsets scroll_offsets(50, 10);
scoped_refptr<ScrollTimeline> timeline = ScrollTimeline::Create(
scroller_id(), ScrollTimeline::ScrollDown, scroll_offsets);
- SetScrollOffset(&property_trees(), scroller_id(), gfx::PointF(0, 40));
- EXPECT_SCROLL_TIMELINE_TIME_NEAR(0,
- timeline->CurrentTime(scroll_tree(), false));
- SetScrollOffset(&property_trees(), scroller_id(), gfx::PointF(0, 150));
+ // Timeline direction reversed.
+ SetScrollOffset(&property_trees(), scroller_id(), gfx::PointF(0, 0));
+ EXPECT_SCROLL_TIMELINE_AFTER_END(timeline->CurrentTime(scroll_tree(), false));
- EXPECT_SCROLL_TIMELINE_TIME_NEAR(ScrollTimeline::kScrollTimelineDurationMs,
- timeline->CurrentTime(scroll_tree(), false));
+ SetScrollOffset(&property_trees(), scroller_id(), gfx::PointF(0, 30));
+ EXPECT_SCROLL_TIMELINE_TIME_NEAR(
+ ScrollTimeline::kScrollTimelineDurationMs / 2,
+ timeline->CurrentTime(scroll_tree(), false));
+
+ SetScrollOffset(&property_trees(), scroller_id(), gfx::PointF(0, 150));
+ EXPECT_SCROLL_TIMELINE_BEFORE_START(
+ timeline->CurrentTime(scroll_tree(), false));
}
TEST_F(ScrollTimelineTest, CurrentTimeHandlesScrollOffsets) {
@@ -460,18 +350,17 @@ TEST_F(ScrollTimelineTest, CurrentTimeHandlesScrollOffsets) {
const double scroller_height =
content_size().height() - container_size().height();
const double end_scroll_offset = scroller_height - 20;
- std::vector<double> scroll_offsets;
- scroll_offsets.push_back(start_scroll_offset);
- scroll_offsets.push_back(end_scroll_offset);
+ ScrollTimeline::ScrollOffsets scroll_offsets(start_scroll_offset,
+ end_scroll_offset);
scoped_refptr<ScrollTimeline> timeline = ScrollTimeline::Create(
scroller_id(), ScrollTimeline::ScrollDown, scroll_offsets);
- // Before the start_scroll_offset the current time should be 0
+ // Before the start_scroll_offset the current time should be < 0
SetScrollOffset(&property_trees(), scroller_id(),
gfx::PointF(0, start_scroll_offset - 10));
- EXPECT_SCROLL_TIMELINE_TIME_NEAR(0,
- timeline->CurrentTime(scroll_tree(), false));
+ EXPECT_SCROLL_TIMELINE_BEFORE_START(
+ timeline->CurrentTime(scroll_tree(), false));
// At the end_scroll_offset the current time should be 100%
SetScrollOffset(&property_trees(), scroller_id(),
@@ -479,19 +368,16 @@ TEST_F(ScrollTimelineTest, CurrentTimeHandlesScrollOffsets) {
EXPECT_SCROLL_TIMELINE_TIME_NEAR(ScrollTimeline::kScrollTimelineDurationMs,
timeline->CurrentTime(scroll_tree(), false));
- // After the end_scroll_offset the current time should be 100%
+ // After the end_scroll_offset the current time should be > 100%
SetScrollOffset(&property_trees(), scroller_id(),
gfx::PointF(0, end_scroll_offset + 10));
- EXPECT_SCROLL_TIMELINE_TIME_NEAR(ScrollTimeline::kScrollTimelineDurationMs,
- timeline->CurrentTime(scroll_tree(), false));
+ EXPECT_SCROLL_TIMELINE_AFTER_END(timeline->CurrentTime(scroll_tree(), false));
}
TEST_F(ScrollTimelineTest, Activeness) {
// ScrollTimeline with zero scroller id is inactive.
- std::vector<double> scroll_offsets;
double scroll_size = content_size().height() - container_size().height();
- scroll_offsets.push_back(0);
- scroll_offsets.push_back(scroll_size);
+ ScrollTimeline::ScrollOffsets scroll_offsets(0, scroll_size);
scoped_refptr<ScrollTimeline> inactive_timeline1 = ScrollTimeline::Create(
absl::nullopt, ScrollTimeline::ScrollDown, scroll_offsets);
EXPECT_FALSE(
@@ -511,9 +397,9 @@ TEST_F(ScrollTimelineTest, Activeness) {
inactive_timeline2->IsActive(scroll_tree(), true /*is_active_tree*/));
// ScrollTimeline with empty scroll offsets is inactive.
- std::vector<double> empty_scroll_offsets;
- scoped_refptr<ScrollTimeline> inactive_timeline3 = ScrollTimeline::Create(
- scroller_id(), ScrollTimeline::ScrollDown, empty_scroll_offsets);
+ scoped_refptr<ScrollTimeline> inactive_timeline3 =
+ ScrollTimeline::Create(scroller_id(), ScrollTimeline::ScrollDown,
+ /* scroll_offsets */ absl::nullopt);
EXPECT_FALSE(
inactive_timeline3->IsActive(scroll_tree(), false /*is_active_tree*/));
EXPECT_FALSE(
diff --git a/chromium/cc/animation/worklet_animation_unittest.cc b/chromium/cc/animation/worklet_animation_unittest.cc
index 7cfe9e80e03..823ae300c0c 100644
--- a/chromium/cc/animation/worklet_animation_unittest.cc
+++ b/chromium/cc/animation/worklet_animation_unittest.cc
@@ -60,7 +60,7 @@ class MockScrollTimeline : public ScrollTimeline {
MockScrollTimeline()
: ScrollTimeline(ElementId(),
ScrollTimeline::ScrollDown,
- std::vector<double>(),
+ /* scroll_offsets */ absl::nullopt,
AnimationIdProvider::NextTimelineId()) {}
MOCK_CONST_METHOD2(CurrentTime,
absl::optional<base::TimeTicks>(const ScrollTree&, bool));
diff --git a/chromium/cc/base/BUILD.gn b/chromium/cc/base/BUILD.gn
index 2d9ea4073b6..29d6aaa9b06 100644
--- a/chromium/cc/base/BUILD.gn
+++ b/chromium/cc/base/BUILD.gn
@@ -56,6 +56,7 @@ cc_component("base") {
"//base",
"//base/third_party/dynamic_annotations",
"//skia",
+ "//ui/base:features",
"//ui/gfx/animation",
"//ui/gfx/geometry",
"//ui/gfx/geometry:geometry_skia",
diff --git a/chromium/cc/base/features.cc b/chromium/cc/base/features.cc
index 0caa7b11875..0f5953f6783 100644
--- a/chromium/cc/base/features.cc
+++ b/chromium/cc/base/features.cc
@@ -6,6 +6,7 @@
#include "base/feature_list.h"
#include "build/build_config.h"
+#include "ui/base/ui_base_features.h"
namespace features {
@@ -20,17 +21,8 @@ namespace features {
const base::Feature kAnimatedImageResume = {"AnimatedImageResume",
base::FEATURE_DISABLED_BY_DEFAULT};
-// Enables impulse-style scroll animations in place of the default ones.
-//
-// Note: Do not enable this on the Mac. The animation does not match the system
-// scroll animation curve to such an extent that it makes Chromium stand out in
-// a bad way.
-const base::Feature kImpulseScrollAnimations = {
- "ImpulseScrollAnimations",
- base::FEATURE_DISABLED_BY_DEFAULT};
-
bool IsImpulseScrollAnimationEnabled() {
- return base::FeatureList::IsEnabled(features::kImpulseScrollAnimations);
+ return base::FeatureList::IsEnabled(features::kWindowsScrollingPersonality);
}
// Whether the compositor should attempt to sync with the scroll handlers before
@@ -71,4 +63,7 @@ const base::Feature kNonBlockingCommit{"NonBlockingCommit",
const base::Feature kSlidingWindowForDroppedFrameCounter{
"SlidingWindowForDroppedFrameCounter", base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kNormalPriorityImageDecoding{
+ "NormalPriorityImageDecoding", base::FEATURE_DISABLED_BY_DEFAULT};
} // namespace features
diff --git a/chromium/cc/base/features.h b/chromium/cc/base/features.h
index aab0e400bab..5dd95a616c0 100644
--- a/chromium/cc/base/features.h
+++ b/chromium/cc/base/features.h
@@ -12,7 +12,6 @@
namespace features {
CC_BASE_EXPORT extern const base::Feature kAnimatedImageResume;
-CC_BASE_EXPORT extern const base::Feature kImpulseScrollAnimations;
CC_BASE_EXPORT extern bool IsImpulseScrollAnimationEnabled();
CC_BASE_EXPORT extern const base::Feature kSynchronizedScrolling;
@@ -64,6 +63,11 @@ CC_BASE_EXPORT extern const base::Feature kNonBlockingCommit;
// When enabled, DroppedFrameCounter will use an adjusted sliding window
// interval specified by field trial params.
CC_BASE_EXPORT extern const base::Feature kSlidingWindowForDroppedFrameCounter;
+
+// When enabled, SupportsBackgroundThreadPriority is set to kNo for
+// GpuImageDecodeTaskImpl and SoftwareImageDecodeTaskImpl.
+// Introduced to fix https://crbug.com/1116624
+CC_BASE_EXPORT extern const base::Feature kNormalPriorityImageDecoding;
} // namespace features
#endif // CC_BASE_FEATURES_H_
diff --git a/chromium/cc/base/math_util.cc b/chromium/cc/base/math_util.cc
index 7c700f83238..e7f0e37e2b2 100644
--- a/chromium/cc/base/math_util.cc
+++ b/chromium/cc/base/math_util.cc
@@ -1017,7 +1017,7 @@ void MathUtil::AddToTracedValue(const char* name,
res->AppendInteger(gradient.angle());
res->AppendInteger(gradient.step_count());
for (size_t i = 0; i < gradient.step_count(); i++) {
- res->AppendDouble(gradient.steps()[i].percent);
+ res->AppendDouble(gradient.steps()[i].fraction);
res->AppendInteger(gradient.steps()[i].alpha);
}
res->EndArray();
diff --git a/chromium/cc/base/rtree.h b/chromium/cc/base/rtree.h
index d59c08a7f22..e1492ce9368 100644
--- a/chromium/cc/base/rtree.h
+++ b/chromium/cc/base/rtree.h
@@ -152,8 +152,8 @@ class RTree {
// This is the count of data elements (rather than total nodes in the tree)
size_t num_data_elements_ = 0u;
- Branch<T> root_;
std::vector<Node<T>> nodes_;
+ Branch<T> root_;
// If false, the rtree encountered overflow does not have reliable bounds.
bool has_valid_bounds_ = true;
@@ -432,6 +432,7 @@ void RTree<T>::GetAllBoundsRecursive(Node<T>* node,
template <typename T>
void RTree<T>::Reset() {
num_data_elements_ = 0;
+ root_.subtree = nullptr;
nodes_.clear();
root_.bounds = gfx::Rect();
has_valid_bounds_ = true;
diff --git a/chromium/cc/base/synced_property.h b/chromium/cc/base/synced_property.h
index f5173bcdb68..8d29bc797a7 100644
--- a/chromium/cc/base/synced_property.h
+++ b/chromium/cc/base/synced_property.h
@@ -5,7 +5,10 @@
#ifndef CC_BASE_SYNCED_PROPERTY_H_
#define CC_BASE_SYNCED_PROPERTY_H_
+#include <utility>
+
#include "base/memory/ref_counted.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
namespace cc {
@@ -39,8 +42,7 @@ class SyncedProperty : public base::RefCounted<SyncedProperty<T>> {
// Sets the value on the impl thread, due to an impl-thread-originating
// action. Returns true if this had any effect. This will remain
// impl-thread-only information at first, and will get pulled back to the main
- // thread on the next call of PullDeltaToMainThread (which happens right
- // before the commit).
+ // thread on the next call of PullDeltaForMainThread.
bool SetCurrent(BaseT current) {
DeltaT delta = T::DeltaBetweenBases(current, active_base_);
if (active_delta_ == delta)
@@ -57,16 +59,27 @@ class SyncedProperty : public base::RefCounted<SyncedProperty<T>> {
// Returns the latest active tree delta and also makes a note that this value
// was sent to the main thread.
DeltaT PullDeltaForMainThread() {
- reflected_delta_in_main_tree_ = PendingDelta();
- return reflected_delta_in_main_tree_;
+ DCHECK(!next_reflected_delta_in_main_tree_.has_value());
+ DeltaT result = UnsentDelta();
+ if (reflected_delta_in_main_tree_.has_value()) {
+ next_reflected_delta_in_main_tree_.emplace(result);
+ } else {
+ reflected_delta_in_main_tree_.emplace(result);
+ }
+ return result;
}
// Push the latest value from the main thread onto pending tree-associated
// state. Returns true if pushing the value results in different values
// between the main layer tree and the pending tree.
bool PushMainToPending(BaseT main_thread_value) {
- reflected_delta_in_pending_tree_ = reflected_delta_in_main_tree_;
- reflected_delta_in_main_tree_ = T::IdentityDelta();
+ DCHECK(reflected_delta_in_main_tree_.has_value() ||
+ !next_reflected_delta_in_main_tree_.has_value());
+ reflected_delta_in_pending_tree_ =
+ reflected_delta_in_main_tree_.value_or(T::IdentityDelta());
+ reflected_delta_in_main_tree_ =
+ std::move(next_reflected_delta_in_main_tree_);
+ next_reflected_delta_in_main_tree_.reset();
pending_base_ = main_thread_value;
return Current(false) != main_thread_value;
@@ -97,16 +110,52 @@ class SyncedProperty : public base::RefCounted<SyncedProperty<T>> {
active_value_before_push != current_active_value;
}
- // This simulates the consequences of the sent value getting committed and
- // activated.
- void AbortCommit() {
- pending_base_ = T::ApplyDelta(pending_base_, reflected_delta_in_main_tree_);
- active_base_ = T::ApplyDelta(active_base_, reflected_delta_in_main_tree_);
- active_delta_ =
- T::DeltaBetweenDeltas(active_delta_, reflected_delta_in_main_tree_);
- reflected_delta_in_main_tree_ = T::IdentityDelta();
+ void AbortCommit(bool main_frame_applied_deltas) {
+ // Finish processing the delta that was sent to the main thread, and reset
+ // the corresponding the delta_in_main_tree_ variable. If
+ // main_frame_applied_deltas is true, we send the delta on to the active
+ // tree just as would happen for a successful commit. Otherwise, we treat
+ // the delta as never having been sent to the main thread and just drop it.
+ if (next_reflected_delta_in_main_tree_.has_value()) {
+ // If next_reflected_delta_in_main_tree_ is populated, we know two things:
+ // - This abort corresponds to next_reflected_delta_in_main_tree_,
+ // because we only send a "next" BeginMainFrame if the previous one
+ // has already signaled "ready to commit".
+ // - The previous main frame has not yet run commit. If it had, then
+ // PushMainToPending would have promoted
+ // next_reflected_delta_in_main_tree_ to reflected_delta_in_main_tree_
+ // and next_reflected_delta_in_main_tree_ would be empty.
+ // In this case, if the main thread processed the delta from this aborted
+ // commit we can simply add the delta to reflected_delta_in_main_tree_.
+ if (main_frame_applied_deltas) {
+ reflected_delta_in_main_tree_ =
+ T::CombineDeltas(reflected_delta_in_main_tree_.value(),
+ next_reflected_delta_in_main_tree_.value());
+ }
+ next_reflected_delta_in_main_tree_.reset();
+ } else {
+ // There is no "next" main frame, this abort was for the primary.
+ if (main_frame_applied_deltas) {
+ DeltaT delta =
+ reflected_delta_in_main_tree_.value_or(T::IdentityDelta());
+ // This simulates the consequences of the sent value getting committed
+ // and activated.
+ pending_base_ = T::ApplyDelta(pending_base_, delta);
+ active_base_ = T::ApplyDelta(active_base_, delta);
+ active_delta_ = T::DeltaBetweenDeltas(active_delta_, delta);
+ }
+ reflected_delta_in_main_tree_.reset();
+ }
}
+ // Values sent to the main thread and not yet resolved in the pending or
+ // active tree.
+ const absl::optional<DeltaT>& reflected_delta_in_main_tree() const {
+ return reflected_delta_in_main_tree_;
+ }
+ const absl::optional<DeltaT>& next_reflected_delta_in_main_tree() const {
+ return next_reflected_delta_in_main_tree_;
+ }
// Values as last pushed to the pending or active tree respectively, with no
// impl-thread delta applied.
BaseT PendingBase() const { return pending_base_; }
@@ -122,6 +171,12 @@ class SyncedProperty : public base::RefCounted<SyncedProperty<T>> {
reflected_delta_in_pending_tree_);
}
+ DeltaT UnsentDelta() const {
+ return T::DeltaBetweenDeltas(
+ PendingDelta(),
+ reflected_delta_in_main_tree_.value_or(T::IdentityDelta()));
+ }
+
void set_clobber_active_value() { clobber_active_value_ = true; }
private:
@@ -134,9 +189,13 @@ class SyncedProperty : public base::RefCounted<SyncedProperty<T>> {
BaseT active_base_ = T::IdentityBase();
// The difference between |active_base_| and the user-perceived value.
DeltaT active_delta_ = T::IdentityDelta();
- // The value sent to the main thread on the last BeginMainFrame. This is
- // always identity outside of the BeginMainFrame to (aborted)commit interval.
- DeltaT reflected_delta_in_main_tree_ = T::IdentityDelta();
+ // A value sent to the main thread on a BeginMainFrame, but not yet applied to
+ // the resulting pending tree.
+ absl::optional<DeltaT> reflected_delta_in_main_tree_;
+ // A value sent to the main thread on a BeginMainFrame at a time when
+ // reflected_delta_in_main_tree_ is populated. This is used when a main frame
+ // is sent to the main thread before the previous one has committed.
+ absl::optional<DeltaT> next_reflected_delta_in_main_tree_;
// The value that was sent to the main thread for BeginMainFrame for the
// current pending tree. This is always identity outside of the
// BeginMainFrame to activation interval.
@@ -164,6 +223,7 @@ class AdditionGroup {
static BaseT ApplyDelta(BaseT v, DeltaT delta) { return v + delta; }
static DeltaT DeltaBetweenBases(BaseT v1, BaseT v2) { return v1 - v2; }
static DeltaT DeltaBetweenDeltas(DeltaT d1, DeltaT d2) { return d1 - d2; }
+ static DeltaT CombineDeltas(DeltaT d1, DeltaT d2) { return d1 + d2; }
};
class ScaleGroup {
@@ -175,6 +235,7 @@ class ScaleGroup {
static float ApplyDelta(float v, float delta) { return v * delta; }
static float DeltaBetweenBases(float v1, float v2) { return v1 / v2; }
static float DeltaBetweenDeltas(float d1, float d2) { return d1 / d2; }
+ static float CombineDeltas(float d1, float d2) { return d1 * d2; }
};
} // namespace cc
diff --git a/chromium/cc/input/compositor_input_interfaces.h b/chromium/cc/input/compositor_input_interfaces.h
index cdc8b4f10d4..fea6c64acbe 100644
--- a/chromium/cc/input/compositor_input_interfaces.h
+++ b/chromium/cc/input/compositor_input_interfaces.h
@@ -29,10 +29,9 @@ class ScrollTree;
enum class ScrollbarOrientation;
// This is the interface that LayerTreeHostImpl and the "graphics" side of the
-// compositor uses to talk to the compositor ThreadedInputHandler. This
-// interface is two-way; it's used used both to communicate state changes from
-// the LayerTree to the input handler and also to query and update state in the
-// input handler.
+// compositor uses to talk to the compositor InputHandler. This interface is
+// two-way; it's used used both to communicate state changes from the LayerTree
+// to the input handler and also to query and update state in the input handler.
class InputDelegateForCompositor {
public:
virtual ~InputDelegateForCompositor() = default;
diff --git a/chromium/cc/input/threaded_input_handler.cc b/chromium/cc/input/input_handler.cc
index be15f495eaa..e6313f3b006 100644
--- a/chromium/cc/input/threaded_input_handler.cc
+++ b/chromium/cc/input/input_handler.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "cc/input/threaded_input_handler.h"
+#include "cc/input/input_handler.h"
#include <utility>
#include <vector>
@@ -53,45 +53,42 @@ InputHandlerCommitData::~InputHandlerCommitData() = default;
// static
base::WeakPtr<InputHandler> InputHandler::Create(
CompositorDelegateForInput& compositor_delegate) {
- auto input_handler =
- std::make_unique<ThreadedInputHandler>(compositor_delegate);
+ auto input_handler = std::make_unique<InputHandler>(compositor_delegate);
base::WeakPtr<InputHandler> input_handler_weak = input_handler->AsWeakPtr();
compositor_delegate.BindToInputHandler(std::move(input_handler));
return input_handler_weak;
}
-ThreadedInputHandler::ThreadedInputHandler(
- CompositorDelegateForInput& compositor_delegate)
+InputHandler::InputHandler(CompositorDelegateForInput& compositor_delegate)
: compositor_delegate_(compositor_delegate),
scrollbar_controller_(std::make_unique<ScrollbarController>(
&compositor_delegate_.GetImplDeprecated())) {}
-ThreadedInputHandler::~ThreadedInputHandler() = default;
+InputHandler::~InputHandler() = default;
//
// =========== InputHandler Interface
//
-base::WeakPtr<InputHandler> ThreadedInputHandler::AsWeakPtr() const {
+base::WeakPtr<InputHandler> InputHandler::AsWeakPtr() const {
return weak_factory_.GetWeakPtr();
}
-void ThreadedInputHandler::BindToClient(InputHandlerClient* client) {
+void InputHandler::BindToClient(InputHandlerClient* client) {
DCHECK(input_handler_client_ == nullptr);
input_handler_client_ = client;
input_handler_client_->SetPrefersReducedMotion(prefers_reduced_motion_);
}
-InputHandler::ScrollStatus ThreadedInputHandler::ScrollBegin(
- ScrollState* scroll_state,
- ui::ScrollInputType type) {
+InputHandler::ScrollStatus InputHandler::ScrollBegin(ScrollState* scroll_state,
+ ui::ScrollInputType type) {
DCHECK(scroll_state);
DCHECK(scroll_state->delta_x() == 0 && scroll_state->delta_y() == 0);
InputHandler::ScrollStatus scroll_status;
scroll_status.main_thread_scrolling_reasons =
MainThreadScrollingReason::kNotScrollingOnMain;
- TRACE_EVENT0("cc", "ThreadedInputHandler::ScrollBegin");
+ TRACE_EVENT0("cc", "InputHandler::ScrollBegin");
// If this ScrollBegin is non-animated then ensure we cancel any ongoing
// animated scrolls.
@@ -317,10 +314,9 @@ InputHandler::ScrollStatus ThreadedInputHandler::ScrollBegin(
DCHECK(scrolling_node);
ActiveTree().SetCurrentlyScrollingNode(scrolling_node);
- if (unification_enabled &&
- !scroll_tree.CanRealizeScrollsOnCompositor(*scrolling_node)) {
- scroll_status.needs_main_thread_repaint = true;
- }
+ if (unification_enabled)
+ scroll_status.main_thread_repaint_reasons =
+ scroll_tree.GetMainThreadRepaintReasons(*scrolling_node);
DidLatchToScroller(*scroll_state, type);
@@ -340,10 +336,10 @@ InputHandler::ScrollStatus ThreadedInputHandler::ScrollBegin(
return scroll_status;
}
-InputHandler::ScrollStatus ThreadedInputHandler::RootScrollBegin(
+InputHandler::ScrollStatus InputHandler::RootScrollBegin(
ScrollState* scroll_state,
ui::ScrollInputType type) {
- TRACE_EVENT0("cc", "ThreadedInputHandler::RootScrollBegin");
+ TRACE_EVENT0("cc", "InputHandler::RootScrollBegin");
if (!OuterViewportScrollNode()) {
InputHandler::ScrollStatus scroll_status;
scroll_status.thread = InputHandler::ScrollThread::SCROLL_IGNORED;
@@ -363,14 +359,14 @@ InputHandler::ScrollStatus ThreadedInputHandler::RootScrollBegin(
return scroll_status;
}
-InputHandlerScrollResult ThreadedInputHandler::ScrollUpdate(
+InputHandlerScrollResult InputHandler::ScrollUpdate(
ScrollState* scroll_state,
base::TimeDelta delayed_by) {
DCHECK(scroll_state);
// The current_native_scrolling_element should only be set for ScrollBegin.
DCHECK(!scroll_state->data()->current_native_scrolling_element());
- TRACE_EVENT2("cc", "ThreadedInputHandler::ScrollUpdate", "dx",
+ TRACE_EVENT2("cc", "InputHandler::ScrollUpdate", "dx",
scroll_state->delta_x(), "dy", scroll_state->delta_y());
if (!CurrentlyScrollingNode())
@@ -494,7 +490,7 @@ InputHandlerScrollResult ThreadedInputHandler::ScrollUpdate(
return scroll_result;
}
-void ThreadedInputHandler::AdjustScrollDeltaForScrollbarSnap(
+void InputHandler::AdjustScrollDeltaForScrollbarSnap(
ScrollState* scroll_state) {
ScrollNode* scroll_node = CurrentlyScrollingNode();
if (!scroll_node || !scroll_node->snap_container_data)
@@ -524,7 +520,7 @@ void ThreadedInputHandler::AdjustScrollDeltaForScrollbarSnap(
scroll_state->data()->delta_y = snap_position.y() - current_position.y();
}
-void ThreadedInputHandler::ScrollEnd(bool should_snap) {
+void InputHandler::ScrollEnd(bool should_snap) {
scrollbar_controller_->ResetState();
if (!CurrentlyScrollingNode())
return;
@@ -556,7 +552,7 @@ void ThreadedInputHandler::ScrollEnd(bool should_snap) {
SetNeedsCommit();
}
-void ThreadedInputHandler::RecordScrollBegin(
+void InputHandler::RecordScrollBegin(
ui::ScrollInputType input_type,
ScrollBeginThreadState scroll_start_state) {
auto tracker_type = GetTrackerTypeForScroll(input_type);
@@ -583,12 +579,12 @@ void ThreadedInputHandler::RecordScrollBegin(
tracker_type, scrolling_thread);
}
-void ThreadedInputHandler::RecordScrollEnd(ui::ScrollInputType input_type) {
+void InputHandler::RecordScrollEnd(ui::ScrollInputType input_type) {
compositor_delegate_.GetImplDeprecated().frame_trackers().StopSequence(
GetTrackerTypeForScroll(input_type));
}
-InputHandlerPointerResult ThreadedInputHandler::MouseMoveAt(
+InputHandlerPointerResult InputHandler::MouseMoveAt(
const gfx::Point& viewport_point) {
InputHandlerPointerResult result;
if (compositor_delegate_.GetSettings()
@@ -641,15 +637,14 @@ InputHandlerPointerResult ThreadedInputHandler::MouseMoveAt(
return result;
}
-PointerResultType ThreadedInputHandler::HitTest(
- const gfx::PointF& viewport_point) {
+PointerResultType InputHandler::HitTest(const gfx::PointF& viewport_point) {
return compositor_delegate_.GetSettings()
.compositor_threaded_scrollbar_scrolling
? scrollbar_controller_->HitTest(viewport_point)
: PointerResultType::kUnhandled;
}
-InputHandlerPointerResult ThreadedInputHandler::MouseDown(
+InputHandlerPointerResult InputHandler::MouseDown(
const gfx::PointF& viewport_point,
bool shift_modifier) {
ScrollbarAnimationController* animation_controller =
@@ -672,7 +667,7 @@ InputHandlerPointerResult ThreadedInputHandler::MouseDown(
return result;
}
-InputHandlerPointerResult ThreadedInputHandler::MouseUp(
+InputHandlerPointerResult InputHandler::MouseUp(
const gfx::PointF& viewport_point) {
if (scroll_element_id_mouse_currently_captured_) {
ScrollbarAnimationController* animation_controller =
@@ -694,27 +689,27 @@ InputHandlerPointerResult ThreadedInputHandler::MouseUp(
return result;
}
-void ThreadedInputHandler::MouseLeave() {
+void InputHandler::MouseLeave() {
compositor_delegate_.DidMouseLeave();
scroll_element_id_mouse_currently_over_ = ElementId();
}
-ElementId ThreadedInputHandler::FindFrameElementIdAtPoint(
+ElementId InputHandler::FindFrameElementIdAtPoint(
const gfx::PointF& viewport_point) {
gfx::PointF device_viewport_point = gfx::ScalePoint(
gfx::PointF(viewport_point), compositor_delegate_.DeviceScaleFactor());
return ActiveTree().FindFrameElementIdAtPoint(device_viewport_point);
}
-void ThreadedInputHandler::RequestUpdateForSynchronousInputHandler() {
+void InputHandler::RequestUpdateForSynchronousInputHandler() {
UpdateRootLayerStateForSynchronousInputHandler();
}
-void ThreadedInputHandler::SetSynchronousInputHandlerRootScrollOffset(
+void InputHandler::SetSynchronousInputHandlerRootScrollOffset(
const gfx::PointF& root_content_offset) {
- TRACE_EVENT2(
- "cc", "ThreadedInputHandler::SetSynchronousInputHandlerRootScrollOffset",
- "offset_x", root_content_offset.x(), "offset_y", root_content_offset.y());
+ TRACE_EVENT2("cc", "InputHandler::SetSynchronousInputHandlerRootScrollOffset",
+ "offset_x", root_content_offset.x(), "offset_y",
+ root_content_offset.y());
gfx::Vector2dF physical_delta =
root_content_offset - GetViewport().TotalScrollOffset();
@@ -741,8 +736,8 @@ void ThreadedInputHandler::SetSynchronousInputHandlerRootScrollOffset(
compositor_delegate_.SetNeedsFullViewportRedraw();
}
-void ThreadedInputHandler::PinchGestureBegin(const gfx::Point& anchor,
- ui::ScrollInputType source) {
+void InputHandler::PinchGestureBegin(const gfx::Point& anchor,
+ ui::ScrollInputType source) {
DCHECK(source == ui::ScrollInputType::kTouchscreen ||
source == ui::ScrollInputType::kWheel);
@@ -778,9 +773,9 @@ void ThreadedInputHandler::PinchGestureBegin(const gfx::Point& anchor,
compositor_delegate_.DidStartPinchZoom();
}
-void ThreadedInputHandler::PinchGestureUpdate(float magnify_delta,
- const gfx::Point& anchor) {
- TRACE_EVENT0("cc", "ThreadedInputHandler::PinchGestureUpdate");
+void InputHandler::PinchGestureUpdate(float magnify_delta,
+ const gfx::Point& anchor) {
+ TRACE_EVENT0("cc", "InputHandler::PinchGestureUpdate");
if (!InnerViewportScrollNode())
return;
has_pinch_zoomed_ = true;
@@ -792,7 +787,7 @@ void ThreadedInputHandler::PinchGestureUpdate(float magnify_delta,
UpdateRootLayerStateForSynchronousInputHandler();
}
-void ThreadedInputHandler::PinchGestureEnd(const gfx::Point& anchor) {
+void InputHandler::PinchGestureEnd(const gfx::Point& anchor) {
// Some tests create a pinch gesture without creating a viewport scroll node.
// In those cases, PinchGestureBegin will not latch to a scroll node.
DCHECK(latched_scroll_type_.has_value() || !CurrentlyScrollingNode());
@@ -811,23 +806,23 @@ void ThreadedInputHandler::PinchGestureEnd(const gfx::Point& anchor) {
compositor_delegate_.DidEndPinchZoom();
}
-void ThreadedInputHandler::SetNeedsAnimateInput() {
+void InputHandler::SetNeedsAnimateInput() {
compositor_delegate_.GetImplDeprecated().SetNeedsAnimateInput();
}
-bool ThreadedInputHandler::IsCurrentlyScrollingViewport() const {
+bool InputHandler::IsCurrentlyScrollingViewport() const {
auto* node = CurrentlyScrollingNode();
if (!node)
return false;
return GetViewport().ShouldScroll(*node);
}
-EventListenerProperties ThreadedInputHandler::GetEventListenerProperties(
+EventListenerProperties InputHandler::GetEventListenerProperties(
EventListenerClass event_class) const {
return ActiveTree().event_listener_properties(event_class);
}
-bool ThreadedInputHandler::HasBlockingWheelEventHandlerAt(
+bool InputHandler::HasBlockingWheelEventHandlerAt(
const gfx::Point& viewport_point) const {
gfx::PointF device_viewport_point = gfx::ScalePoint(
gfx::PointF(viewport_point), compositor_delegate_.DeviceScaleFactor());
@@ -840,7 +835,7 @@ bool ThreadedInputHandler::HasBlockingWheelEventHandlerAt(
}
InputHandler::TouchStartOrMoveEventListenerType
-ThreadedInputHandler::EventListenerTypeForTouchStartOrMoveAt(
+InputHandler::EventListenerTypeForTouchStartOrMoveAt(
const gfx::Point& viewport_point,
TouchAction* out_touch_action) {
gfx::PointF device_viewport_point = gfx::ScalePoint(
@@ -894,20 +889,19 @@ ThreadedInputHandler::EventListenerTypeForTouchStartOrMoveAt(
}
std::unique_ptr<LatencyInfoSwapPromiseMonitor>
-ThreadedInputHandler::CreateLatencyInfoSwapPromiseMonitor(
- ui::LatencyInfo* latency) {
+InputHandler::CreateLatencyInfoSwapPromiseMonitor(ui::LatencyInfo* latency) {
return compositor_delegate_.GetImplDeprecated()
.CreateLatencyInfoSwapPromiseMonitor(latency);
}
std::unique_ptr<EventsMetricsManager::ScopedMonitor>
-ThreadedInputHandler::GetScopedEventMetricsMonitor(
+InputHandler::GetScopedEventMetricsMonitor(
EventsMetricsManager::ScopedMonitor::DoneCallback done_callback) {
return compositor_delegate_.GetImplDeprecated().GetScopedEventMetricsMonitor(
std::move(done_callback));
}
-ScrollElasticityHelper* ThreadedInputHandler::CreateScrollElasticityHelper() {
+ScrollElasticityHelper* InputHandler::CreateScrollElasticityHelper() {
DCHECK(!scroll_elasticity_helper_);
if (compositor_delegate_.GetSettings().enable_elastic_overscroll) {
scroll_elasticity_helper_.reset(
@@ -917,14 +911,14 @@ ScrollElasticityHelper* ThreadedInputHandler::CreateScrollElasticityHelper() {
return scroll_elasticity_helper_.get();
}
-void ThreadedInputHandler::DestroyScrollElasticityHelper() {
+void InputHandler::DestroyScrollElasticityHelper() {
// Remove any stretch before destroying helper.
scroll_elasticity_helper_->SetStretchAmount(gfx::Vector2dF());
scroll_elasticity_helper_.reset();
}
-bool ThreadedInputHandler::GetScrollOffsetForLayer(ElementId element_id,
- gfx::PointF* offset) {
+bool InputHandler::GetScrollOffsetForLayer(ElementId element_id,
+ gfx::PointF* offset) {
ScrollTree& scroll_tree = GetScrollTree();
ScrollNode* scroll_node = scroll_tree.FindNodeFromElementId(element_id);
if (!scroll_node)
@@ -933,8 +927,8 @@ bool ThreadedInputHandler::GetScrollOffsetForLayer(ElementId element_id,
return true;
}
-bool ThreadedInputHandler::ScrollLayerTo(ElementId element_id,
- const gfx::PointF& offset) {
+bool InputHandler::ScrollLayerTo(ElementId element_id,
+ const gfx::PointF& offset) {
ScrollTree& scroll_tree = GetScrollTree();
ScrollNode* scroll_node = scroll_tree.FindNodeFromElementId(element_id);
if (!scroll_node)
@@ -946,7 +940,7 @@ bool ThreadedInputHandler::ScrollLayerTo(ElementId element_id,
return true;
}
-bool ThreadedInputHandler::ScrollingShouldSwitchtoMainThread() {
+bool InputHandler::ScrollingShouldSwitchtoMainThread() {
DCHECK(!base::FeatureList::IsEnabled(features::kScrollUnification));
ScrollTree& scroll_tree = GetScrollTree();
ScrollNode* scroll_node = scroll_tree.CurrentlyScrollingNode();
@@ -963,7 +957,7 @@ bool ThreadedInputHandler::ScrollingShouldSwitchtoMainThread() {
return false;
}
-bool ThreadedInputHandler::GetSnapFlingInfoAndSetAnimatingSnapTarget(
+bool InputHandler::GetSnapFlingInfoAndSetAnimatingSnapTarget(
const gfx::Vector2dF& natural_displacement_in_viewport,
gfx::PointF* out_initial_position,
gfx::PointF* out_target_position) {
@@ -995,7 +989,7 @@ bool ThreadedInputHandler::GetSnapFlingInfoAndSetAnimatingSnapTarget(
return true;
}
-void ThreadedInputHandler::ScrollEndForSnapFling(bool did_finish) {
+void InputHandler::ScrollEndForSnapFling(bool did_finish) {
ScrollNode* scroll_node = CurrentlyScrollingNode();
// When a snap fling animation reaches its intended target then we update the
// scrolled node's snap targets. This also ensures blink learns about the new
@@ -1012,7 +1006,7 @@ void ThreadedInputHandler::ScrollEndForSnapFling(bool did_finish) {
ScrollEnd(false /* should_snap */);
}
-void ThreadedInputHandler::NotifyInputEvent() {
+void InputHandler::NotifyInputEvent() {
compositor_delegate_.GetImplDeprecated().NotifyInputEvent();
}
@@ -1020,8 +1014,7 @@ void ThreadedInputHandler::NotifyInputEvent() {
// =========== InputDelegateForCompositor Interface
//
-void ThreadedInputHandler::ProcessCommitDeltas(
- CompositorCommitData* commit_data) {
+void InputHandler::ProcessCommitDeltas(CompositorCommitData* commit_data) {
DCHECK(commit_data);
if (ActiveTree().LayerListIsEmpty())
return;
@@ -1080,7 +1073,7 @@ void ThreadedInputHandler::ProcessCommitDeltas(
last_latched_scroller_ = ElementId();
}
-void ThreadedInputHandler::TickAnimations(base::TimeTicks monotonic_time) {
+void InputHandler::TickAnimations(base::TimeTicks monotonic_time) {
if (input_handler_client_) {
// This does not set did_animate, because if the InputHandlerClient
// changes anything it will be through the InputHandler interface which
@@ -1089,36 +1082,35 @@ void ThreadedInputHandler::TickAnimations(base::TimeTicks monotonic_time) {
}
}
-void ThreadedInputHandler::WillShutdown() {
+void InputHandler::WillShutdown() {
if (input_handler_client_) {
- input_handler_client_->WillShutdown();
- input_handler_client_ = nullptr;
+ input_handler_client_.ExtractAsDangling()->WillShutdown();
}
if (scroll_elasticity_helper_)
scroll_elasticity_helper_.reset();
}
-void ThreadedInputHandler::WillDraw() {
+void InputHandler::WillDraw() {
if (input_handler_client_)
input_handler_client_->ReconcileElasticOverscrollAndRootScroll();
}
-void ThreadedInputHandler::WillBeginImplFrame(const viz::BeginFrameArgs& args) {
+void InputHandler::WillBeginImplFrame(const viz::BeginFrameArgs& args) {
if (input_handler_client_) {
scrollbar_controller_->WillBeginImplFrame();
input_handler_client_->DeliverInputForBeginFrame(args);
}
}
-void ThreadedInputHandler::DidCommit() {
+void InputHandler::DidCommit() {
// In high latency mode commit cannot finish within the same frame. We need to
// flush input here to make sure they got picked up by |PrepareTiles()|.
if (input_handler_client_ && compositor_delegate_.IsInHighLatencyMode())
input_handler_client_->DeliverInputForHighLatencyMode();
}
-void ThreadedInputHandler::DidActivatePendingTree() {
+void InputHandler::DidActivatePendingTree() {
// The previous scrolling node might no longer exist in the new tree.
if (!CurrentlyScrollingNode())
ClearCurrentlyScrollingNode();
@@ -1128,24 +1120,22 @@ void ThreadedInputHandler::DidActivatePendingTree() {
UpdateRootLayerStateForSynchronousInputHandler();
}
-void ThreadedInputHandler::RootLayerStateMayHaveChanged() {
+void InputHandler::RootLayerStateMayHaveChanged() {
UpdateRootLayerStateForSynchronousInputHandler();
}
-void ThreadedInputHandler::DidRegisterScrollbar(
- ElementId scroll_element_id,
- ScrollbarOrientation orientation) {
+void InputHandler::DidRegisterScrollbar(ElementId scroll_element_id,
+ ScrollbarOrientation orientation) {
scrollbar_controller_->DidRegisterScrollbar(scroll_element_id, orientation);
}
-void ThreadedInputHandler::DidUnregisterScrollbar(
- ElementId scroll_element_id,
- ScrollbarOrientation orientation) {
+void InputHandler::DidUnregisterScrollbar(ElementId scroll_element_id,
+ ScrollbarOrientation orientation) {
scrollbar_controller_->DidUnregisterScrollbar(scroll_element_id, orientation);
}
-void ThreadedInputHandler::ScrollOffsetAnimationFinished() {
- TRACE_EVENT0("cc", "ThreadedInputHandler::ScrollOffsetAnimationFinished");
+void InputHandler::ScrollOffsetAnimationFinished() {
+ TRACE_EVENT0("cc", "InputHandler::ScrollOffsetAnimationFinished");
// ScrollOffsetAnimationFinished is called in two cases:
// 1- smooth scrolling animation is over (IsAnimatingForSnap == false).
// 2- snap scroll animation is over (IsAnimatingForSnap == true).
@@ -1175,8 +1165,7 @@ void ThreadedInputHandler::ScrollOffsetAnimationFinished() {
}
}
-void ThreadedInputHandler::SetPrefersReducedMotion(
- bool prefers_reduced_motion) {
+void InputHandler::SetPrefersReducedMotion(bool prefers_reduced_motion) {
if (prefers_reduced_motion_ == prefers_reduced_motion)
return;
prefers_reduced_motion_ = prefers_reduced_motion;
@@ -1185,11 +1174,11 @@ void ThreadedInputHandler::SetPrefersReducedMotion(
input_handler_client_->SetPrefersReducedMotion(prefers_reduced_motion_);
}
-bool ThreadedInputHandler::IsCurrentlyScrolling() const {
+bool InputHandler::IsCurrentlyScrolling() const {
return CurrentlyScrollingNode();
}
-ActivelyScrollingType ThreadedInputHandler::GetActivelyScrollingType() const {
+ActivelyScrollingType InputHandler::GetActivelyScrollingType() const {
if (!CurrentlyScrollingNode())
return ActivelyScrollingType::kNone;
@@ -1205,49 +1194,49 @@ ActivelyScrollingType ThreadedInputHandler::GetActivelyScrollingType() const {
return ActivelyScrollingType::kPrecise;
}
-ScrollNode* ThreadedInputHandler::CurrentlyScrollingNode() {
+ScrollNode* InputHandler::CurrentlyScrollingNode() {
return GetScrollTree().CurrentlyScrollingNode();
}
-const ScrollNode* ThreadedInputHandler::CurrentlyScrollingNode() const {
+const ScrollNode* InputHandler::CurrentlyScrollingNode() const {
return GetScrollTree().CurrentlyScrollingNode();
}
-ScrollTree& ThreadedInputHandler::GetScrollTree() {
+ScrollTree& InputHandler::GetScrollTree() {
return compositor_delegate_.GetScrollTree();
}
-ScrollTree& ThreadedInputHandler::GetScrollTree() const {
+ScrollTree& InputHandler::GetScrollTree() const {
return compositor_delegate_.GetScrollTree();
}
-ScrollNode* ThreadedInputHandler::InnerViewportScrollNode() const {
+ScrollNode* InputHandler::InnerViewportScrollNode() const {
return ActiveTree().InnerViewportScrollNode();
}
-ScrollNode* ThreadedInputHandler::OuterViewportScrollNode() const {
+ScrollNode* InputHandler::OuterViewportScrollNode() const {
return ActiveTree().OuterViewportScrollNode();
}
-Viewport& ThreadedInputHandler::GetViewport() const {
+Viewport& InputHandler::GetViewport() const {
return compositor_delegate_.GetImplDeprecated().viewport();
}
-void ThreadedInputHandler::SetNeedsCommit() {
+void InputHandler::SetNeedsCommit() {
compositor_delegate_.SetNeedsCommit();
}
-LayerTreeImpl& ThreadedInputHandler::ActiveTree() {
+LayerTreeImpl& InputHandler::ActiveTree() {
DCHECK(compositor_delegate_.GetImplDeprecated().active_tree());
return *compositor_delegate_.GetImplDeprecated().active_tree();
}
-LayerTreeImpl& ThreadedInputHandler::ActiveTree() const {
+LayerTreeImpl& InputHandler::ActiveTree() const {
DCHECK(compositor_delegate_.GetImplDeprecated().active_tree());
return *compositor_delegate_.GetImplDeprecated().active_tree();
}
-FrameSequenceTrackerType ThreadedInputHandler::GetTrackerTypeForScroll(
+FrameSequenceTrackerType InputHandler::GetTrackerTypeForScroll(
ui::ScrollInputType input_type) const {
switch (input_type) {
case ui::ScrollInputType::kWheel:
@@ -1261,7 +1250,7 @@ FrameSequenceTrackerType ThreadedInputHandler::GetTrackerTypeForScroll(
}
}
-bool ThreadedInputHandler::IsMainThreadScrolling(
+bool InputHandler::IsMainThreadScrolling(
const InputHandler::ScrollStatus& status,
const ScrollNode* scroll_node) const {
if (status.thread == InputHandler::ScrollThread::SCROLL_ON_MAIN_THREAD) {
@@ -1277,14 +1266,14 @@ bool ThreadedInputHandler::IsMainThreadScrolling(
return false;
}
-float ThreadedInputHandler::LineStep() const {
+float InputHandler::LineStep() const {
return kPixelsPerLineStep;
}
// TODO(mehdika): There is some redundancy between this function and
// ScrollbarController::GetScrollDistanceForScrollbarPart, these two need to be
// kept in sync.
-gfx::Vector2dF ThreadedInputHandler::ResolveScrollGranularityToPixels(
+gfx::Vector2dF InputHandler::ResolveScrollGranularityToPixels(
const ScrollNode& scroll_node,
const gfx::Vector2dF& scroll_delta,
ui::ScrollGranularity granularity) {
@@ -1320,7 +1309,7 @@ gfx::Vector2dF ThreadedInputHandler::ResolveScrollGranularityToPixels(
return pixel_delta;
}
-InputHandler::ScrollStatus ThreadedInputHandler::TryScroll(
+InputHandler::ScrollStatus InputHandler::TryScroll(
const ScrollTree& scroll_tree,
ScrollNode* scroll_node) const {
DCHECK(!base::FeatureList::IsEnabled(features::kScrollUnification));
@@ -1391,7 +1380,7 @@ InputHandler::ScrollStatus ThreadedInputHandler::TryScroll(
return scroll_status;
}
-base::flat_set<int> ThreadedInputHandler::NonFastScrollableNodes(
+base::flat_set<int> InputHandler::NonFastScrollableNodes(
const gfx::PointF& device_viewport_point) const {
base::flat_set<int> non_fast_scrollable_nodes;
@@ -1404,7 +1393,7 @@ base::flat_set<int> ThreadedInputHandler::NonFastScrollableNodes(
return non_fast_scrollable_nodes;
}
-ScrollNode* ThreadedInputHandler::FindScrollNodeForCompositedScrolling(
+ScrollNode* InputHandler::FindScrollNodeForCompositedScrolling(
const gfx::PointF& device_viewport_point,
LayerImpl* layer_impl,
bool* scroll_on_main_thread,
@@ -1486,8 +1475,7 @@ ScrollNode* ThreadedInputHandler::FindScrollNodeForCompositedScrolling(
return impl_scroll_node;
}
-ThreadedInputHandler::ScrollHitTestResult
-ThreadedInputHandler::HitTestScrollNode(
+InputHandler::ScrollHitTestResult InputHandler::HitTestScrollNode(
const gfx::PointF& device_viewport_point) const {
ScrollHitTestResult result;
result.scroll_node = nullptr;
@@ -1559,7 +1547,7 @@ ThreadedInputHandler::HitTestScrollNode(
// Requires falling back to main thread scrolling when it hit tests in scrollbar
// from touch.
-bool ThreadedInputHandler::IsTouchDraggingScrollbar(
+bool InputHandler::IsTouchDraggingScrollbar(
LayerImpl* first_scrolling_layer_or_scrollbar,
ui::ScrollInputType type) {
return first_scrolling_layer_or_scrollbar &&
@@ -1567,7 +1555,7 @@ bool ThreadedInputHandler::IsTouchDraggingScrollbar(
type == ui::ScrollInputType::kTouchscreen;
}
-ScrollNode* ThreadedInputHandler::GetNodeToScroll(ScrollNode* node) const {
+ScrollNode* InputHandler::GetNodeToScroll(ScrollNode* node) const {
// Blink has a notion of a "root scroller", which is the scroller in a page
// that is considered to host the main content. Typically this will be the
// document/LayoutView contents; however, in some situations Blink may choose
@@ -1599,7 +1587,7 @@ ScrollNode* ThreadedInputHandler::GetNodeToScroll(ScrollNode* node) const {
return node;
}
-bool ThreadedInputHandler::IsInitialScrollHitTestReliable(
+bool InputHandler::IsInitialScrollHitTestReliable(
const LayerImpl* layer_impl,
const LayerImpl* first_scrolling_layer_or_scrollbar) const {
if (!first_scrolling_layer_or_scrollbar)
@@ -1641,9 +1629,8 @@ bool ThreadedInputHandler::IsInitialScrollHitTestReliable(
return false;
}
-gfx::Vector2dF ThreadedInputHandler::ComputeScrollDelta(
- const ScrollNode& scroll_node,
- const gfx::Vector2dF& delta) {
+gfx::Vector2dF InputHandler::ComputeScrollDelta(const ScrollNode& scroll_node,
+ const gfx::Vector2dF& delta) {
ScrollTree& scroll_tree = GetScrollTree();
float scale_factor = compositor_delegate_.PageScaleFactor();
@@ -1659,7 +1646,7 @@ gfx::Vector2dF ThreadedInputHandler::ComputeScrollDelta(
return new_offset - old_offset;
}
-bool ThreadedInputHandler::CalculateLocalScrollDeltaAndStartPoint(
+bool InputHandler::CalculateLocalScrollDeltaAndStartPoint(
const ScrollNode& scroll_node,
const gfx::PointF& viewport_point,
const gfx::Vector2dF& viewport_delta,
@@ -1706,7 +1693,7 @@ bool ThreadedInputHandler::CalculateLocalScrollDeltaAndStartPoint(
return true;
}
-gfx::Vector2dF ThreadedInputHandler::ScrollNodeWithViewportSpaceDelta(
+gfx::Vector2dF InputHandler::ScrollNodeWithViewportSpaceDelta(
const ScrollNode& scroll_node,
const gfx::PointF& viewport_point,
const gfx::Vector2dF& viewport_delta) {
@@ -1755,7 +1742,7 @@ gfx::Vector2dF ThreadedInputHandler::ScrollNodeWithViewportSpaceDelta(
return actual_viewport_end_point - viewport_point;
}
-gfx::Vector2dF ThreadedInputHandler::ScrollNodeWithLocalDelta(
+gfx::Vector2dF InputHandler::ScrollNodeWithLocalDelta(
const ScrollNode& scroll_node,
const gfx::Vector2dF& local_delta) const {
bool scrolls_outer_viewport = scroll_node.scrolls_outer_viewport;
@@ -1782,11 +1769,10 @@ gfx::Vector2dF ThreadedInputHandler::ScrollNodeWithLocalDelta(
// TODO(danakj): Make this into two functions, one with delta, one with
// viewport_point, no bool required.
-gfx::Vector2dF ThreadedInputHandler::ScrollSingleNode(
- const ScrollNode& scroll_node,
- const gfx::Vector2dF& delta,
- const gfx::Point& viewport_point,
- bool is_direct_manipulation) {
+gfx::Vector2dF InputHandler::ScrollSingleNode(const ScrollNode& scroll_node,
+ const gfx::Vector2dF& delta,
+ const gfx::Point& viewport_point,
+ bool is_direct_manipulation) {
gfx::Vector2dF adjusted_delta = UserScrollableDelta(scroll_node, delta);
// Events representing direct manipulation of the screen (such as gesture
@@ -1807,15 +1793,15 @@ gfx::Vector2dF ThreadedInputHandler::ScrollSingleNode(
return ScrollNodeWithLocalDelta(scroll_node, adjusted_delta);
}
-void ThreadedInputHandler::ScrollLatchedScroller(ScrollState* scroll_state,
- base::TimeDelta delayed_by) {
+void InputHandler::ScrollLatchedScroller(ScrollState* scroll_state,
+ base::TimeDelta delayed_by) {
DCHECK(CurrentlyScrollingNode());
DCHECK(scroll_state);
DCHECK(latched_scroll_type_.has_value());
ScrollNode& scroll_node = *CurrentlyScrollingNode();
const gfx::Vector2dF delta(scroll_state->delta_x(), scroll_state->delta_y());
- TRACE_EVENT2("cc", "ThreadedInputHandler::ScrollLatchedScroller", "delta_x",
+ TRACE_EVENT2("cc", "InputHandler::ScrollLatchedScroller", "delta_x",
delta.x(), "delta_y", delta.y());
gfx::Vector2dF applied_delta;
gfx::Vector2dF delta_applied_to_content;
@@ -1934,18 +1920,16 @@ void ThreadedInputHandler::ScrollLatchedScroller(ScrollState* scroll_state,
scroll_state->ConsumeDelta(applied_delta.x(), applied_delta.y());
}
-bool ThreadedInputHandler::CanPropagate(ScrollNode* scroll_node,
- float x,
- float y) {
+bool InputHandler::CanPropagate(ScrollNode* scroll_node, float x, float y) {
return (x == 0 || scroll_node->overscroll_behavior.x ==
OverscrollBehavior::Type::kAuto) &&
(y == 0 || scroll_node->overscroll_behavior.y ==
OverscrollBehavior::Type::kAuto);
}
-ScrollNode* ThreadedInputHandler::FindNodeToLatch(ScrollState* scroll_state,
- ScrollNode* starting_node,
- ui::ScrollInputType type) {
+ScrollNode* InputHandler::FindNodeToLatch(ScrollState* scroll_state,
+ ScrollNode* starting_node,
+ ui::ScrollInputType type) {
ScrollTree& scroll_tree = GetScrollTree();
ScrollNode* scroll_node = nullptr;
ScrollNode* first_scrollable_node = nullptr;
@@ -1999,7 +1983,7 @@ ScrollNode* ThreadedInputHandler::FindNodeToLatch(ScrollState* scroll_state,
return scroll_node;
}
-void ThreadedInputHandler::UpdateRootLayerStateForSynchronousInputHandler() {
+void InputHandler::UpdateRootLayerStateForSynchronousInputHandler() {
if (!input_handler_client_)
return;
input_handler_client_->UpdateRootLayerStateForSynchronousInputHandler(
@@ -2009,8 +1993,8 @@ void ThreadedInputHandler::UpdateRootLayerStateForSynchronousInputHandler() {
ActiveTree().max_page_scale_factor());
}
-void ThreadedInputHandler::DidLatchToScroller(const ScrollState& scroll_state,
- ui::ScrollInputType type) {
+void InputHandler::DidLatchToScroller(const ScrollState& scroll_state,
+ ui::ScrollInputType type) {
DCHECK(CurrentlyScrollingNode());
deferred_scroll_end_ = false;
compositor_delegate_.GetImplDeprecated()
@@ -2032,8 +2016,8 @@ void ThreadedInputHandler::DidLatchToScroller(const ScrollState& scroll_state,
UpdateScrollSourceInfo(scroll_state, type);
}
-bool ThreadedInputHandler::CanConsumeDelta(const ScrollState& scroll_state,
- const ScrollNode& scroll_node) {
+bool InputHandler::CanConsumeDelta(const ScrollState& scroll_state,
+ const ScrollNode& scroll_node) {
gfx::Vector2dF delta_to_scroll;
if (scroll_state.is_beginning()) {
delta_to_scroll = gfx::Vector2dF(scroll_state.delta_x_hint(),
@@ -2066,8 +2050,7 @@ bool ThreadedInputHandler::CanConsumeDelta(const ScrollState& scroll_state,
return false;
}
-bool ThreadedInputHandler::ShouldAnimateScroll(
- const ScrollState& scroll_state) const {
+bool InputHandler::ShouldAnimateScroll(const ScrollState& scroll_state) const {
if (!compositor_delegate_.GetSettings().enable_smooth_scroll)
return false;
@@ -2077,7 +2060,7 @@ bool ThreadedInputHandler::ShouldAnimateScroll(
return !has_precise_scroll_deltas;
}
-bool ThreadedInputHandler::SnapAtScrollEnd(SnapReason reason) {
+bool InputHandler::SnapAtScrollEnd(SnapReason reason) {
ScrollNode* scroll_node = CurrentlyScrollingNode();
if (!scroll_node || !scroll_node->snap_container_data.has_value())
return false;
@@ -2151,19 +2134,19 @@ bool ThreadedInputHandler::SnapAtScrollEnd(SnapReason reason) {
return did_animate;
}
-bool ThreadedInputHandler::IsAnimatingForSnap() const {
+bool InputHandler::IsAnimatingForSnap() const {
return scroll_animating_snap_target_ids_ != TargetSnapAreaElementIds();
}
-gfx::PointF ThreadedInputHandler::GetVisualScrollOffset(
+gfx::PointF InputHandler::GetVisualScrollOffset(
const ScrollNode& scroll_node) const {
if (scroll_node.scrolls_outer_viewport)
return GetViewport().TotalScrollOffset();
return GetScrollTree().current_scroll_offset(scroll_node.element_id);
}
-void ThreadedInputHandler::ClearCurrentlyScrollingNode() {
- TRACE_EVENT0("cc", "ThreadedInputHandler::ClearCurrentlyScrollingNode");
+void InputHandler::ClearCurrentlyScrollingNode() {
+ TRACE_EVENT0("cc", "InputHandler::ClearCurrentlyScrollingNode");
ActiveTree().ClearCurrentlyScrollingNode();
accumulated_root_overscroll_ = gfx::Vector2dF();
did_scroll_x_for_scroll_gesture_ = false;
@@ -2176,7 +2159,7 @@ void ThreadedInputHandler::ClearCurrentlyScrollingNode() {
compositor_delegate_.DidEndScroll();
}
-bool ThreadedInputHandler::ScrollAnimationUpdateTarget(
+bool InputHandler::ScrollAnimationUpdateTarget(
const ScrollNode& scroll_node,
const gfx::Vector2dF& scroll_delta,
base::TimeDelta delayed_by) {
@@ -2212,9 +2195,8 @@ bool ThreadedInputHandler::ScrollAnimationUpdateTarget(
return animation_updated;
}
-void ThreadedInputHandler::UpdateScrollSourceInfo(
- const ScrollState& scroll_state,
- ui::ScrollInputType type) {
+void InputHandler::UpdateScrollSourceInfo(const ScrollState& scroll_state,
+ ui::ScrollInputType type) {
if (type == ui::ScrollInputType::kWheel &&
scroll_state.delta_granularity() ==
ui::ScrollGranularity::kScrollByPrecisePixel) {
@@ -2230,8 +2212,7 @@ void ThreadedInputHandler::UpdateScrollSourceInfo(
// Return true if scrollable node for 'ancestor' is the same as 'child' or an
// ancestor along the scroll tree.
-bool ThreadedInputHandler::IsScrolledBy(LayerImpl* child,
- ScrollNode* ancestor) {
+bool InputHandler::IsScrolledBy(LayerImpl* child, ScrollNode* ancestor) {
DCHECK(ancestor && ancestor->scrollable);
if (!child)
return false;
@@ -2245,7 +2226,7 @@ bool ThreadedInputHandler::IsScrolledBy(LayerImpl* child,
return false;
}
-gfx::Vector2dF ThreadedInputHandler::UserScrollableDelta(
+gfx::Vector2dF InputHandler::UserScrollableDelta(
const ScrollNode& node,
const gfx::Vector2dF& delta) const {
gfx::Vector2dF adjusted_delta = delta;
@@ -2257,12 +2238,11 @@ gfx::Vector2dF ThreadedInputHandler::UserScrollableDelta(
return adjusted_delta;
}
-bool ThreadedInputHandler::ScrollbarScrollIsActive() {
+bool InputHandler::ScrollbarScrollIsActive() {
return scrollbar_controller_->ScrollbarScrollIsActive();
}
-void ThreadedInputHandler::SetDeferBeginMainFrame(
- bool defer_begin_main_frame) const {
+void InputHandler::SetDeferBeginMainFrame(bool defer_begin_main_frame) const {
compositor_delegate_.SetDeferBeginMainFrame(defer_begin_main_frame);
}
diff --git a/chromium/cc/input/input_handler.h b/chromium/cc/input/input_handler.h
index ae2ff545aa7..83e52afddb7 100644
--- a/chromium/cc/input/input_handler.h
+++ b/chromium/cc/input/input_handler.h
@@ -9,6 +9,7 @@
#include "base/time/time.h"
#include "cc/cc_export.h"
+#include "cc/input/compositor_input_interfaces.h"
#include "cc/input/event_listener_properties.h"
#include "cc/input/main_thread_scrolling_reason.h"
#include "cc/input/overscroll_behavior.h"
@@ -16,6 +17,7 @@
#include "cc/input/scrollbar.h"
#include "cc/input/touch_action.h"
#include "cc/metrics/events_metrics_manager.h"
+#include "cc/metrics/frame_sequence_metrics.h"
#include "cc/paint/element_id.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
#include "ui/events/types/scroll_input_type.h"
@@ -36,7 +38,10 @@ namespace cc {
class CompositorDelegateForInput;
class LatencyInfoSwapPromiseMonitor;
+class LayerImpl;
+class ScrollbarController;
class ScrollElasticityHelper;
+class Viewport;
enum class PointerResultType { kUnhandled = 0, kScrollbarScroll };
@@ -131,7 +136,7 @@ class CC_EXPORT InputHandlerClient {
// main thread about changes that have occurred as a result of input since the
// last commit.
struct InputHandlerCommitData {
- // Defined in threaded_input_handler.cc to avoid inlining since flat_set has
+ // Defined in input_handler.cc to avoid inlining since flat_set has
// non-trivial size destructor.
InputHandlerCommitData();
~InputHandlerCommitData();
@@ -157,9 +162,9 @@ struct InputHandlerCommitData {
bool has_scrolled_by_precisiontouchpad = false;
};
-// The InputHandler interface is a way for the embedders to interact with the
-// input system running on the compositor thread. Each instance of a compositor
-// (i.e. a LayerTreeHostImpl) is associated with one InputHandler instance. The
+// The InputHandler is a way for the embedders to interact with the input system
+// running on the compositor thread. Each instance of a compositor (i.e. a
+// LayerTreeHostImpl) is associated with one InputHandler instance. The
// InputHandler sits in between the embedder (the UI compositor or Blink) and
// the compositor (LayerTreeHostImpl); as such, it must be bound to both.
//
@@ -169,7 +174,10 @@ struct InputHandlerCommitData {
// the InputHandlerClient interface and bind it to the handler by calling
// BindToClient on the input handler. This should all be done on the
// input-handling thread (i.e. the "compositor" thread if one exists).
-class CC_EXPORT InputHandler {
+//
+// Many methods are virtual for input_handler_proxy_unittest.cc.
+// TODO: consider revising these tests to reduce reliance on mocking.
+class CC_EXPORT InputHandler : public InputDelegateForCompositor {
public:
// Creates an instance of the InputHandler and binds it to the layer tree
// delegate. The delegate owns the InputHandler so their lifetimes
@@ -189,6 +197,9 @@ class CC_EXPORT InputHandler {
LAST_SCROLL_STATUS = SCROLL_UNKNOWN
};
+ explicit InputHandler(CompositorDelegateForInput& compositor_delegate);
+ ~InputHandler() override;
+
InputHandler(const InputHandler&) = delete;
InputHandler& operator=(const InputHandler&) = delete;
@@ -221,12 +232,15 @@ class CC_EXPORT InputHandler {
// the main thread to perform a hit test.
bool needs_main_thread_hit_test = false;
- // Used only in scroll unification. Tells the caller that we have performed
+ // Used only in scroll unification. A nonzero value means we have performed
// the scroll (i.e. updated the offset in the scroll tree) on the compositor
// thread, but we will need a main thread lifecycle update + commit before
// the user will see the new pixels (for example, because the scroller does
- // not have a composited layer).
- bool needs_main_thread_repaint = false;
+ // not have a composited layer). If nonzero, this will be one or more values
+ // from the MainThreadScrollingReason enum. (Unification avoids setting
+ // main_thread_scrolling_reasons, to keep that field consistent with
+ // semantics of ScrollThread::SCROLL_ON_IMPL_THREAD.)
+ uint32_t main_thread_repaint_reasons = 0;
};
enum class TouchStartOrMoveEventListenerType {
@@ -235,12 +249,12 @@ class CC_EXPORT InputHandler {
HANDLER_ON_SCROLLING_LAYER
};
- virtual base::WeakPtr<InputHandler> AsWeakPtr() const = 0;
+ virtual base::WeakPtr<InputHandler> AsWeakPtr() const;
// Binds a client to this handler to receive notifications. Only one client
// can be bound to an InputHandler. The client must live at least until the
// handler calls WillShutdown() on the client.
- virtual void BindToClient(InputHandlerClient* client) = 0;
+ virtual void BindToClient(InputHandlerClient* client);
// Selects a ScrollNode to be "latched" for scrolling using the
// |scroll_state| start position. The selected node remains latched until the
@@ -250,12 +264,12 @@ class CC_EXPORT InputHandler {
// SCROLL_IGNORED if there is nothing to be scrolled at the given
// coordinates.
virtual ScrollStatus ScrollBegin(ScrollState* scroll_state,
- ui::ScrollInputType type) = 0;
+ ui::ScrollInputType type);
// Similar to ScrollBegin, except the hit test is skipped and scroll always
// targets at the root layer.
virtual ScrollStatus RootScrollBegin(ScrollState* scroll_state,
- ui::ScrollInputType type) = 0;
+ ui::ScrollInputType type);
// Scroll the layer selected by |ScrollBegin| by given |scroll_state| delta.
// Internally, the delta is transformed to local layer's coordinate space for
@@ -271,66 +285,66 @@ class CC_EXPORT InputHandler {
// |delayed_by| is the delay from the event that caused the scroll. This is
// taken into account when determining the duration of the animation if one
// is created.
- virtual InputHandlerScrollResult ScrollUpdate(ScrollState* scroll_state,
- base::TimeDelta delayed_by) = 0;
+ virtual InputHandlerScrollResult ScrollUpdate(
+ ScrollState* scroll_state,
+ base::TimeDelta delayed_by = base::TimeDelta());
// Stop scrolling the selected layer. Must be called only if ScrollBegin()
// returned SCROLL_STARTED. No-op if ScrollBegin wasn't called or didn't
// result in a successful scroll latch. Snap to a snap position if
// |should_snap| is true.
- virtual void ScrollEnd(bool should_snap = false) = 0;
+ virtual void ScrollEnd(bool should_snap = false);
// Called to notify every time scroll-begin/end is attempted by an input
// event.
virtual void RecordScrollBegin(ui::ScrollInputType input_type,
- ScrollBeginThreadState scroll_start_state) = 0;
- virtual void RecordScrollEnd(ui::ScrollInputType input_type) = 0;
+ ScrollBeginThreadState scroll_start_state);
+ virtual void RecordScrollEnd(ui::ScrollInputType input_type);
- virtual PointerResultType HitTest(const gfx::PointF& mouse_position) = 0;
+ virtual PointerResultType HitTest(const gfx::PointF& mouse_position);
virtual InputHandlerPointerResult MouseMoveAt(
- const gfx::Point& mouse_position) = 0;
+ const gfx::Point& mouse_position);
// TODO(arakeri): Pass in the modifier instead of a bool once the refactor
// (crbug.com/1022097) is done. For details, see crbug.com/1016955.
virtual InputHandlerPointerResult MouseDown(const gfx::PointF& mouse_position,
- bool shift_modifier) = 0;
- virtual InputHandlerPointerResult MouseUp(
- const gfx::PointF& mouse_position) = 0;
- virtual void MouseLeave() = 0;
+ bool shift_modifier);
+ virtual InputHandlerPointerResult MouseUp(const gfx::PointF& mouse_position);
+ virtual void MouseLeave();
// Returns visible_frame_element_id from the layer hit by the given point.
// If the hit test failed, an invalid element ID is returned.
virtual ElementId FindFrameElementIdAtPoint(
- const gfx::PointF& mouse_position) = 0;
+ const gfx::PointF& mouse_position);
// Requests a callback to UpdateRootLayerStateForSynchronousInputHandler()
// giving the current root scroll and page scale information.
- virtual void RequestUpdateForSynchronousInputHandler() = 0;
+ virtual void RequestUpdateForSynchronousInputHandler();
// Called when the root scroll offset has been changed in the synchronous
// input handler by the application (outside of input event handling). Offset
// is expected in "content/page coordinates".
virtual void SetSynchronousInputHandlerRootScrollOffset(
- const gfx::PointF& root_content_offset) = 0;
+ const gfx::PointF& root_content_offset);
virtual void PinchGestureBegin(const gfx::Point& anchor,
- ui::ScrollInputType source) = 0;
+ ui::ScrollInputType source);
virtual void PinchGestureUpdate(float magnify_delta,
- const gfx::Point& anchor) = 0;
- virtual void PinchGestureEnd(const gfx::Point& anchor) = 0;
+ const gfx::Point& anchor);
+ virtual void PinchGestureEnd(const gfx::Point& anchor);
// Request another callback to InputHandlerClient::Animate().
- virtual void SetNeedsAnimateInput() = 0;
+ virtual void SetNeedsAnimateInput();
// Returns true if there is an active scroll on the viewport.
- virtual bool IsCurrentlyScrollingViewport() const = 0;
+ virtual bool IsCurrentlyScrollingViewport() const;
virtual EventListenerProperties GetEventListenerProperties(
- EventListenerClass event_class) const = 0;
+ EventListenerClass event_class) const;
// Returns true if |viewport_point| hits a wheel event handler region that
// could block scrolling.
virtual bool HasBlockingWheelEventHandlerAt(
- const gfx::Point& viewport_point) const = 0;
+ const gfx::Point& viewport_point) const;
// It returns the type of a touch start or move event listener at
// |viewport_point|. Whether the page should be given the opportunity to
@@ -343,7 +357,7 @@ class CC_EXPORT InputHandler {
// default touch action is auto.
virtual TouchStartOrMoveEventListenerType
EventListenerTypeForTouchStartOrMoveAt(const gfx::Point& viewport_point,
- TouchAction* out_touch_action) = 0;
+ TouchAction* out_touch_action);
// Calling `CreateLatencyInfoSwapPromiseMonitor()` to get a scoped
// `LatencyInfoSwapPromiseMonitor`. During the life time of the
@@ -351,7 +365,7 @@ class CC_EXPORT InputHandler {
// `SetNeedsRedrawRect()` is called on `LayerTreeHostImpl`, the original
// latency info will be turned into a `LatencyInfoSwapPromise`.
virtual std::unique_ptr<LatencyInfoSwapPromiseMonitor>
- CreateLatencyInfoSwapPromiseMonitor(ui::LatencyInfo* latency) = 0;
+ CreateLatencyInfoSwapPromiseMonitor(ui::LatencyInfo* latency);
// Returns a new instance of `EventsMetricsManager::ScopedMonitor` to monitor
// the scope of handling an event. If `done_callback` is not a null callback,
@@ -364,19 +378,18 @@ class CC_EXPORT InputHandler {
// it.
virtual std::unique_ptr<EventsMetricsManager::ScopedMonitor>
GetScopedEventMetricsMonitor(
- EventsMetricsManager::ScopedMonitor::DoneCallback done_callback) = 0;
+ EventsMetricsManager::ScopedMonitor::DoneCallback done_callback);
- virtual ScrollElasticityHelper* CreateScrollElasticityHelper() = 0;
- virtual void DestroyScrollElasticityHelper() = 0;
+ virtual ScrollElasticityHelper* CreateScrollElasticityHelper();
+ virtual void DestroyScrollElasticityHelper();
// Called by the single-threaded UI Compositor to get or set the scroll offset
// on the impl side. Returns false if |element_id| isn't in the active tree.
virtual bool GetScrollOffsetForLayer(ElementId element_id,
- gfx::PointF* offset) = 0;
- virtual bool ScrollLayerTo(ElementId element_id,
- const gfx::PointF& offset) = 0;
+ gfx::PointF* offset);
+ virtual bool ScrollLayerTo(ElementId element_id, const gfx::PointF& offset);
- virtual bool ScrollingShouldSwitchtoMainThread() = 0;
+ virtual bool ScrollingShouldSwitchtoMainThread();
// Sets the initial and target offset for scroll snapping for the currently
// scrolling node and the given natural displacement. Also sets the target
@@ -387,27 +400,379 @@ class CC_EXPORT InputHandler {
virtual bool GetSnapFlingInfoAndSetAnimatingSnapTarget(
const gfx::Vector2dF& natural_displacement_in_viewport,
gfx::PointF* initial_offset,
- gfx::PointF* target_offset) = 0;
+ gfx::PointF* target_offset);
// |did_finish| is true if the animation reached its target position (i.e.
// it wasn't aborted).
- virtual void ScrollEndForSnapFling(bool did_finish) = 0;
+ virtual void ScrollEndForSnapFling(bool did_finish);
// Notifies when any input event is received, irrespective of whether it is
// being handled by the InputHandler or not.
- virtual void NotifyInputEvent() = 0;
+ virtual void NotifyInputEvent();
// Returns true if ScrollbarController is in the middle of a scroll operation.
- virtual bool ScrollbarScrollIsActive() = 0;
+ virtual bool ScrollbarScrollIsActive();
// Defers posting BeginMainFrame tasks. This is used during the main thread
// hit test for a GestureScrollBegin, to avoid posting a frame before the
// compositor thread has had a chance to update the scroll offset.
- virtual void SetDeferBeginMainFrame(bool defer_begin_main_frame) const = 0;
-
- protected:
- virtual ~InputHandler() = default;
- InputHandler() = default;
+ virtual void SetDeferBeginMainFrame(bool defer_begin_main_frame) const;
+
+ bool CanConsumeDelta(const ScrollState& scroll_state,
+ const ScrollNode& scroll_node);
+ // Returns the amount of delta that can be applied to scroll_node, taking
+ // page scale into account.
+ gfx::Vector2dF ComputeScrollDelta(const ScrollNode& scroll_node,
+ const gfx::Vector2dF& delta);
+
+ gfx::Vector2dF ScrollSingleNode(const ScrollNode& scroll_node,
+ const gfx::Vector2dF& delta,
+ const gfx::Point& viewport_point,
+ bool is_direct_manipulation);
+
+ float LineStep() const;
+
+ // Resolves a delta in the given granularity for the |scroll_node| into
+ // physical pixels to scroll.
+ gfx::Vector2dF ResolveScrollGranularityToPixels(
+ const ScrollNode& scroll_node,
+ const gfx::Vector2dF& scroll_delta,
+ ui::ScrollGranularity granularity);
+
+ // Used to set the pinch gesture active state when the pinch gesture is
+ // handled on another layer tree. In a page with OOPIFs, only the main
+ // frame's layer tree directly handles pinch events. But layer trees for
+ // sub-frames need to know when pinch gestures are active so they can
+ // throttle the re-rastering. This function allows setting this flag on
+ // OOPIF layer trees using information sent (initially) from the main-frame.
+ void set_external_pinch_gesture_active(bool external_pinch_gesture_active) {
+ external_pinch_gesture_active_ = external_pinch_gesture_active;
+ // Only one of the flags should ever be true at any given time.
+ DCHECK(!pinch_gesture_active_ || !external_pinch_gesture_active_);
+ }
+
+ bool pinch_gesture_active() const {
+ return pinch_gesture_active_ || external_pinch_gesture_active_;
+ }
+
+ void set_force_smooth_wheel_scrolling_for_testing(bool enabled) {
+ force_smooth_wheel_scrolling_for_testing_ = enabled;
+ }
+
+ gfx::Vector2dF accumulated_root_overscroll_for_testing() const {
+ return accumulated_root_overscroll_;
+ }
+
+ bool animating_for_snap_for_testing() const { return IsAnimatingForSnap(); }
+
+ // =========== InputDelegateForCompositor Interface - This section implements
+ // the interface that LayerTreeHostImpl uses to communicate with the input
+ // system.
+ void ProcessCommitDeltas(CompositorCommitData* commit_data) override;
+ void TickAnimations(base::TimeTicks monotonic_time) override;
+ void WillShutdown() override;
+ void WillDraw() override;
+ void WillBeginImplFrame(const viz::BeginFrameArgs& args) override;
+ void DidCommit() override;
+ void DidActivatePendingTree() override;
+ void RootLayerStateMayHaveChanged() override;
+ void DidRegisterScrollbar(ElementId scroll_element_id,
+ ScrollbarOrientation orientation) override;
+ void DidUnregisterScrollbar(ElementId scroll_element_id,
+ ScrollbarOrientation orientation) override;
+ void ScrollOffsetAnimationFinished() override;
+ void SetPrefersReducedMotion(bool prefers_reduced_motion) override;
+ bool IsCurrentlyScrolling() const override;
+ ActivelyScrollingType GetActivelyScrollingType() const override;
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(ScrollUnifiedLayerTreeHostImplTest,
+ AbortAnimatedScrollBeforeStartingAutoscroll);
+ FRIEND_TEST_ALL_PREFIXES(ScrollUnifiedLayerTreeHostImplTest,
+ AnimatedScrollYielding);
+ FRIEND_TEST_ALL_PREFIXES(ScrollUnifiedLayerTreeHostImplTest,
+ AutoscrollOnDeletedScrollbar);
+ FRIEND_TEST_ALL_PREFIXES(ScrollUnifiedLayerTreeHostImplTest,
+ ThumbDragAfterJumpClick);
+ FRIEND_TEST_ALL_PREFIXES(ScrollUnifiedLayerTreeHostImplTest,
+ ScrollOnLargeThumb);
+ FRIEND_TEST_ALL_PREFIXES(LayerTreeHostImplTest, AutoscrollTaskAbort);
+
+ // This method gets the scroll offset for a regular scroller, or the combined
+ // visual and layout offsets of the viewport.
+ gfx::PointF GetVisualScrollOffset(const ScrollNode& scroll_node) const;
+ bool IsScrolledBy(LayerImpl* child, ScrollNode* ancestor);
+ bool IsAnimatingForSnap() const;
+
+ ScrollNode* CurrentlyScrollingNode();
+ const ScrollNode* CurrentlyScrollingNode() const;
+ void ClearCurrentlyScrollingNode();
+ ScrollTree& GetScrollTree();
+ ScrollTree& GetScrollTree() const;
+ Viewport& GetViewport() const;
+
+ ScrollNode* InnerViewportScrollNode() const;
+ ScrollNode* OuterViewportScrollNode() const;
+
+ void SetNeedsCommit();
+ LayerTreeImpl& ActiveTree();
+ LayerTreeImpl& ActiveTree() const;
+
+ bool IsMainThreadScrolling(const InputHandler::ScrollStatus& status,
+ const ScrollNode* scroll_node) const;
+
+ bool IsTouchDraggingScrollbar(
+ LayerImpl* first_scrolling_layer_or_drawn_scrollbar,
+ ui::ScrollInputType type);
+
+ void UpdateRootLayerStateForSynchronousInputHandler();
+
+ // Called during ScrollBegin once a scroller was successfully latched to
+ // (i.e. it can and will consume scroll delta on the compositor thread). The
+ // latched scroller is now available in CurrentlyScrollingNode().
+ // TODO(bokan): There's some debate about the name of this method. We should
+ // get consensus on terminology to use and apply it consistently.
+ // https://crrev.com/c/1981336/9/cc/trees/layer_tree_host_impl.cc#4520
+ void DidLatchToScroller(const ScrollState& scroll_state,
+ ui::ScrollInputType type);
+
+ // This function keeps track of sources of scrolls that are handled in the
+ // compositor side. The information gets shared by the main thread as part of
+ // the begin_main_frame_state. Finally Use counters are updated in the main
+ // thread side to keep track of the frequency of scrolling with different
+ // sources per page load. TODO(crbug.com/691886): Use GRC API to plumb the
+ // scroll source info for Use Counters.
+ void UpdateScrollSourceInfo(const ScrollState& scroll_state,
+ ui::ScrollInputType type);
+
+ // Applies the scroll_state to the currently latched scroller. See comment in
+ // InputHandler::ScrollUpdate declaration for the meaning of |delayed_by|.
+ void ScrollLatchedScroller(ScrollState* scroll_state,
+ base::TimeDelta delayed_by);
+
+ // Determines whether the given scroll node can scroll on the compositor
+ // thread or if there are any reasons it must be scrolled on the main thread
+ // or not at all. Note: in general, this is not sufficient to determine if a
+ // scroll can occur on the compositor thread. If hit testing to a scroll
+ // node, the caller must also check whether the hit point intersects a
+ // non-fast-scrolling-region of any ancestor scrolling layers. Can be removed
+ // after scroll unification https://crbug.com/476553.
+ InputHandler::ScrollStatus TryScroll(const ScrollTree& scroll_tree,
+ ScrollNode* scroll_node) const;
+
+ enum class SnapReason { kGestureScrollEnd, kScrollOffsetAnimationFinished };
+
+ // Creates an animation curve and returns true if we need to update the
+ // scroll position to a snap point. Otherwise returns false.
+ bool SnapAtScrollEnd(SnapReason reason);
+
+ // |layer| is returned from a regular hit test, and
+ // |first_scrolling_layer_or_drawn_scrollbar| is returned from a hit test
+ // performed only on scrollers and scrollbars. Initial scroll hit testing can
+ // be unreliable if the latter is not the direct scroll ancestor of the
+ // former. In this case, we will fall back to main thread scrolling because
+ // the compositor thread doesn't know which layer to scroll. This happens when
+ // a layer covers a scroller that doesn't scroll the former, or a scroller is
+ // masked by a mask layer for mask image, clip-path, rounded border, etc.
+ //
+ // Note, position: fixed layers use the inner viewport as their ScrollNode
+ // (since they don't scroll with the outer viewport), however, scrolls from
+ // the fixed layer still chain to the outer viewport. It's also possible for a
+ // node to have the inner viewport as its ancestor without going through the
+ // outer viewport; however, it may still scroll using the viewport(). Hence,
+ // this method must use the same scroll chaining logic we use in ApplyScroll.
+ bool IsInitialScrollHitTestReliable(
+ const LayerImpl* layer,
+ const LayerImpl* first_scrolling_layer_or_drawn_scrollbar) const;
+
+ // Similar to above but includes complicated logic to determine whether the
+ // ScrollNode is able to be scrolled on the compositor or requires main
+ // thread scrolling. If main thread scrolling is required
+ // |scroll_on_main_thread| is set to true and the reason is given in
+ // |main_thread_scrolling_reason| to on of the enum values in
+ // main_thread_scrolling_reason.h. Can be removed after scroll unification
+ // https://crbug.com/476553.
+ ScrollNode* FindScrollNodeForCompositedScrolling(
+ const gfx::PointF& device_viewport_point,
+ LayerImpl* layer_hit_by_point,
+ bool* scroll_on_main_thread,
+ uint32_t* main_thread_scrolling_reason);
+
+ // Return all ScrollNode indices that have an associated layer with a non-fast
+ // region that intersects the point.
+ base::flat_set<int> NonFastScrollableNodes(
+ const gfx::PointF& device_viewport_point) const;
+
+ // Returns the ScrollNode we should use to scroll, accounting for viewport
+ // scroll chaining rules.
+ ScrollNode* GetNodeToScroll(ScrollNode* node) const;
+
+ // Given a starting node (determined by hit-test), walks up the scroll tree
+ // looking for the first node that can consume scroll from the given
+ // scroll_state and returns the first such node. If none is found, or if
+ // starting_node is nullptr, returns nullptr;
+ ScrollNode* FindNodeToLatch(ScrollState* scroll_state,
+ ScrollNode* starting_node,
+ ui::ScrollInputType type);
+
+ bool CanPropagate(ScrollNode* scroll_node, float x, float y);
+
+ // Performs a hit test to determine the ScrollNode to use when scrolling at
+ // |viewport_point|. If no layer is hit, this falls back to the inner
+ // viewport scroll node. Returns:
+ // - If |hit_test_sucessful| is false, hit testing has failed and the
+ // compositor cannot determine the correct scroll node (e.g. see comments in
+ // IsInitialScrollHitTestReliable). |scroll_node| is always nullptr in this
+ // case.
+ // - If |hit_test_successful| is true, returns the ScrollNode to use in
+ // |scroll_node|. This can be nullptr if no layer was hit and there are no
+ // viewport nodes (e.g. OOPIF, UI compositor).
+ struct ScrollHitTestResult {
+ ScrollNode* scroll_node;
+ bool hit_test_successful;
+ };
+ ScrollHitTestResult HitTestScrollNode(
+ const gfx::PointF& device_viewport_point) const;
+
+ bool ShouldAnimateScroll(const ScrollState& scroll_state) const;
+
+ bool ScrollAnimationUpdateTarget(const ScrollNode& scroll_node,
+ const gfx::Vector2dF& scroll_delta,
+ base::TimeDelta delayed_by);
+
+ // Transforms viewport start point and scroll delta to local start point and
+ // local delta, respectively. If the transformation of either the start or end
+ // point of a scroll is clipped, the function returns false.
+ bool CalculateLocalScrollDeltaAndStartPoint(
+ const ScrollNode& scroll_node,
+ const gfx::PointF& viewport_point,
+ const gfx::Vector2dF& viewport_delta,
+ gfx::Vector2dF* out_local_scroll_delta,
+ gfx::PointF* out_local_start_point = nullptr);
+ gfx::Vector2dF ScrollNodeWithViewportSpaceDelta(
+ const ScrollNode& scroll_node,
+ const gfx::PointF& viewport_point,
+ const gfx::Vector2dF& viewport_delta);
+ gfx::Vector2dF ScrollNodeWithLocalDelta(
+ const ScrollNode& scroll_node,
+ const gfx::Vector2dF& local_delta) const;
+ // This helper returns an adjusted version of |delta| where the scroll delta
+ // is cleared in any axis in which user scrolling is disabled (e.g. by
+ // |overflow-x: hidden|).
+ gfx::Vector2dF UserScrollableDelta(const ScrollNode& node,
+ const gfx::Vector2dF& delta) const;
+
+ void AdjustScrollDeltaForScrollbarSnap(ScrollState* scroll_state);
+
+ FrameSequenceTrackerType GetTrackerTypeForScroll(
+ ui::ScrollInputType input_type) const;
+
+ ScrollbarController* scrollbar_controller_for_testing() const {
+ return scrollbar_controller_.get();
+ }
+
+ // The input handler is owned by the delegate so their lifetimes are tied
+ // together.
+ CompositorDelegateForInput& compositor_delegate_;
+
+ raw_ptr<InputHandlerClient> input_handler_client_ = nullptr;
+
+ // An object to implement the ScrollElasticityHelper interface and
+ // hold all state related to elasticity. May be nullptr if never requested.
+ std::unique_ptr<ScrollElasticityHelper> scroll_elasticity_helper_;
+
+ // Manages composited scrollbar hit testing.
+ std::unique_ptr<ScrollbarController> scrollbar_controller_;
+
+ // Overscroll delta accumulated on the viewport throughout a scroll gesture;
+ // reset when the gesture ends.
+ gfx::Vector2dF accumulated_root_overscroll_;
+
+ // Unconsumed scroll delta sent to the main thread for firing overscroll DOM
+ // events. Resets after each commit.
+ gfx::Vector2dF overscroll_delta_for_main_thread_;
+
+ // The source device type that started the scroll gesture. Only set between a
+ // ScrollBegin and ScrollEnd.
+ absl::optional<ui::ScrollInputType> latched_scroll_type_;
+
+ // Tracks the last scroll update/begin state received. Used to infer the most
+ // recent scroll type and direction.
+ absl::optional<ScrollState> last_scroll_begin_state_;
+ absl::optional<ScrollState> last_scroll_update_state_;
+
+ // If a scroll snap is being animated, then the value of this will be the
+ // element id(s) of the target(s). Otherwise, the ids will be invalid.
+ // At the end of a scroll animation, the target should be set as the scroll
+ // node's snap target.
+ TargetSnapAreaElementIds scroll_animating_snap_target_ids_;
+
+ // A set of elements that scroll-snapped to a new target since the last
+ // begin main frame. The snap target ids of these elements will be sent to
+ // the main thread in the next begin main frame.
+ base::flat_map<ElementId, TargetSnapAreaElementIds> updated_snapped_elements_;
+
+ ElementId scroll_element_id_mouse_currently_over_;
+ ElementId scroll_element_id_mouse_currently_captured_;
+
+ // Set in ScrollBegin and outlives the currently scrolling node so it can be
+ // used to send the scrollend and overscroll DOM events from the main thread
+ // when scrolling occurs on the compositor thread. This value is cleared at
+ // the first commit after a GSE.
+ ElementId last_latched_scroller_;
+
+ // Scroll animation can finish either before or after GSE arrival.
+ // deferred_scroll_end_ is set when the GSE has arrvied before scroll
+ // animation completion. ScrollEnd will get called once the animation is
+ // over.
+ bool deferred_scroll_end_ = false;
+
+ // Set to true when a scroll gesture being handled on the compositor has
+ // ended. i.e. When a GSE has arrived and any ongoing scroll animation has
+ // ended.
+ bool scroll_gesture_did_end_ = false;
+
+ // True iff some of the delta has been consumed for the current scroll
+ // sequence on the specific axis.
+ bool did_scroll_x_for_scroll_gesture_ = false;
+ bool did_scroll_y_for_scroll_gesture_ = false;
+
+ // did_scroll_x/y_for_scroll_gesture_ is true when contents consume the delta,
+ // but delta_consumed_for_scroll_gesture_ can be true when only browser
+ // controls consume all the delta.
+ bool delta_consumed_for_scroll_gesture_ = false;
+
+ // TODO(bokan): Mac doesn't yet have smooth scrolling for wheel; however, to
+ // allow consistency in tests we use this bit to override that decision.
+ // https://crbug.com/574283.
+ bool force_smooth_wheel_scrolling_for_testing_ = false;
+
+ // This value is used to allow the compositor to throttle re-rastering during
+ // pinch gestures, when the page scale factor may be changing frequently. It
+ // is set in one of two ways:
+ // i) In a layer tree serving the root of the frame/compositor tree, it is
+ // directly set during processing of GesturePinch events on the impl thread
+ // (only the root layer tree has access to these).
+ // ii) In a layer tree serving a sub-frame in the frame/compositor tree, it
+ // is set from the main thread during the commit process, using information
+ // sent from the root layer tree via IPC messaging.
+ bool pinch_gesture_active_ = false;
+ bool external_pinch_gesture_active_ = false;
+ bool pinch_gesture_end_should_clear_scrolling_node_ = false;
+
+ // These are used to transfer usage of different types of scrolling to the
+ // main thread.
+ bool has_pinch_zoomed_ = false;
+ bool has_scrolled_by_wheel_ = false;
+ bool has_scrolled_by_touch_ = false;
+ bool has_scrolled_by_precisiontouchpad_ = false;
+ bool has_scrolled_by_scrollbar_ = false;
+
+ bool prefers_reduced_motion_ = false;
+
+ // Must be the last member to ensure this is destroyed first in the
+ // destruction order and invalidates all weak pointers.
+ base::WeakPtrFactory<InputHandler> weak_factory_{this};
};
} // namespace cc
diff --git a/chromium/cc/input/main_thread_scrolling_reason.cc b/chromium/cc/input/main_thread_scrolling_reason.cc
index eacc3ec2838..483e1785841 100644
--- a/chromium/cc/input/main_thread_scrolling_reason.cc
+++ b/chromium/cc/input/main_thread_scrolling_reason.cc
@@ -60,4 +60,16 @@ void MainThreadScrollingReason::AddToTracedValue(
traced_value.EndArray();
}
+int MainThreadScrollingReason::BucketIndexForTesting(uint32_t reason) {
+ // These two values are already bucket indices.
+ DCHECK_NE(reason, kNotScrollingOnMain);
+ DCHECK_NE(reason, kScrollingOnMainForAnyReason);
+
+ int index = 0;
+ while (reason >>= 1)
+ ++index;
+ DCHECK_NE(index, 0);
+ return index;
+}
+
} // namespace cc
diff --git a/chromium/cc/input/main_thread_scrolling_reason.h b/chromium/cc/input/main_thread_scrolling_reason.h
index cc411a5ebae..2c77a6f5633 100644
--- a/chromium/cc/input/main_thread_scrolling_reason.h
+++ b/chromium/cc/input/main_thread_scrolling_reason.h
@@ -21,29 +21,36 @@ namespace cc {
// tools/metrics/histograms/enums.xml
// When adding a new MainThreadScrollingReason, make sure the corresponding
// [MainThread/Compositor]CanSetScrollReasons function is also updated.
+//
+// More info at: http://bit.ly/mtsr-details
+//
struct CC_EXPORT MainThreadScrollingReason {
enum : uint32_t {
kNotScrollingOnMain = 0,
+ // This is used only to report the histogram of main thread scrolling for
+ // any reason below. It's a histogram bucket index instead of a bit.
+ kScrollingOnMainForAnyReason = 1,
+
// This enum simultaneously defines actual bitmask values and indices into
- // the bitmask, but kNotScrollingMain is recorded in the histograms as
- // value 0, so the 0th bit should never be used.
+ // the bitmask (which are the numbers after "1 << " below, used as the
+ // histogram bucket indices), but value 0 and 1 are used as the histogram
+ // bucket indices for kNotScrollingMain and kScrollingOnMainForAnyReason,
+ // respectively, so the 0th bit and the 1st bit should never be used.
// See also blink::RecordScrollReasonsMetric().
// Non-transient scrolling reasons. These are set on the ScrollNode.
- kHasBackgroundAttachmentFixedObjects = 1 << 1,
+ kHasBackgroundAttachmentFixedObjects = 1 << 2,
kThreadedScrollingDisabled = 1 << 3,
- kPopupNoThreadedInput = 1 << 26,
+ kPopupNoThreadedInput = 1 << 4,
// Style-related scrolling on main reasons. Subpixel (LCD) text rendering
// requires blending glyphs with the background at a specific screen
// position; transparency and transforms break this.
// These are only reported by the main-thread scroll gesture event codepath.
// After scroll unification, we report kNoScrollingLayer instead.
- kNonCompositedReasonsFirst = 18,
- kNotOpaqueForTextAndLCDText = 1 << 19,
- kCantPaintScrollingBackgroundAndLCDText = 1 << 20,
- kNonCompositedReasonsLast = 23,
+ kNotOpaqueForTextAndLCDText = 1 << 5,
+ kCantPaintScrollingBackgroundAndLCDText = 1 << 6,
// Transient scrolling reasons. These are computed for each scroll gesture.
// When computed inside ScrollBegin, these prevent the InputHandler from
@@ -51,16 +58,17 @@ struct CC_EXPORT MainThreadScrollingReason {
// InputHandler is scrolling "on impl", but we report a transient main
// thread scrolling reason to UMA when we determine that some other aspect
// of handling the scroll has been (or will be) blocked on the main thread.
- kScrollbarScrolling = 1 << 4,
- kNonFastScrollableRegion = 1 << 6,
- kFailedHitTest = 1 << 8,
- kNoScrollingLayer = 1 << 9,
- kNotScrollable = 1 << 10,
+ kScrollbarScrolling = 1 << 7,
+ kNonFastScrollableRegion = 1 << 8,
+ kFailedHitTest = 1 << 9,
+ kNoScrollingLayer = 1 << 10,
+ kNotScrollable = 1 << 11,
kNonInvertibleTransform = 1 << 12,
- kWheelEventHandlerRegion = 1 << 24,
- kTouchEventHandlerRegion = 1 << 25,
+ kWheelEventHandlerRegion = 1 << 13,
+ kTouchEventHandlerRegion = 1 << 14,
- kMainThreadScrollingReasonLast = 26,
+ // For blink::RecordScrollReasonsMetric() to know the number of used bits.
+ kMainThreadScrollingReasonLast = 14,
};
static const uint32_t kNonCompositedReasons =
@@ -91,6 +99,8 @@ struct CC_EXPORT MainThreadScrollingReason {
return (reasons & kNonCompositedReasons) != 0;
}
+ static int BucketIndexForTesting(uint32_t reason);
+
static std::string AsText(uint32_t reasons);
static void AddToTracedValue(uint32_t reasons,
base::trace_event::TracedValue&);
diff --git a/chromium/cc/input/scroll_utils.cc b/chromium/cc/input/scroll_utils.cc
index c90c93a0db0..87e846217b9 100644
--- a/chromium/cc/input/scroll_utils.cc
+++ b/chromium/cc/input/scroll_utils.cc
@@ -34,4 +34,14 @@ gfx::Vector2dF ScrollUtils::ResolveScrollPercentageToPixels(
std::copysign(delta_y, sign_y));
}
+gfx::Vector2dF ScrollUtils::ResolvePixelScrollToPercentageForTesting(
+ const gfx::Vector2dF& delta,
+ const gfx::SizeF& scroller,
+ const gfx::SizeF& viewport) {
+ float delta_x = delta.x() / std::min(scroller.width(), viewport.width());
+ float delta_y = delta.y() / std::min(scroller.height(), viewport.height());
+
+ return gfx::Vector2dF(delta_x, delta_y);
+}
+
} // namespace cc
diff --git a/chromium/cc/input/scroll_utils.h b/chromium/cc/input/scroll_utils.h
index c73d5c42282..ecb76de1a25 100644
--- a/chromium/cc/input/scroll_utils.h
+++ b/chromium/cc/input/scroll_utils.h
@@ -31,6 +31,13 @@ class CC_EXPORT ScrollUtils {
const gfx::Vector2dF& scroll_delta,
const gfx::SizeF& scroller_size,
const gfx::SizeF& viewport_size);
+
+ // Transforms a pixel delta into a percentage. Used for when a test needs to
+ // work with percent based scrolling and non percent based scrolling.
+ static gfx::Vector2dF ResolvePixelScrollToPercentageForTesting(
+ const gfx::Vector2dF& pixel_scroll_delta,
+ const gfx::SizeF& scroller_size,
+ const gfx::SizeF& viewport_size);
};
} // namespace cc
diff --git a/chromium/cc/input/scrollbar_animation_controller.cc b/chromium/cc/input/scrollbar_animation_controller.cc
index a3eba61f9f8..41f19f63d13 100644
--- a/chromium/cc/input/scrollbar_animation_controller.cc
+++ b/chromium/cc/input/scrollbar_animation_controller.cc
@@ -380,16 +380,18 @@ void ScrollbarAnimationController::ApplyOpacityToScrollbars(float opacity) {
scrollbar->SetOverlayScrollbarLayerOpacityAnimated(effective_opacity);
}
- bool previouslyVisible = opacity_ > 0.0f;
- bool currentlyVisible = opacity > 0.0f;
+ bool previously_visible_ = opacity_ > 0.0f;
+ bool currently_visible = opacity > 0.0f;
if (opacity_ != opacity)
client_->SetNeedsRedrawForScrollbarAnimation();
opacity_ = opacity;
- if (previouslyVisible != currentlyVisible)
+ if (previously_visible_ != currently_visible) {
client_->DidChangeScrollbarVisibility();
+ visibility_changed_ = true;
+ }
}
} // namespace cc
diff --git a/chromium/cc/input/scrollbar_animation_controller.h b/chromium/cc/input/scrollbar_animation_controller.h
index ce4a3f92197..b3f429677aa 100644
--- a/chromium/cc/input/scrollbar_animation_controller.h
+++ b/chromium/cc/input/scrollbar_animation_controller.h
@@ -65,6 +65,8 @@ class CC_EXPORT ScrollbarAnimationController {
~ScrollbarAnimationController();
bool ScrollbarsHidden() const;
+ bool visibility_changed() const { return visibility_changed_; }
+ void ClearVisibilityChanged() { visibility_changed_ = false; }
bool Animate(base::TimeTicks now);
@@ -94,7 +96,8 @@ class CC_EXPORT ScrollbarAnimationController {
ScrollbarSet Scrollbars() const;
- static constexpr float kMouseMoveDistanceToTriggerFadeIn = 30.0f;
+ SingleScrollbarAnimationControllerThinning& GetScrollbarAnimationController(
+ ScrollbarOrientation) const;
private:
// Describes whether the current animation should FadeIn or FadeOut.
@@ -113,9 +116,6 @@ class CC_EXPORT ScrollbarAnimationController {
base::TimeDelta thinning_duration,
float initial_opacity);
- SingleScrollbarAnimationControllerThinning& GetScrollbarAnimationController(
- ScrollbarOrientation) const;
-
// Any scrollbar state update would show scrollbar hen post the delay fade out
// if needed.
void UpdateScrollbarState();
@@ -165,6 +165,8 @@ class CC_EXPORT ScrollbarAnimationController {
bool tickmarks_showing_;
+ bool visibility_changed_ = false;
+
std::unique_ptr<SingleScrollbarAnimationControllerThinning>
vertical_controller_;
std::unique_ptr<SingleScrollbarAnimationControllerThinning>
diff --git a/chromium/cc/input/scrollbar_animation_controller_unittest.cc b/chromium/cc/input/scrollbar_animation_controller_unittest.cc
index 6069fc44543..d3e5389e5f5 100644
--- a/chromium/cc/input/scrollbar_animation_controller_unittest.cc
+++ b/chromium/cc/input/scrollbar_animation_controller_unittest.cc
@@ -24,18 +24,13 @@ namespace {
const float kIdleThicknessScale =
SingleScrollbarAnimationControllerThinning::kIdleThicknessScale;
-const float kMouseMoveDistanceToTriggerFadeIn =
- ScrollbarAnimationController::kMouseMoveDistanceToTriggerFadeIn;
-const float kMouseMoveDistanceToTriggerExpand =
- SingleScrollbarAnimationControllerThinning::
- kMouseMoveDistanceToTriggerExpand;
const int kThumbThickness = 10;
class MockScrollbarAnimationControllerClient
: public ScrollbarAnimationControllerClient {
public:
- explicit MockScrollbarAnimationControllerClient(LayerTreeHostImpl* host_impl,
- bool is_fluent)
+ MockScrollbarAnimationControllerClient(LayerTreeHostImpl* host_impl,
+ bool is_fluent)
: host_impl_(host_impl), is_fluent_(is_fluent) {}
~MockScrollbarAnimationControllerClient() override = default;
@@ -125,6 +120,14 @@ class ScrollbarAnimationControllerAuraOverlayTest
kThinningDuration, 0.0f);
v_scrollbar_layer_->SetCurrentPos(0);
h_scrollbar_layer_->SetCurrentPos(0);
+ mouse_move_distance_to_trigger_fade_in_ =
+ scrollbar_controller_
+ ->GetScrollbarAnimationController(ScrollbarOrientation::VERTICAL)
+ .MouseMoveDistanceToTriggerFadeIn();
+ mouse_move_distance_to_trigger_expand_ =
+ scrollbar_controller_
+ ->GetScrollbarAnimationController(ScrollbarOrientation::VERTICAL)
+ .MouseMoveDistanceToTriggerExpand();
}
// Return a point with given offset from the top-left of vertical scrollbar.
@@ -149,6 +152,8 @@ class ScrollbarAnimationControllerAuraOverlayTest
return p;
}
+ float mouse_move_distance_to_trigger_fade_in_;
+ float mouse_move_distance_to_trigger_expand_;
std::unique_ptr<ScrollbarAnimationController> scrollbar_controller_;
raw_ptr<LayerImpl> clip_layer_;
raw_ptr<LayerImpl> scroll_layer_;
@@ -489,8 +494,8 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
// Then move mouse away, The fade out animation should have been cleared or
// cancelled.
- scrollbar_controller_->DidMouseMove(
- NearVerticalScrollbarBegin(-kMouseMoveDistanceToTriggerExpand, 0));
+ scrollbar_controller_->DidMouseMove(NearVerticalScrollbarBegin(
+ -mouse_move_distance_to_trigger_expand_ - 1, 0));
EXPECT_TRUE(client_.start_fade().is_null() ||
client_.start_fade().IsCancelled());
@@ -559,8 +564,8 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, FadeAfterReleasedFar) {
client_.start_fade().IsCancelled());
// Now move the mouse away from the scrollbar and release it.
- scrollbar_controller_->DidMouseMove(
- NearVerticalScrollbarBegin(-kMouseMoveDistanceToTriggerFadeIn, 0));
+ scrollbar_controller_->DidMouseMove(NearVerticalScrollbarBegin(
+ -mouse_move_distance_to_trigger_fade_in_ - 1, 0));
scrollbar_controller_->DidMouseUp();
scrollbar_controller_->Animate(time);
@@ -886,8 +891,8 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, MouseNearEach) {
h_scrollbar_layer_->thumb_thickness_scale_factor());
// Now move away from bar.
- scrollbar_controller_->DidMouseMove(
- NearVerticalScrollbarBegin(-kMouseMoveDistanceToTriggerExpand, 0));
+ scrollbar_controller_->DidMouseMove(NearVerticalScrollbarBegin(
+ -mouse_move_distance_to_trigger_expand_ - 1, 0));
scrollbar_controller_->Animate(time);
time += kThinningDuration;
scrollbar_controller_->Animate(time);
@@ -925,8 +930,8 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, MouseNearEach) {
EXPECT_FLOAT_EQ(1, h_scrollbar_layer_->thumb_thickness_scale_factor());
// Now move away from bar.
- scrollbar_controller_->DidMouseMove(
- NearHorizontalScrollbarBegin(0, -kMouseMoveDistanceToTriggerExpand));
+ scrollbar_controller_->DidMouseMove(NearHorizontalScrollbarBegin(
+ 0, -mouse_move_distance_to_trigger_expand_ - 1));
scrollbar_controller_->Animate(time);
time += kThinningDuration;
scrollbar_controller_->Animate(time);
@@ -1062,7 +1067,7 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, BasicMouseHoverFadeIn) {
// Move mouse over the fade in region of scrollbar.
scrollbar_controller_->DidMouseMove(
- NearVerticalScrollbarBegin(-kMouseMoveDistanceToTriggerFadeIn + 1, 0));
+ NearVerticalScrollbarBegin(-mouse_move_distance_to_trigger_fade_in_, 0));
// An fade in animation should have been enqueued.
EXPECT_FALSE(client_.start_fade().is_null());
@@ -1095,7 +1100,7 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
// Move mouse over the fade in region of scrollbar.
scrollbar_controller_->DidMouseMove(
- NearVerticalScrollbarBegin(-kMouseMoveDistanceToTriggerFadeIn + 1, 0));
+ NearVerticalScrollbarBegin(-mouse_move_distance_to_trigger_fade_in_, 0));
// An fade in animation should have been enqueued.
EXPECT_FALSE(client_.start_fade().is_null());
@@ -1105,8 +1110,8 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
client_.start_fade().Reset();
// Move mouse still hover the fade in region of scrollbar should not
// post a new fade in.
- scrollbar_controller_->DidMouseMove(
- NearVerticalScrollbarBegin(-kMouseMoveDistanceToTriggerFadeIn + 2, 0));
+ scrollbar_controller_->DidMouseMove(NearVerticalScrollbarBegin(
+ -mouse_move_distance_to_trigger_fade_in_ + 2, 0));
EXPECT_TRUE(client_.start_fade().is_null());
}
@@ -1120,7 +1125,7 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
// Move mouse over the fade in region of scrollbar.
scrollbar_controller_->DidMouseMove(
- NearVerticalScrollbarBegin(-kMouseMoveDistanceToTriggerFadeIn + 1, 0));
+ NearVerticalScrollbarBegin(-mouse_move_distance_to_trigger_fade_in_, 0));
// An fade in animation should have been enqueued.
EXPECT_FALSE(client_.start_fade().is_null());
@@ -1128,8 +1133,8 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
EXPECT_EQ(kFadeDelay, client_.delay());
// Move mouse far away,delay fade in should be canceled.
- scrollbar_controller_->DidMouseMove(
- NearVerticalScrollbarBegin(-kMouseMoveDistanceToTriggerFadeIn, 0));
+ scrollbar_controller_->DidMouseMove(NearVerticalScrollbarBegin(
+ -mouse_move_distance_to_trigger_fade_in_ - 1, 0));
EXPECT_TRUE(client_.start_fade().is_null() ||
client_.start_fade().IsCancelled());
@@ -1144,7 +1149,7 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
// Move mouse over the fade in region of scrollbar.
scrollbar_controller_->DidMouseMove(
- NearVerticalScrollbarBegin(-kMouseMoveDistanceToTriggerFadeIn + 1, 0));
+ NearVerticalScrollbarBegin(-mouse_move_distance_to_trigger_fade_in_, 0));
// An fade in animation should have been enqueued.
EXPECT_FALSE(client_.start_fade().is_null());
@@ -1158,7 +1163,7 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
// Move mouse over the fade in region of scrollbar.
scrollbar_controller_->DidMouseMove(
- NearVerticalScrollbarBegin(-kMouseMoveDistanceToTriggerFadeIn + 1, 0));
+ NearVerticalScrollbarBegin(-mouse_move_distance_to_trigger_fade_in_, 0));
// An fade in animation should have been enqueued.
EXPECT_FALSE(client_.start_fade().is_null());
@@ -1185,7 +1190,7 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
// Move mouse over the fade in region of scrollbar.
scrollbar_controller_->DidMouseMove(
- NearVerticalScrollbarBegin(-kMouseMoveDistanceToTriggerFadeIn + 1, 0));
+ NearVerticalScrollbarBegin(-mouse_move_distance_to_trigger_fade_in_, 0));
// An fade in animation should have been enqueued.
EXPECT_FALSE(client_.start_fade().is_null());
@@ -1199,7 +1204,7 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
// Move mouse hover the fade in region of scrollbar with press.
scrollbar_controller_->DidMouseMove(
- NearVerticalScrollbarBegin(-kMouseMoveDistanceToTriggerFadeIn + 1, 0));
+ NearVerticalScrollbarBegin(-mouse_move_distance_to_trigger_fade_in_, 0));
// Should not have delay fade animation.
EXPECT_TRUE(client_.start_fade().is_null() ||
@@ -1233,7 +1238,7 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
// Move mouse over the fade in region of scrollbar.
scrollbar_controller_->DidMouseMove(
- NearVerticalScrollbarBegin(-kMouseMoveDistanceToTriggerFadeIn + 1, 0));
+ NearVerticalScrollbarBegin(-mouse_move_distance_to_trigger_fade_in_, 0));
// An fade in animation should have been enqueued.
EXPECT_FALSE(client_.start_fade().is_null());
@@ -1247,8 +1252,8 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
// Move mouse far from hover the fade in region of scrollbar with
// press.
- scrollbar_controller_->DidMouseMove(
- NearVerticalScrollbarBegin(-kMouseMoveDistanceToTriggerFadeIn, 0));
+ scrollbar_controller_->DidMouseMove(NearVerticalScrollbarBegin(
+ -mouse_move_distance_to_trigger_fade_in_ - 1, 0));
// Should not have delay fade animation.
EXPECT_TRUE(client_.start_fade().is_null() ||
diff --git a/chromium/cc/input/single_scrollbar_animation_controller_thinning.cc b/chromium/cc/input/single_scrollbar_animation_controller_thinning.cc
index 5288a8c5d3b..7a4d2489707 100644
--- a/chromium/cc/input/single_scrollbar_animation_controller_thinning.cc
+++ b/chromium/cc/input/single_scrollbar_animation_controller_thinning.cc
@@ -143,7 +143,10 @@ void SingleScrollbarAnimationControllerThinning::DidMouseUp() {
captured_ = false;
StopAnimation();
- if (!mouse_is_near_scrollbar_thumb_) {
+ const bool thickness_should_decrease = client_->IsFluentScrollbar()
+ ? !mouse_is_near_scrollbar_track_
+ : !mouse_is_near_scrollbar_thumb_;
+ if (thickness_should_decrease) {
thickness_change_ = AnimationChange::DECREASE;
StartAnimation();
} else {
@@ -152,7 +155,11 @@ void SingleScrollbarAnimationControllerThinning::DidMouseUp() {
}
void SingleScrollbarAnimationControllerThinning::DidMouseLeave() {
- if (!mouse_is_over_scrollbar_thumb_ && !mouse_is_near_scrollbar_thumb_)
+ if (client_->IsFluentScrollbar() && !mouse_is_near_scrollbar_track_)
+ return;
+
+ if (!client_->IsFluentScrollbar() && !mouse_is_over_scrollbar_thumb_ &&
+ !mouse_is_near_scrollbar_thumb_)
return;
mouse_is_over_scrollbar_thumb_ = false;
@@ -173,35 +180,50 @@ void SingleScrollbarAnimationControllerThinning::DidMouseMove(
if (!scrollbar)
return;
- float distance_to_scrollbar_track =
+ const float distance_to_scrollbar_track =
DistanceToScrollbarPart(device_viewport_point, *scrollbar,
ScrollbarPart::TRACK_BUTTONS_TICKMARKS);
- float distance_to_scrollbar_thumb = DistanceToScrollbarPart(
+ const float distance_to_scrollbar_thumb = DistanceToScrollbarPart(
device_viewport_point, *scrollbar, ScrollbarPart::THUMB);
- mouse_is_near_scrollbar_track_ =
- distance_to_scrollbar_track <
- ScrollbarAnimationController::kMouseMoveDistanceToTriggerFadeIn;
-
- bool mouse_is_over_scrollbar_thumb = distance_to_scrollbar_thumb == 0.0f;
- bool mouse_is_near_scrollbar_thumb =
- distance_to_scrollbar_thumb < kMouseMoveDistanceToTriggerExpand;
-
- if (!captured_ &&
- mouse_is_near_scrollbar_thumb != mouse_is_near_scrollbar_thumb_) {
- thickness_change_ = mouse_is_near_scrollbar_thumb
- ? AnimationChange::INCREASE
- : AnimationChange::DECREASE;
+ const bool mouse_is_near_scrollbar_track =
+ distance_to_scrollbar_track <= MouseMoveDistanceToTriggerFadeIn();
+
+ const bool mouse_is_over_scrollbar_thumb =
+ distance_to_scrollbar_thumb == 0.0f;
+ const bool mouse_is_near_scrollbar_thumb =
+ distance_to_scrollbar_thumb <= MouseMoveDistanceToTriggerExpand();
+ const bool thickness_should_change =
+ client_->IsFluentScrollbar()
+ ? (mouse_is_near_scrollbar_track_ != mouse_is_near_scrollbar_track)
+ : (mouse_is_near_scrollbar_thumb_ != mouse_is_near_scrollbar_thumb);
+
+ if (!captured_ && thickness_should_change) {
+ const bool thickness_should_increase = client_->IsFluentScrollbar()
+ ? mouse_is_near_scrollbar_track
+ : mouse_is_near_scrollbar_thumb;
+ thickness_change_ = thickness_should_increase ? AnimationChange::INCREASE
+ : AnimationChange::DECREASE;
StartAnimation();
}
+
+ mouse_is_near_scrollbar_track_ = mouse_is_near_scrollbar_track;
mouse_is_near_scrollbar_thumb_ = mouse_is_near_scrollbar_thumb;
mouse_is_over_scrollbar_thumb_ = mouse_is_over_scrollbar_thumb;
}
+float SingleScrollbarAnimationControllerThinning::
+ ThumbThicknessScaleByMouseDistanceToScrollbar() const {
+ const bool mouse_is_near_scrollbar_part =
+ client_->IsFluentScrollbar() ? mouse_is_near_scrollbar_track_
+ : mouse_is_near_scrollbar_thumb_;
+ return mouse_is_near_scrollbar_part ? 1.f : kIdleThicknessScale;
+}
+
float SingleScrollbarAnimationControllerThinning::ThumbThicknessScaleAt(
- float progress) {
+ float progress) const {
if (thickness_change_ == AnimationChange::NONE)
- return mouse_is_near_scrollbar_thumb_ ? 1.f : kIdleThicknessScale;
+ return ThumbThicknessScaleByMouseDistanceToScrollbar();
float factor = thickness_change_ == AnimationChange::INCREASE
? progress
: (1.f - progress);
@@ -232,8 +254,7 @@ float SingleScrollbarAnimationControllerThinning::AdjustScale(
void SingleScrollbarAnimationControllerThinning::UpdateThumbThicknessScale() {
StopAnimation();
- ApplyThumbThicknessScale(
- mouse_is_near_scrollbar_thumb_ ? 1.f : kIdleThicknessScale);
+ ApplyThumbThicknessScale(ThumbThicknessScaleByMouseDistanceToScrollbar());
}
void SingleScrollbarAnimationControllerThinning::ApplyThumbThicknessScale(
@@ -251,4 +272,14 @@ void SingleScrollbarAnimationControllerThinning::ApplyThumbThicknessScale(
}
}
+float SingleScrollbarAnimationControllerThinning::
+ MouseMoveDistanceToTriggerExpand() {
+ return client_->IsFluentScrollbar() ? 0.0f : 25.0f;
+}
+
+float SingleScrollbarAnimationControllerThinning::
+ MouseMoveDistanceToTriggerFadeIn() {
+ return client_->IsFluentScrollbar() ? 0.0f : 30.0f;
+}
+
} // namespace cc
diff --git a/chromium/cc/input/single_scrollbar_animation_controller_thinning.h b/chromium/cc/input/single_scrollbar_animation_controller_thinning.h
index 44eef269f1a..4241de6ec47 100644
--- a/chromium/cc/input/single_scrollbar_animation_controller_thinning.h
+++ b/chromium/cc/input/single_scrollbar_animation_controller_thinning.h
@@ -23,7 +23,6 @@ class ScrollbarAnimationControllerClient;
class CC_EXPORT SingleScrollbarAnimationControllerThinning {
public:
static constexpr float kIdleThicknessScale = 0.4f;
- static constexpr float kMouseMoveDistanceToTriggerExpand = 25.f;
static std::unique_ptr<SingleScrollbarAnimationControllerThinning> Create(
ElementId scroll_element_id,
@@ -61,6 +60,9 @@ class CC_EXPORT SingleScrollbarAnimationControllerThinning {
void DidMouseLeave();
void DidMouseMove(const gfx::PointF& device_viewport_point);
+ float MouseMoveDistanceToTriggerExpand();
+ float MouseMoveDistanceToTriggerFadeIn();
+
private:
SingleScrollbarAnimationControllerThinning(
ElementId scroll_element_id,
@@ -75,7 +77,8 @@ class CC_EXPORT SingleScrollbarAnimationControllerThinning {
// Describes whether the current animation should INCREASE (thicken)
// a bar or DECREASE it (thin).
enum class AnimationChange { NONE, INCREASE, DECREASE };
- float ThumbThicknessScaleAt(float progress);
+ float ThumbThicknessScaleAt(float progress) const;
+ float ThumbThicknessScaleByMouseDistanceToScrollbar() const;
float AdjustScale(float new_value,
float current_value,
@@ -95,6 +98,8 @@ class CC_EXPORT SingleScrollbarAnimationControllerThinning {
bool captured_;
bool mouse_is_over_scrollbar_thumb_;
bool mouse_is_near_scrollbar_thumb_;
+ // For Fluent scrollbars the near distance to the track is 0 which is
+ // equivalent to the mouse being over the thumb/track.
bool mouse_is_near_scrollbar_track_;
// Are we narrowing or thickening the bars.
AnimationChange thickness_change_;
diff --git a/chromium/cc/input/single_scrollbar_animation_controller_thinning_unittest.cc b/chromium/cc/input/single_scrollbar_animation_controller_thinning_unittest.cc
index ff0221ea9e5..3ce3c9943fe 100644
--- a/chromium/cc/input/single_scrollbar_animation_controller_thinning_unittest.cc
+++ b/chromium/cc/input/single_scrollbar_animation_controller_thinning_unittest.cc
@@ -12,34 +12,29 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-using testing::AtLeast;
-using testing::Mock;
-using testing::NiceMock;
-using testing::_;
+using ::testing::_;
+using ::testing::Bool;
+using ::testing::Mock;
+using ::testing::NiceMock;
namespace cc {
namespace {
const float kIdleThicknessScale =
SingleScrollbarAnimationControllerThinning::kIdleThicknessScale;
-const float kMouseMoveDistanceToTriggerExpand =
- SingleScrollbarAnimationControllerThinning::
- kMouseMoveDistanceToTriggerExpand;
-const float kMouseMoveDistanceToTriggerFadeIn =
- ScrollbarAnimationController::kMouseMoveDistanceToTriggerFadeIn;
class MockSingleScrollbarAnimationControllerClient
: public ScrollbarAnimationControllerClient {
public:
- explicit MockSingleScrollbarAnimationControllerClient(
- LayerTreeHostImpl* host_impl)
- : host_impl_(host_impl) {}
+ MockSingleScrollbarAnimationControllerClient(LayerTreeHostImpl* host_impl,
+ bool is_fluent)
+ : host_impl_(host_impl), is_fluent_(is_fluent) {}
~MockSingleScrollbarAnimationControllerClient() override = default;
ScrollbarSet ScrollbarsFor(ElementId scroll_element_id) const override {
return host_impl_->ScrollbarsFor(scroll_element_id);
}
- bool IsFluentScrollbar() const override { return false; }
+ bool IsFluentScrollbar() const override { return is_fluent_; }
MOCK_METHOD2(PostDelayedScrollbarAnimationTask,
void(base::OnceClosure start_fade, base::TimeDelta delay));
@@ -49,16 +44,21 @@ class MockSingleScrollbarAnimationControllerClient
private:
raw_ptr<LayerTreeHostImpl> host_impl_;
+ bool is_fluent_;
};
class SingleScrollbarAnimationControllerThinningTest
: public LayerTreeImplTestBase,
- public testing::Test {
+ public testing::Test,
+ public testing::WithParamInterface<bool> {
public:
- SingleScrollbarAnimationControllerThinningTest() : client_(host_impl()) {}
+ explicit SingleScrollbarAnimationControllerThinningTest(
+ bool is_fluent = GetParam())
+ : client_(host_impl(), is_fluent) {}
protected:
const base::TimeDelta kThinningDuration = base::Seconds(2);
+ const int kThumbThickness = 10;
void SetUp() override {
root_layer()->SetBounds(gfx::Size(100, 100));
@@ -67,7 +67,6 @@ class SingleScrollbarAnimationControllerThinningTest
scroll_layer->SetElementId(
LayerIdToElementIdForTesting(scroll_layer->id()));
- const int kThumbThickness = 10;
const int kTrackStart = 0;
const int kTrackLength = 100;
const bool kIsLeftSideVerticalScrollbar = false;
@@ -91,8 +90,14 @@ class SingleScrollbarAnimationControllerThinningTest
scrollbar_controller_ = SingleScrollbarAnimationControllerThinning::Create(
scroll_layer->element_id(), ScrollbarOrientation::HORIZONTAL, &client_,
kThinningDuration);
+ mouse_move_distance_to_trigger_fade_in_ =
+ scrollbar_controller_->MouseMoveDistanceToTriggerFadeIn();
+ mouse_move_distance_to_trigger_expand_ =
+ scrollbar_controller_->MouseMoveDistanceToTriggerExpand();
}
+ float mouse_move_distance_to_trigger_fade_in_;
+ float mouse_move_distance_to_trigger_expand_;
std::unique_ptr<SingleScrollbarAnimationControllerThinning>
scrollbar_controller_;
raw_ptr<SolidColorScrollbarLayerImpl> scrollbar_layer_;
@@ -106,19 +111,27 @@ gfx::PointF NearScrollbar(float offset_x, float offset_y) {
return p;
}
+class SingleScrollbarAnimationControllerThinningFluentTest
+ : public SingleScrollbarAnimationControllerThinningTest {
+ public:
+ SingleScrollbarAnimationControllerThinningFluentTest()
+ : SingleScrollbarAnimationControllerThinningTest(/* is_fluent */ true) {}
+};
+
// Check initialization of scrollbar. Should start thin.
-TEST_F(SingleScrollbarAnimationControllerThinningTest, Idle) {
+TEST_P(SingleScrollbarAnimationControllerThinningTest, Idle) {
EXPECT_FLOAT_EQ(kIdleThicknessScale,
scrollbar_layer_->thumb_thickness_scale_factor());
}
// Move the pointer near the scrollbar. Confirm it gets thick and narrow when
// moved away.
-TEST_F(SingleScrollbarAnimationControllerThinningTest, MouseNear) {
+TEST_P(SingleScrollbarAnimationControllerThinningTest, MouseNear) {
base::TimeTicks time;
time += base::Seconds(1);
- scrollbar_controller_->DidMouseMove(NearScrollbar(-1, 0));
+ scrollbar_controller_->DidMouseMove(
+ NearScrollbar(-mouse_move_distance_to_trigger_expand_, 0));
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(kIdleThicknessScale,
scrollbar_layer_->thumb_thickness_scale_factor());
@@ -129,7 +142,8 @@ TEST_F(SingleScrollbarAnimationControllerThinningTest, MouseNear) {
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
// Subsequent moves within the nearness threshold should not change anything.
- scrollbar_controller_->DidMouseMove(NearScrollbar(-2, 0));
+ scrollbar_controller_->DidMouseMove(
+ NearScrollbar(-mouse_move_distance_to_trigger_expand_ + 1, 0));
scrollbar_controller_->Animate(time);
time += base::Seconds(10);
scrollbar_controller_->Animate(time);
@@ -137,7 +151,7 @@ TEST_F(SingleScrollbarAnimationControllerThinningTest, MouseNear) {
// Now move away from thumb.
scrollbar_controller_->DidMouseMove(
- NearScrollbar(-kMouseMoveDistanceToTriggerExpand, 0));
+ NearScrollbar(-mouse_move_distance_to_trigger_expand_ - 1, 0));
scrollbar_controller_->Animate(time);
time += kThinningDuration;
scrollbar_controller_->Animate(time);
@@ -146,7 +160,7 @@ TEST_F(SingleScrollbarAnimationControllerThinningTest, MouseNear) {
// Move away from track.
scrollbar_controller_->DidMouseMove(
- NearScrollbar(-kMouseMoveDistanceToTriggerFadeIn, 0));
+ NearScrollbar(-mouse_move_distance_to_trigger_fade_in_ - 1, 0));
scrollbar_controller_->Animate(time);
time += kThinningDuration;
scrollbar_controller_->Animate(time);
@@ -156,7 +170,7 @@ TEST_F(SingleScrollbarAnimationControllerThinningTest, MouseNear) {
// Move the pointer over the scrollbar. Make sure it gets thick that it gets
// thin when moved away.
-TEST_F(SingleScrollbarAnimationControllerThinningTest, MouseOver) {
+TEST_P(SingleScrollbarAnimationControllerThinningTest, MouseOver) {
base::TimeTicks time;
time += base::Seconds(1);
@@ -180,7 +194,7 @@ TEST_F(SingleScrollbarAnimationControllerThinningTest, MouseOver) {
// Moving off the scrollbar but still withing the "near" threshold should do
// nothing.
scrollbar_controller_->DidMouseMove(
- NearScrollbar(-kMouseMoveDistanceToTriggerExpand + 1, 0));
+ NearScrollbar(-mouse_move_distance_to_trigger_expand_, 0));
scrollbar_controller_->Animate(time);
time += base::Seconds(10);
scrollbar_controller_->Animate(time);
@@ -188,7 +202,7 @@ TEST_F(SingleScrollbarAnimationControllerThinningTest, MouseOver) {
// Now move away from thumb.
scrollbar_controller_->DidMouseMove(
- NearScrollbar(-kMouseMoveDistanceToTriggerExpand, 0));
+ NearScrollbar(-mouse_move_distance_to_trigger_expand_ - 1, 0));
scrollbar_controller_->Animate(time);
time += kThinningDuration;
scrollbar_controller_->Animate(time);
@@ -199,7 +213,7 @@ TEST_F(SingleScrollbarAnimationControllerThinningTest, MouseOver) {
// First move the pointer over the scrollbar off of it. Make sure the thinning
// animation kicked off in DidMouseMoveOffScrollbar gets overridden by the
// thickening animation in the DidMouseMove call.
-TEST_F(SingleScrollbarAnimationControllerThinningTest,
+TEST_P(SingleScrollbarAnimationControllerThinningTest,
MouseNearThenAwayWhileAnimating) {
base::TimeTicks time;
time += base::Seconds(1);
@@ -232,7 +246,8 @@ TEST_F(SingleScrollbarAnimationControllerThinningTest,
// Now we get a notification for the mouse moving over the scroller. The
// animation is reset to the thickening direction but we won't start
// thickening until the new animation catches up to the current thickness.
- scrollbar_controller_->DidMouseMove(NearScrollbar(-1, 0));
+ scrollbar_controller_->DidMouseMove(
+ NearScrollbar(-mouse_move_distance_to_trigger_expand_, 0));
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f - (1.0f - kIdleThicknessScale) / 2.0f,
scrollbar_layer_->thumb_thickness_scale_factor());
@@ -264,7 +279,7 @@ TEST_F(SingleScrollbarAnimationControllerThinningTest,
// First move the pointer on the scrollbar, then press it, then away.
// Confirm that the bar gets thick. Then mouse up. Confirm that
// the bar gets thin.
-TEST_F(SingleScrollbarAnimationControllerThinningTest,
+TEST_P(SingleScrollbarAnimationControllerThinningTest,
MouseCaptureAndReleaseOutOfBar) {
base::TimeTicks time;
time += base::Seconds(1);
@@ -289,7 +304,7 @@ TEST_F(SingleScrollbarAnimationControllerThinningTest,
// Move outside the "near" threshold. Because the scrollbar is captured it
// should remain thick.
scrollbar_controller_->DidMouseMove(
- NearScrollbar(-kMouseMoveDistanceToTriggerExpand, 0));
+ NearScrollbar(-mouse_move_distance_to_trigger_expand_ - 1, 0));
time += kThinningDuration;
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
@@ -309,7 +324,7 @@ TEST_F(SingleScrollbarAnimationControllerThinningTest,
// First move the pointer on the scrollbar, then press it, then away. Confirm
// that the bar gets thick. Then move point on the scrollbar and mouse up.
// Confirm that the bar stays thick.
-TEST_F(SingleScrollbarAnimationControllerThinningTest,
+TEST_P(SingleScrollbarAnimationControllerThinningTest,
MouseCaptureAndReleaseOnBar) {
base::TimeTicks time;
time += base::Seconds(1);
@@ -331,7 +346,7 @@ TEST_F(SingleScrollbarAnimationControllerThinningTest,
// Move away from scrollbar. Nothing should change.
scrollbar_controller_->DidMouseMove(
- NearScrollbar(kMouseMoveDistanceToTriggerExpand, 0));
+ NearScrollbar(mouse_move_distance_to_trigger_expand_ + 1, 0));
time += base::Seconds(1);
scrollbar_controller_->Animate(time);
time += base::Seconds(10);
@@ -341,7 +356,7 @@ TEST_F(SingleScrollbarAnimationControllerThinningTest,
// Move over scrollbar and release. Since we're near the scrollbar, it should
// remain thick.
scrollbar_controller_->DidMouseMove(
- NearScrollbar(-kMouseMoveDistanceToTriggerExpand + 1, 0));
+ NearScrollbar(-mouse_move_distance_to_trigger_expand_, 0));
scrollbar_controller_->DidMouseUp();
time += base::Seconds(1);
scrollbar_controller_->Animate(time);
@@ -351,13 +366,14 @@ TEST_F(SingleScrollbarAnimationControllerThinningTest,
}
// Tests that the thickening/thinning effects are animated.
-TEST_F(SingleScrollbarAnimationControllerThinningTest, ThicknessAnimated) {
+TEST_P(SingleScrollbarAnimationControllerThinningTest, ThicknessAnimated) {
base::TimeTicks time;
time += base::Seconds(1);
// Move mouse near scrollbar. Test that at half the duration time, the
// thickness is half way through its animation.
- scrollbar_controller_->DidMouseMove(NearScrollbar(-1, 0));
+ scrollbar_controller_->DidMouseMove(
+ NearScrollbar(-mouse_move_distance_to_trigger_expand_, 0));
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(kIdleThicknessScale,
scrollbar_layer_->thumb_thickness_scale_factor());
@@ -374,7 +390,7 @@ TEST_F(SingleScrollbarAnimationControllerThinningTest, ThicknessAnimated) {
// Move mouse away from scrollbar. Same check.
time += base::Seconds(1);
scrollbar_controller_->DidMouseMove(
- NearScrollbar(-kMouseMoveDistanceToTriggerExpand, 0));
+ NearScrollbar(-mouse_move_distance_to_trigger_expand_ - 1, 0));
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
@@ -389,5 +405,64 @@ TEST_F(SingleScrollbarAnimationControllerThinningTest, ThicknessAnimated) {
scrollbar_layer_->thumb_thickness_scale_factor());
}
+// Make sure the Fluent scrollbar transitions to the full mode (thick) after
+// moving the mouse over scrollbar track and get back to the minimal mode (thin)
+// when moved away both inside and outside the layer.
+TEST_F(SingleScrollbarAnimationControllerThinningFluentTest,
+ FluentMouseOverTrack) {
+ base::TimeTicks time;
+ time += base::Seconds(1);
+
+ // Move the mouse over the scrollbar track.
+ scrollbar_controller_->DidMouseMove(NearScrollbar(0, 75));
+ scrollbar_controller_->Animate(time);
+ EXPECT_FLOAT_EQ(kIdleThicknessScale,
+ scrollbar_layer_->thumb_thickness_scale_factor());
+
+ // Should animate to the full mode.
+ time += kThinningDuration;
+ scrollbar_controller_->Animate(time);
+ EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+
+ // Subsequent moves should not change anything.
+ scrollbar_controller_->DidMouseMove(NearScrollbar(0, 75));
+ scrollbar_controller_->Animate(time);
+ time += base::Seconds(10);
+ scrollbar_controller_->Animate(time);
+ EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+
+ // Moving away from the scrollbar track should trigger the transition to the
+ // minimal mode.
+ scrollbar_controller_->DidMouseMove(NearScrollbar(-1, 75));
+ scrollbar_controller_->Animate(time);
+ time += kThinningDuration;
+ scrollbar_controller_->Animate(time);
+ EXPECT_FLOAT_EQ(kIdleThicknessScale,
+ scrollbar_layer_->thumb_thickness_scale_factor());
+
+ // Move the mouse over the scrollbar track again. Scrollbar should be in the
+ // full mode.
+ scrollbar_controller_->DidMouseMove(NearScrollbar(0, 75));
+ scrollbar_controller_->Animate(time);
+ EXPECT_FLOAT_EQ(kIdleThicknessScale,
+ scrollbar_layer_->thumb_thickness_scale_factor());
+ time += kThinningDuration;
+ scrollbar_controller_->Animate(time);
+ EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+
+ // Moving away from the scrollbar track out of the layer should also
+ // trigger the transition to the minimal mode.
+ scrollbar_controller_->DidMouseMove(NearScrollbar(kThumbThickness + 1, 75));
+ scrollbar_controller_->Animate(time);
+ time += kThinningDuration;
+ scrollbar_controller_->Animate(time);
+ EXPECT_FLOAT_EQ(kIdleThicknessScale,
+ scrollbar_layer_->thumb_thickness_scale_factor());
+}
+
+INSTANTIATE_TEST_SUITE_P(All,
+ SingleScrollbarAnimationControllerThinningTest,
+ Bool());
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/input/threaded_input_handler.h b/chromium/cc/input/threaded_input_handler.h
deleted file mode 100644
index 08a356852ae..00000000000
--- a/chromium/cc/input/threaded_input_handler.h
+++ /dev/null
@@ -1,472 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_INPUT_THREADED_INPUT_HANDLER_H_
-#define CC_INPUT_THREADED_INPUT_HANDLER_H_
-
-#include <memory>
-
-#include "base/containers/flat_set.h"
-#include "base/gtest_prod_util.h"
-#include "base/memory/raw_ptr.h"
-#include "base/time/time.h"
-#include "cc/input/compositor_input_interfaces.h"
-#include "cc/input/event_listener_properties.h"
-#include "cc/input/input_handler.h"
-#include "cc/input/scroll_snap_data.h"
-#include "cc/input/scroll_state.h"
-#include "cc/input/touch_action.h"
-#include "cc/metrics/events_metrics_manager.h"
-#include "cc/metrics/frame_sequence_metrics.h"
-#include "cc/paint/element_id.h"
-#include "components/viz/common/frame_sinks/begin_frame_args.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
-#include "ui/events/types/scroll_input_type.h"
-
-namespace gfx {
-class Point;
-class PointF;
-class Vector2dF;
-} // namespace gfx
-
-namespace cc {
-
-class LatencyInfoSwapPromiseMonitor;
-class LayerImpl;
-class ScrollbarController;
-class ScrollElasticityHelper;
-struct ScrollNode;
-class ScrollTree;
-class Viewport;
-
-class CC_EXPORT ThreadedInputHandler : public InputHandler,
- public InputDelegateForCompositor {
- public:
- explicit ThreadedInputHandler(
- CompositorDelegateForInput& compositor_delegate);
- ~ThreadedInputHandler() override;
-
- // =========== InputHandler "Interface" - will override in a future CL
- base::WeakPtr<InputHandler> AsWeakPtr() const override;
- void BindToClient(InputHandlerClient* client) override;
- InputHandler::ScrollStatus ScrollBegin(ScrollState* scroll_state,
- ui::ScrollInputType type) override;
- InputHandler::ScrollStatus RootScrollBegin(ScrollState* scroll_state,
- ui::ScrollInputType type) override;
- InputHandlerScrollResult ScrollUpdate(
- ScrollState* scroll_state,
- base::TimeDelta delayed_by = base::TimeDelta()) override;
- void ScrollEnd(bool should_snap = false) override;
- PointerResultType HitTest(const gfx::PointF& viewport_point) override;
- void RecordScrollBegin(ui::ScrollInputType input_type,
- ScrollBeginThreadState scroll_start_state) override;
- void RecordScrollEnd(ui::ScrollInputType input_type) override;
- InputHandlerPointerResult MouseMoveAt(
- const gfx::Point& viewport_point) override;
- InputHandlerPointerResult MouseDown(const gfx::PointF& viewport_point,
- bool shift_modifier) override;
- InputHandlerPointerResult MouseUp(const gfx::PointF& viewport_point) override;
- void MouseLeave() override;
- ElementId FindFrameElementIdAtPoint(
- const gfx::PointF& viewport_point) override;
- void RequestUpdateForSynchronousInputHandler() override;
- void SetSynchronousInputHandlerRootScrollOffset(
- const gfx::PointF& root_content_offset) override;
- void PinchGestureBegin(const gfx::Point& anchor,
- ui::ScrollInputType source) override;
- void PinchGestureUpdate(float magnify_delta,
- const gfx::Point& anchor) override;
- void PinchGestureEnd(const gfx::Point& anchor) override;
- void SetNeedsAnimateInput() override;
- bool IsCurrentlyScrollingViewport() const override;
- EventListenerProperties GetEventListenerProperties(
- EventListenerClass event_class) const override;
- bool HasBlockingWheelEventHandlerAt(
- const gfx::Point& viewport_point) const override;
- InputHandler::TouchStartOrMoveEventListenerType
- EventListenerTypeForTouchStartOrMoveAt(
- const gfx::Point& viewport_port,
- TouchAction* out_touch_action) override;
- std::unique_ptr<LatencyInfoSwapPromiseMonitor>
- CreateLatencyInfoSwapPromiseMonitor(ui::LatencyInfo* latency) override;
- std::unique_ptr<EventsMetricsManager::ScopedMonitor>
- GetScopedEventMetricsMonitor(
- EventsMetricsManager::ScopedMonitor::DoneCallback done_callback) override;
- ScrollElasticityHelper* CreateScrollElasticityHelper() override;
- void DestroyScrollElasticityHelper() override;
- bool GetScrollOffsetForLayer(ElementId element_id,
- gfx::PointF* offset) override;
- bool ScrollLayerTo(ElementId element_id, const gfx::PointF& offset) override;
- bool ScrollingShouldSwitchtoMainThread() override;
- bool GetSnapFlingInfoAndSetAnimatingSnapTarget(
- const gfx::Vector2dF& natural_displacement_in_viewport,
- gfx::PointF* out_initial_position,
- gfx::PointF* out_target_position) override;
- void ScrollEndForSnapFling(bool did_finish) override;
- void NotifyInputEvent() override;
- bool ScrollbarScrollIsActive() override;
- void SetDeferBeginMainFrame(bool defer_begin_main_frame) const override;
-
- // =========== InputDelegateForCompositor Interface - This section implements
- // the interface that LayerTreeHostImpl uses to communicate with the input
- // system.
- void ProcessCommitDeltas(CompositorCommitData* commit_data) override;
- void TickAnimations(base::TimeTicks monotonic_time) override;
- void WillShutdown() override;
- void WillDraw() override;
- void WillBeginImplFrame(const viz::BeginFrameArgs& args) override;
- void DidCommit() override;
- void DidActivatePendingTree() override;
- void RootLayerStateMayHaveChanged() override;
- void DidRegisterScrollbar(ElementId scroll_element_id,
- ScrollbarOrientation orientation) override;
- void DidUnregisterScrollbar(ElementId scroll_element_id,
- ScrollbarOrientation orientation) override;
- void ScrollOffsetAnimationFinished() override;
- void SetPrefersReducedMotion(bool prefers_reduced_motion) override;
- bool IsCurrentlyScrolling() const override;
- ActivelyScrollingType GetActivelyScrollingType() const override;
-
- // =========== Public Interface
-
- bool CanConsumeDelta(const ScrollState& scroll_state,
- const ScrollNode& scroll_node);
- // Returns the amount of delta that can be applied to scroll_node, taking
- // page scale into account.
- gfx::Vector2dF ComputeScrollDelta(const ScrollNode& scroll_node,
- const gfx::Vector2dF& delta);
-
- gfx::Vector2dF ScrollSingleNode(const ScrollNode& scroll_node,
- const gfx::Vector2dF& delta,
- const gfx::Point& viewport_point,
- bool is_direct_manipulation);
-
- float LineStep() const;
-
- // Resolves a delta in the given granularity for the |scroll_node| into
- // physical pixels to scroll.
- gfx::Vector2dF ResolveScrollGranularityToPixels(
- const ScrollNode& scroll_node,
- const gfx::Vector2dF& scroll_delta,
- ui::ScrollGranularity granularity);
-
- // Used to set the pinch gesture active state when the pinch gesture is
- // handled on another layer tree. In a page with OOPIFs, only the main
- // frame's layer tree directly handles pinch events. But layer trees for
- // sub-frames need to know when pinch gestures are active so they can
- // throttle the re-rastering. This function allows setting this flag on
- // OOPIF layer trees using information sent (initially) from the main-frame.
- void set_external_pinch_gesture_active(bool external_pinch_gesture_active) {
- external_pinch_gesture_active_ = external_pinch_gesture_active;
- // Only one of the flags should ever be true at any given time.
- DCHECK(!pinch_gesture_active_ || !external_pinch_gesture_active_);
- }
-
- bool pinch_gesture_active() const {
- return pinch_gesture_active_ || external_pinch_gesture_active_;
- }
-
- void set_force_smooth_wheel_scrolling_for_testing(bool enabled) {
- force_smooth_wheel_scrolling_for_testing_ = enabled;
- }
-
- gfx::Vector2dF accumulated_root_overscroll_for_testing() const {
- return accumulated_root_overscroll_;
- }
-
- bool animating_for_snap_for_testing() const { return IsAnimatingForSnap(); }
-
- private:
- FRIEND_TEST_ALL_PREFIXES(ScrollUnifiedLayerTreeHostImplTest,
- AbortAnimatedScrollBeforeStartingAutoscroll);
- FRIEND_TEST_ALL_PREFIXES(ScrollUnifiedLayerTreeHostImplTest,
- AnimatedScrollYielding);
- FRIEND_TEST_ALL_PREFIXES(ScrollUnifiedLayerTreeHostImplTest,
- AutoscrollOnDeletedScrollbar);
- FRIEND_TEST_ALL_PREFIXES(ScrollUnifiedLayerTreeHostImplTest,
- ThumbDragAfterJumpClick);
- FRIEND_TEST_ALL_PREFIXES(ScrollUnifiedLayerTreeHostImplTest,
- ScrollOnLargeThumb);
- FRIEND_TEST_ALL_PREFIXES(LayerTreeHostImplTest, AutoscrollTaskAbort);
-
- // This method gets the scroll offset for a regular scroller, or the combined
- // visual and layout offsets of the viewport.
- gfx::PointF GetVisualScrollOffset(const ScrollNode& scroll_node) const;
- bool IsScrolledBy(LayerImpl* child, ScrollNode* ancestor);
- bool IsAnimatingForSnap() const;
-
- ScrollNode* CurrentlyScrollingNode();
- const ScrollNode* CurrentlyScrollingNode() const;
- void ClearCurrentlyScrollingNode();
- ScrollTree& GetScrollTree();
- ScrollTree& GetScrollTree() const;
- Viewport& GetViewport() const;
-
- ScrollNode* InnerViewportScrollNode() const;
- ScrollNode* OuterViewportScrollNode() const;
-
- void SetNeedsCommit();
- LayerTreeImpl& ActiveTree();
- LayerTreeImpl& ActiveTree() const;
-
- bool IsMainThreadScrolling(const InputHandler::ScrollStatus& status,
- const ScrollNode* scroll_node) const;
-
- bool IsTouchDraggingScrollbar(
- LayerImpl* first_scrolling_layer_or_drawn_scrollbar,
- ui::ScrollInputType type);
-
- void UpdateRootLayerStateForSynchronousInputHandler();
-
- // Called during ScrollBegin once a scroller was successfully latched to
- // (i.e. it can and will consume scroll delta on the compositor thread). The
- // latched scroller is now available in CurrentlyScrollingNode().
- // TODO(bokan): There's some debate about the name of this method. We should
- // get consensus on terminology to use and apply it consistently.
- // https://crrev.com/c/1981336/9/cc/trees/layer_tree_host_impl.cc#4520
- void DidLatchToScroller(const ScrollState& scroll_state,
- ui::ScrollInputType type);
-
- // This function keeps track of sources of scrolls that are handled in the
- // compositor side. The information gets shared by the main thread as part of
- // the begin_main_frame_state. Finally Use counters are updated in the main
- // thread side to keep track of the frequency of scrolling with different
- // sources per page load. TODO(crbug.com/691886): Use GRC API to plumb the
- // scroll source info for Use Counters.
- void UpdateScrollSourceInfo(const ScrollState& scroll_state,
- ui::ScrollInputType type);
-
- // Applies the scroll_state to the currently latched scroller. See comment in
- // InputHandler::ScrollUpdate declaration for the meaning of |delayed_by|.
- void ScrollLatchedScroller(ScrollState* scroll_state,
- base::TimeDelta delayed_by);
-
- // Determines whether the given scroll node can scroll on the compositor
- // thread or if there are any reasons it must be scrolled on the main thread
- // or not at all. Note: in general, this is not sufficient to determine if a
- // scroll can occur on the compositor thread. If hit testing to a scroll
- // node, the caller must also check whether the hit point intersects a
- // non-fast-scrolling-region of any ancestor scrolling layers. Can be removed
- // after scroll unification https://crbug.com/476553.
- InputHandler::ScrollStatus TryScroll(const ScrollTree& scroll_tree,
- ScrollNode* scroll_node) const;
-
- enum class SnapReason { kGestureScrollEnd, kScrollOffsetAnimationFinished };
-
- // Creates an animation curve and returns true if we need to update the
- // scroll position to a snap point. Otherwise returns false.
- bool SnapAtScrollEnd(SnapReason reason);
-
- // |layer| is returned from a regular hit test, and
- // |first_scrolling_layer_or_drawn_scrollbar| is returned from a hit test
- // performed only on scrollers and scrollbars. Initial scroll hit testing can
- // be unreliable if the latter is not the direct scroll ancestor of the
- // former. In this case, we will fall back to main thread scrolling because
- // the compositor thread doesn't know which layer to scroll. This happens when
- // a layer covers a scroller that doesn't scroll the former, or a scroller is
- // masked by a mask layer for mask image, clip-path, rounded border, etc.
- //
- // Note, position: fixed layers use the inner viewport as their ScrollNode
- // (since they don't scroll with the outer viewport), however, scrolls from
- // the fixed layer still chain to the outer viewport. It's also possible for a
- // node to have the inner viewport as its ancestor without going through the
- // outer viewport; however, it may still scroll using the viewport(). Hence,
- // this method must use the same scroll chaining logic we use in ApplyScroll.
- bool IsInitialScrollHitTestReliable(
- const LayerImpl* layer,
- const LayerImpl* first_scrolling_layer_or_drawn_scrollbar) const;
-
- // Similar to above but includes complicated logic to determine whether the
- // ScrollNode is able to be scrolled on the compositor or requires main
- // thread scrolling. If main thread scrolling is required
- // |scroll_on_main_thread| is set to true and the reason is given in
- // |main_thread_scrolling_reason| to on of the enum values in
- // main_thread_scrolling_reason.h. Can be removed after scroll unification
- // https://crbug.com/476553.
- ScrollNode* FindScrollNodeForCompositedScrolling(
- const gfx::PointF& device_viewport_point,
- LayerImpl* layer_hit_by_point,
- bool* scroll_on_main_thread,
- uint32_t* main_thread_scrolling_reason);
-
- // Return all ScrollNode indices that have an associated layer with a non-fast
- // region that intersects the point.
- base::flat_set<int> NonFastScrollableNodes(
- const gfx::PointF& device_viewport_point) const;
-
- // Returns the ScrollNode we should use to scroll, accounting for viewport
- // scroll chaining rules.
- ScrollNode* GetNodeToScroll(ScrollNode* node) const;
-
- // Given a starting node (determined by hit-test), walks up the scroll tree
- // looking for the first node that can consume scroll from the given
- // scroll_state and returns the first such node. If none is found, or if
- // starting_node is nullptr, returns nullptr;
- ScrollNode* FindNodeToLatch(ScrollState* scroll_state,
- ScrollNode* starting_node,
- ui::ScrollInputType type);
-
- bool CanPropagate(ScrollNode* scroll_node, float x, float y);
-
- // Performs a hit test to determine the ScrollNode to use when scrolling at
- // |viewport_point|. If no layer is hit, this falls back to the inner
- // viewport scroll node. Returns:
- // - If |hit_test_sucessful| is false, hit testing has failed and the
- // compositor cannot determine the correct scroll node (e.g. see comments in
- // IsInitialScrollHitTestReliable). |scroll_node| is always nullptr in this
- // case.
- // - If |hit_test_successful| is true, returns the ScrollNode to use in
- // |scroll_node|. This can be nullptr if no layer was hit and there are no
- // viewport nodes (e.g. OOPIF, UI compositor).
- struct ScrollHitTestResult {
- ScrollNode* scroll_node;
- bool hit_test_successful;
- };
- ScrollHitTestResult HitTestScrollNode(
- const gfx::PointF& device_viewport_point) const;
-
- bool ShouldAnimateScroll(const ScrollState& scroll_state) const;
-
- bool ScrollAnimationUpdateTarget(const ScrollNode& scroll_node,
- const gfx::Vector2dF& scroll_delta,
- base::TimeDelta delayed_by);
-
- // Transforms viewport start point and scroll delta to local start point and
- // local delta, respectively. If the transformation of either the start or end
- // point of a scroll is clipped, the function returns false.
- bool CalculateLocalScrollDeltaAndStartPoint(
- const ScrollNode& scroll_node,
- const gfx::PointF& viewport_point,
- const gfx::Vector2dF& viewport_delta,
- gfx::Vector2dF* out_local_scroll_delta,
- gfx::PointF* out_local_start_point = nullptr);
- gfx::Vector2dF ScrollNodeWithViewportSpaceDelta(
- const ScrollNode& scroll_node,
- const gfx::PointF& viewport_point,
- const gfx::Vector2dF& viewport_delta);
- gfx::Vector2dF ScrollNodeWithLocalDelta(
- const ScrollNode& scroll_node,
- const gfx::Vector2dF& local_delta) const;
- // This helper returns an adjusted version of |delta| where the scroll delta
- // is cleared in any axis in which user scrolling is disabled (e.g. by
- // |overflow-x: hidden|).
- gfx::Vector2dF UserScrollableDelta(const ScrollNode& node,
- const gfx::Vector2dF& delta) const;
-
- void AdjustScrollDeltaForScrollbarSnap(ScrollState* scroll_state);
-
- FrameSequenceTrackerType GetTrackerTypeForScroll(
- ui::ScrollInputType input_type) const;
-
- ScrollbarController* scrollbar_controller_for_testing() const {
- return scrollbar_controller_.get();
- }
-
- // The input handler is owned by the delegate so their lifetimes are tied
- // together.
- CompositorDelegateForInput& compositor_delegate_;
-
- raw_ptr<InputHandlerClient> input_handler_client_ = nullptr;
-
- // An object to implement the ScrollElasticityHelper interface and
- // hold all state related to elasticity. May be nullptr if never requested.
- std::unique_ptr<ScrollElasticityHelper> scroll_elasticity_helper_;
-
- // Manages composited scrollbar hit testing.
- std::unique_ptr<ScrollbarController> scrollbar_controller_;
-
- // Overscroll delta accumulated on the viewport throughout a scroll gesture;
- // reset when the gesture ends.
- gfx::Vector2dF accumulated_root_overscroll_;
-
- // Unconsumed scroll delta sent to the main thread for firing overscroll DOM
- // events. Resets after each commit.
- gfx::Vector2dF overscroll_delta_for_main_thread_;
-
- // The source device type that started the scroll gesture. Only set between a
- // ScrollBegin and ScrollEnd.
- absl::optional<ui::ScrollInputType> latched_scroll_type_;
-
- // Tracks the last scroll update/begin state received. Used to infer the most
- // recent scroll type and direction.
- absl::optional<ScrollState> last_scroll_begin_state_;
- absl::optional<ScrollState> last_scroll_update_state_;
-
- // If a scroll snap is being animated, then the value of this will be the
- // element id(s) of the target(s). Otherwise, the ids will be invalid.
- // At the end of a scroll animation, the target should be set as the scroll
- // node's snap target.
- TargetSnapAreaElementIds scroll_animating_snap_target_ids_;
-
- // A set of elements that scroll-snapped to a new target since the last
- // begin main frame. The snap target ids of these elements will be sent to
- // the main thread in the next begin main frame.
- base::flat_map<ElementId, TargetSnapAreaElementIds> updated_snapped_elements_;
-
- ElementId scroll_element_id_mouse_currently_over_;
- ElementId scroll_element_id_mouse_currently_captured_;
-
- // Set in ScrollBegin and outlives the currently scrolling node so it can be
- // used to send the scrollend and overscroll DOM events from the main thread
- // when scrolling occurs on the compositor thread. This value is cleared at
- // the first commit after a GSE.
- ElementId last_latched_scroller_;
-
- // Scroll animation can finish either before or after GSE arrival.
- // deferred_scroll_end_ is set when the GSE has arrvied before scroll
- // animation completion. ScrollEnd will get called once the animation is
- // over.
- bool deferred_scroll_end_ = false;
-
- // Set to true when a scroll gesture being handled on the compositor has
- // ended. i.e. When a GSE has arrived and any ongoing scroll animation has
- // ended.
- bool scroll_gesture_did_end_ = false;
-
- // True iff some of the delta has been consumed for the current scroll
- // sequence on the specific axis.
- bool did_scroll_x_for_scroll_gesture_ = false;
- bool did_scroll_y_for_scroll_gesture_ = false;
-
- // did_scroll_x/y_for_scroll_gesture_ is true when contents consume the delta,
- // but delta_consumed_for_scroll_gesture_ can be true when only browser
- // controls consume all the delta.
- bool delta_consumed_for_scroll_gesture_ = false;
-
- // TODO(bokan): Mac doesn't yet have smooth scrolling for wheel; however, to
- // allow consistency in tests we use this bit to override that decision.
- // https://crbug.com/574283.
- bool force_smooth_wheel_scrolling_for_testing_ = false;
-
- // This value is used to allow the compositor to throttle re-rastering during
- // pinch gestures, when the page scale factor may be changing frequently. It
- // is set in one of two ways:
- // i) In a layer tree serving the root of the frame/compositor tree, it is
- // directly set during processing of GesturePinch events on the impl thread
- // (only the root layer tree has access to these).
- // ii) In a layer tree serving a sub-frame in the frame/compositor tree, it
- // is set from the main thread during the commit process, using information
- // sent from the root layer tree via IPC messaging.
- bool pinch_gesture_active_ = false;
- bool external_pinch_gesture_active_ = false;
- bool pinch_gesture_end_should_clear_scrolling_node_ = false;
-
- // These are used to transfer usage of different types of scrolling to the
- // main thread.
- bool has_pinch_zoomed_ = false;
- bool has_scrolled_by_wheel_ = false;
- bool has_scrolled_by_touch_ = false;
- bool has_scrolled_by_precisiontouchpad_ = false;
- bool has_scrolled_by_scrollbar_ = false;
-
- bool prefers_reduced_motion_ = false;
-
- // Must be the last member to ensure this is destroyed first in the
- // destruction order and invalidates all weak pointers.
- base::WeakPtrFactory<ThreadedInputHandler> weak_factory_{this};
-};
-
-} // namespace cc
-
-#endif // CC_INPUT_THREADED_INPUT_HANDLER_H_
diff --git a/chromium/cc/input/touch_action.h b/chromium/cc/input/touch_action.h
index 21655306c3a..d5a29507ef2 100644
--- a/chromium/cc/input/touch_action.h
+++ b/chromium/cc/input/touch_action.h
@@ -39,8 +39,15 @@ enum class TouchAction {
// and it doesn't have a horizontal scrollable ancestor (including
// itself), we don't set this bit.
kInternalPanXScrolls = 0x40,
- kAuto = kManipulation | kDoubleTapZoom | kInternalPanXScrolls,
- kMax = (1 << 7) - 1
+
+ // This is used internally by stylus handwriting feature. Stylus writing would
+ // not be started when this bit is set. When the element is non-password edit
+ // field and has kPan, we don't set this bit.
+ kInternalNotWritable = 0x80,
+
+ kAuto = kManipulation | kDoubleTapZoom | kInternalPanXScrolls |
+ kInternalNotWritable,
+ kMax = (1 << 8) - 1
};
inline TouchAction operator|(TouchAction a, TouchAction b) {
@@ -67,6 +74,11 @@ inline const char* TouchActionToString(TouchAction touch_action) {
// we skip printing internal panx scrolls since it's not a web exposed touch
// action field.
touch_action &= ~TouchAction::kInternalPanXScrolls;
+
+ // we skip printing kInternalNotWritable since it's not a web exposed
+ // touch action field.
+ touch_action &= ~TouchAction::kInternalNotWritable;
+
switch (static_cast<int>(touch_action)) {
case 0:
return "NONE";
diff --git a/chromium/cc/layers/heads_up_display_layer_impl.cc b/chromium/cc/layers/heads_up_display_layer_impl.cc
index bf883bd1e01..17138b5f195 100644
--- a/chromium/cc/layers/heads_up_display_layer_impl.cc
+++ b/chromium/cc/layers/heads_up_display_layer_impl.cc
@@ -223,7 +223,7 @@ void HeadsUpDisplayLayerImpl::AppendQuads(
// layers.
gfx::Rect quad_rect(internal_content_bounds_);
auto* quad = render_pass->CreateAndAppendDrawQuad<viz::SolidColorDrawQuad>();
- quad->SetNew(shared_quad_state, quad_rect, quad_rect, SK_ColorTRANSPARENT,
+ quad->SetNew(shared_quad_state, quad_rect, quad_rect, SkColors::kTransparent,
false);
ValidateQuadResources(quad);
current_quad_ = quad;
@@ -491,7 +491,7 @@ void HeadsUpDisplayLayerImpl::UpdateHudTexture(
resource_id, /*premultiplied_alpha=*/true,
/*uv_top_left=*/gfx::PointF(),
/*uv_bottom_right=*/uv_bottom_right,
- /*background_color=*/SK_ColorTRANSPARENT, vertex_opacity,
+ /*background_color=*/SkColors::kTransparent, vertex_opacity,
/*flipped=*/false,
/*nearest_neighbor=*/false, /*secure_output_only=*/false,
gfx::ProtectedVideoType::kClear);
@@ -588,7 +588,7 @@ void HeadsUpDisplayLayerImpl::DrawHudContents(PaintCanvas* canvas) {
const LayerTreeDebugState& debug_state = layer_tree_impl()->debug_state();
TRACE_EVENT0("cc", "DrawHudContents");
- canvas->clear(SkColorSetARGB(0, 0, 0, 0));
+ canvas->clear(SkColors::kTransparent);
canvas->save();
canvas->scale(internal_contents_scale_);
@@ -685,8 +685,7 @@ void HeadsUpDisplayLayerImpl::DrawText(PaintCanvas* canvas,
void HeadsUpDisplayLayerImpl::DrawGraphBackground(PaintCanvas* canvas,
PaintFlags* flags,
const SkRect& bounds) const {
- // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
- flags->setColor(DebugColors::HUDBackgroundColor().toSkColor());
+ flags->setColor(DebugColors::HUDBackgroundColor());
canvas->drawRect(bounds, *flags);
}
@@ -694,8 +693,7 @@ void HeadsUpDisplayLayerImpl::DrawGraphLines(PaintCanvas* canvas,
PaintFlags* flags,
const SkRect& bounds) const {
// Draw top and bottom line.
- // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
- flags->setColor(DebugColors::HUDSeparatorLineColor().toSkColor());
+ flags->setColor(DebugColors::HUDSeparatorLineColor());
canvas->drawLine(bounds.left(), bounds.top() - 1, bounds.right(),
bounds.top() - 1, *flags);
canvas->drawLine(bounds.left(), bounds.bottom(), bounds.right(),
@@ -706,8 +704,7 @@ void HeadsUpDisplayLayerImpl::DrawSeparatorLine(PaintCanvas* canvas,
PaintFlags* flags,
const SkRect& bounds) const {
// Draw separator line as transparent white.
- constexpr auto kSeparatorLineColor = SkColorSetARGB(64, 255, 255, 255);
- flags->setColor(kSeparatorLineColor);
+ flags->setColor({1.0f, 1.0f, 1.0f, 0.25f});
canvas->drawLine(bounds.left(), bounds.top(), bounds.right(), bounds.top(),
*flags);
}
@@ -757,13 +754,11 @@ SkRect HeadsUpDisplayLayerImpl::DrawFrameThroughputDisplay(
}
VLOG(1) << value_text;
- // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
- flags.setColor(DebugColors::HUDTitleColor().toSkColor());
+ flags.setColor(DebugColors::HUDTitleColor());
DrawText(canvas, flags, title, TextAlign::kLeft, kTitleFontHeight,
title_bounds.left(), title_bounds.bottom());
- // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
- flags.setColor(DebugColors::FPSDisplayTextAndGraphColor().toSkColor());
+ flags.setColor(DebugColors::FPSDisplayTextAndGraphColor());
DrawText(canvas, flags, value_text, TextAlign::kRight, kFontHeight,
text_bounds.right(), text_bounds.bottom());
@@ -790,15 +785,13 @@ SkRect HeadsUpDisplayLayerImpl::DrawFrameThroughputDisplay(
flags.setStyle(PaintFlags::kStroke_Style);
flags.setStrokeWidth(1);
- // TODO(crbug/1308932): Remove all instances of toSkColor below and make all
- // SkColor4f.
- flags.setColor(DebugColors::FPSDisplaySuccessfulFrame().toSkColor());
+ flags.setColor(DebugColors::FPSDisplaySuccessfulFrame());
canvas->drawPath(good_path, flags);
- flags.setColor(DebugColors::FPSDisplayDroppedFrame().toSkColor());
+ flags.setColor(DebugColors::FPSDisplayDroppedFrame());
canvas->drawPath(dropped_path, flags);
- flags.setColor(DebugColors::FPSDisplayMissedFrame().toSkColor());
+ flags.setColor(DebugColors::FPSDisplayMissedFrame());
canvas->drawPath(partial_path, flags);
return area;
@@ -828,13 +821,11 @@ SkRect HeadsUpDisplayLayerImpl::DrawMemoryDisplay(PaintCanvas* canvas,
SkPoint stat2_pos = SkPoint::Make(left + width - kPadding - 1,
top + 2 * kPadding + 3 * kFontHeight);
- // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
- flags.setColor(DebugColors::HUDTitleColor().toSkColor());
+ flags.setColor(DebugColors::HUDTitleColor());
DrawText(canvas, flags, "GPU memory", TextAlign::kLeft, kTitleFontHeight,
title_pos);
- // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
- flags.setColor(DebugColors::MemoryDisplayTextColor().toSkColor());
+ flags.setColor(DebugColors::MemoryDisplayTextColor());
std::string text = base::StringPrintf(
"%6.1f MB used", memory_entry_.total_bytes_used / kMegabyte);
DrawText(canvas, flags, text, TextAlign::kRight, kFontHeight, stat1_pos);
@@ -864,8 +855,11 @@ SkRect HeadsUpDisplayLayerImpl::DrawMemoryDisplay(PaintCanvas* canvas,
memory_entry_.total_budget_in_bytes) *
180;
- SkColor colors[] = {SK_ColorRED, SK_ColorGREEN, SK_ColorGREEN,
- SkColorSetARGB(255, 255, 140, 0), SK_ColorRED};
+ SkColor4f colors[] = {SkColors::kRed,
+ SkColors::kGreen,
+ SkColors::kGreen,
+ {1.0f, 0.55f, 0.0f, 1.0f},
+ SkColors::kRed};
const SkScalar pos[] = {SkFloatToScalar(0.2f), SkFloatToScalar(0.4f),
SkFloatToScalar(0.6f), SkFloatToScalar(0.8f),
SkFloatToScalar(1.0f)};
@@ -939,8 +933,8 @@ void HeadsUpDisplayLayerImpl::DrawDebugRect(
PaintCanvas* canvas,
PaintFlags* flags,
const DebugRect& rect,
- SkColor stroke_color,
- SkColor fill_color,
+ SkColor4f stroke_color,
+ SkColor4f fill_color,
float stroke_width,
const std::string& label_text) const {
DCHECK(typeface_.get());
@@ -998,14 +992,12 @@ void HeadsUpDisplayLayerImpl::DrawDebugRects(
std::vector<DebugRect> new_layout_shift_rects;
for (size_t i = 0; i < debug_rects.size(); ++i) {
- SkColor stroke_color = 0;
- SkColor fill_color = 0;
+ SkColor4f stroke_color = SkColors::kTransparent;
+ SkColor4f fill_color = SkColors::kTransparent;
float stroke_width = 0.f;
std::string label_text;
switch (debug_rects[i].type) {
- // TODO(crbug/1308932): Remove all instances of toSkColor below and make
- // all SkColor4f.
case LAYOUT_SHIFT_RECT_TYPE:
new_layout_shift_rects.push_back(debug_rects[i]);
continue;
@@ -1013,65 +1005,56 @@ void HeadsUpDisplayLayerImpl::DrawDebugRects(
new_paint_rects.push_back(debug_rects[i]);
continue;
case PROPERTY_CHANGED_RECT_TYPE:
- stroke_color =
- DebugColors::PropertyChangedRectBorderColor().toSkColor();
- fill_color = DebugColors::PropertyChangedRectFillColor().toSkColor();
+ stroke_color = DebugColors::PropertyChangedRectBorderColor();
+ fill_color = DebugColors::PropertyChangedRectFillColor();
stroke_width = DebugColors::PropertyChangedRectBorderWidth();
break;
case SURFACE_DAMAGE_RECT_TYPE:
- stroke_color = DebugColors::SurfaceDamageRectBorderColor().toSkColor();
- fill_color = DebugColors::SurfaceDamageRectFillColor().toSkColor();
+ stroke_color = DebugColors::SurfaceDamageRectBorderColor();
+ fill_color = DebugColors::SurfaceDamageRectFillColor();
stroke_width = DebugColors::SurfaceDamageRectBorderWidth();
break;
case SCREEN_SPACE_RECT_TYPE:
- stroke_color =
- DebugColors::ScreenSpaceLayerRectBorderColor().toSkColor();
- fill_color = DebugColors::ScreenSpaceLayerRectFillColor().toSkColor();
+ stroke_color = DebugColors::ScreenSpaceLayerRectBorderColor();
+ fill_color = DebugColors::ScreenSpaceLayerRectFillColor();
stroke_width = DebugColors::ScreenSpaceLayerRectBorderWidth();
break;
case TOUCH_EVENT_HANDLER_RECT_TYPE:
- stroke_color =
- DebugColors::TouchEventHandlerRectBorderColor().toSkColor();
- fill_color = DebugColors::TouchEventHandlerRectFillColor().toSkColor();
+ stroke_color = DebugColors::TouchEventHandlerRectBorderColor();
+ fill_color = DebugColors::TouchEventHandlerRectFillColor();
stroke_width = DebugColors::TouchEventHandlerRectBorderWidth();
label_text = "touch event listener: ";
label_text.append(TouchActionToString(debug_rects[i].touch_action));
break;
case WHEEL_EVENT_HANDLER_RECT_TYPE:
- stroke_color =
- DebugColors::WheelEventHandlerRectBorderColor().toSkColor();
- fill_color = DebugColors::WheelEventHandlerRectFillColor().toSkColor();
+ stroke_color = DebugColors::WheelEventHandlerRectBorderColor();
+ fill_color = DebugColors::WheelEventHandlerRectFillColor();
stroke_width = DebugColors::WheelEventHandlerRectBorderWidth();
label_text = "mousewheel event listener";
break;
case SCROLL_EVENT_HANDLER_RECT_TYPE:
- stroke_color =
- DebugColors::ScrollEventHandlerRectBorderColor().toSkColor();
- fill_color = DebugColors::ScrollEventHandlerRectFillColor().toSkColor();
+ stroke_color = DebugColors::ScrollEventHandlerRectBorderColor();
+ fill_color = DebugColors::ScrollEventHandlerRectFillColor();
stroke_width = DebugColors::ScrollEventHandlerRectBorderWidth();
label_text = "scroll event listener";
break;
case NON_FAST_SCROLLABLE_RECT_TYPE:
- stroke_color =
- DebugColors::NonFastScrollableRectBorderColor().toSkColor();
- fill_color = DebugColors::NonFastScrollableRectFillColor().toSkColor();
+ stroke_color = DebugColors::NonFastScrollableRectBorderColor();
+ fill_color = DebugColors::NonFastScrollableRectFillColor();
stroke_width = DebugColors::NonFastScrollableRectBorderWidth();
label_text = "repaints on scroll";
break;
case MAIN_THREAD_SCROLLING_REASON_RECT_TYPE:
- stroke_color =
- DebugColors::MainThreadScrollingReasonRectBorderColor().toSkColor();
- fill_color =
- DebugColors::MainThreadScrollingReasonRectFillColor().toSkColor();
+ stroke_color = DebugColors::MainThreadScrollingReasonRectBorderColor();
+ fill_color = DebugColors::MainThreadScrollingReasonRectFillColor();
stroke_width = DebugColors::MainThreadScrollingReasonRectBorderWidth();
label_text = "main thread scrolling: ";
label_text.append(base::ToLowerASCII(MainThreadScrollingReason::AsText(
debug_rects[i].main_thread_scrolling_reasons)));
break;
case ANIMATION_BOUNDS_RECT_TYPE:
- stroke_color =
- DebugColors::LayerAnimationBoundsBorderColor().toSkColor();
- fill_color = DebugColors::LayerAnimationBoundsFillColor().toSkColor();
+ stroke_color = DebugColors::LayerAnimationBoundsBorderColor();
+ fill_color = DebugColors::LayerAnimationBoundsFillColor();
stroke_width = DebugColors::LayerAnimationBoundsBorderWidth();
label_text = "animation bounds";
break;
@@ -1088,13 +1071,10 @@ void HeadsUpDisplayLayerImpl::DrawDebugRects(
if (paint_rects_fade_step_ > 0) {
paint_rects_fade_step_--;
for (auto& paint_rect : paint_rects_) {
- // TODO(crbug/1308932): Remove all instances of toSkColor below and make
- // all SkColor4f.
- DrawDebugRect(
- canvas, &flags, paint_rect,
- DebugColors::PaintRectBorderColor(paint_rects_fade_step_).toSkColor(),
- DebugColors::PaintRectFillColor(paint_rects_fade_step_).toSkColor(),
- DebugColors::PaintRectBorderWidth(), "");
+ DrawDebugRect(canvas, &flags, paint_rect,
+ DebugColors::PaintRectBorderColor(paint_rects_fade_step_),
+ DebugColors::PaintRectFillColor(paint_rects_fade_step_),
+ DebugColors::PaintRectBorderWidth(), "");
}
}
if (new_layout_shift_rects.size()) {
@@ -1108,9 +1088,8 @@ void HeadsUpDisplayLayerImpl::DrawDebugRects(
// all SkColor4f.
DrawDebugRect(
canvas, &flags, layout_shift_debug_rect,
- DebugColors::LayoutShiftRectBorderColor().toSkColor(),
- DebugColors::LayoutShiftRectFillColor(layout_shift_rects_fade_step_)
- .toSkColor(),
+ DebugColors::LayoutShiftRectBorderColor(),
+ DebugColors::LayoutShiftRectFillColor(layout_shift_rects_fade_step_),
DebugColors::LayoutShiftRectBorderWidth(), "");
}
}
@@ -1126,19 +1105,18 @@ int HeadsUpDisplayLayerImpl::DrawSingleMetric(
bool has_value,
double value) const {
std::string value_str = "-";
- // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
- SkColor metrics_color = DebugColors::HUDTitleColor().toSkColor();
- SkColor badge_color = SK_ColorGREEN;
+ SkColor4f metrics_color = DebugColors::HUDTitleColor();
+ SkColor4f badge_color = SkColors::kGreen;
if (has_value) {
value_str = ToStringTwoDecimalPrecision(value) + info.UnitToString();
if (value < info.green_threshold) {
- metrics_color = SK_ColorGREEN;
+ metrics_color = SkColors::kGreen;
} else if (value < info.yellow_threshold) {
- metrics_color = SK_ColorYELLOW;
- badge_color = SK_ColorYELLOW;
+ metrics_color = SkColors::kYellow;
+ badge_color = SkColors::kYellow;
} else {
- metrics_color = SK_ColorRED;
- badge_color = SK_ColorRED;
+ metrics_color = SkColors::kRed;
+ badge_color = SkColors::kRed;
}
}
@@ -1147,13 +1125,13 @@ int HeadsUpDisplayLayerImpl::DrawSingleMetric(
badge_flags.setColor(badge_color);
badge_flags.setStyle(PaintFlags::kFill_Style);
badge_flags.setAntiAlias(true);
- if (badge_color == SK_ColorGREEN) {
+ if (badge_color == SkColors::kGreen) {
constexpr int kRadius = 6;
int x = left + metrics_sizes.kSidePadding + kRadius;
int y = top - kRadius - 2;
SkPath circle = SkPath::Circle(x, y, kRadius);
canvas->drawPath(circle, badge_flags);
- } else if (badge_color == SK_ColorYELLOW) {
+ } else if (badge_color == SkColors::kYellow) {
constexpr int kSquareSize = 12;
int x = left + metrics_sizes.kSidePadding;
int y = top - kSquareSize - 2;
@@ -1175,8 +1153,7 @@ int HeadsUpDisplayLayerImpl::DrawSingleMetric(
// Draw the label and values of the metric.
PaintFlags flags;
- // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
- flags.setColor(DebugColors::HUDTitleColor().toSkColor());
+ flags.setColor(DebugColors::HUDTitleColor());
DrawText(canvas, flags, name, TextAlign::kLeft, metrics_sizes.kFontHeight,
left + metrics_sizes.kSidePadding + metrics_sizes.kBadgeWidth, top);
flags.setColor(metrics_color);
diff --git a/chromium/cc/layers/heads_up_display_layer_impl.h b/chromium/cc/layers/heads_up_display_layer_impl.h
index 6bc0fff3c4a..7762af57f1a 100644
--- a/chromium/cc/layers/heads_up_display_layer_impl.h
+++ b/chromium/cc/layers/heads_up_display_layer_impl.h
@@ -130,8 +130,8 @@ class CC_EXPORT HeadsUpDisplayLayerImpl : public LayerImpl {
void DrawDebugRect(PaintCanvas* canvas,
PaintFlags* flags,
const DebugRect& rect,
- SkColor stroke_color,
- SkColor fill_color,
+ SkColor4f stroke_color,
+ SkColor4f fill_color,
float stroke_width,
const std::string& label_text) const;
void DrawDebugRects(PaintCanvas* canvas,
diff --git a/chromium/cc/layers/layer.cc b/chromium/cc/layers/layer.cc
index 7e9dd9f6e9b..eda9833edb1 100644
--- a/chromium/cc/layers/layer.cc
+++ b/chromium/cc/layers/layer.cc
@@ -546,10 +546,9 @@ void Layer::SetSafeOpaqueBackgroundColor(SkColor4f background_color) {
SetNeedsPushProperties();
}
-SkColor4f Layer::SafeOpaqueBackgroundColor(
- SkColor4f host_background_color) const {
+SkColor4f Layer::SafeOpaqueBackgroundColor() const {
if (contents_opaque()) {
- if (!IsAttached() || !IsUsingLayerLists()) {
+ if (!IsUsingLayerLists()) {
// In layer tree mode, PropertyTreeBuilder should have calculated the safe
// opaque background color and called SetSafeOpaqueBackgroundColor().
DCHECK(layer_tree_inputs());
@@ -558,12 +557,8 @@ SkColor4f Layer::SafeOpaqueBackgroundColor(
}
// In layer list mode, the PropertyTreeBuilder algorithm doesn't apply
// because it depends on the layer tree hierarchy. Instead we use
- // background_color() if it's not transparent, or layer_tree_host_'s
- // background_color(), with the alpha channel forced to be opaque.
- SkColor4f color = background_color() == SkColors::kTransparent
- ? host_background_color
- : background_color();
- return color.makeOpaque();
+ // background_color() made opaque.
+ return background_color().makeOpaque();
}
if (background_color().isOpaque()) {
// The layer is not opaque while the background color is, meaning that the
@@ -575,16 +570,6 @@ SkColor4f Layer::SafeOpaqueBackgroundColor(
return background_color();
}
-SkColor4f Layer::SafeOpaqueBackgroundColor() const {
- // TODO(crbug/1308932): Remove FromColor and make all SkColor4f.
- SkColor4f host_background_color =
- IsAttached()
- ? SkColor4f::FromColor(
- layer_tree_host()->pending_commit_state()->background_color)
- : layer_tree_inputs()->safe_opaque_background_color;
- return SafeOpaqueBackgroundColor(host_background_color);
-}
-
void Layer::SetMasksToBounds(bool masks_to_bounds) {
DCHECK(IsPropertyChangeAllowed());
auto& inputs = EnsureLayerTreeInputs();
@@ -1469,9 +1454,7 @@ void Layer::PushPropertiesTo(LayerImpl* layer,
layer->SetElementId(inputs.element_id);
layer->SetHasTransformNode(has_transform_node());
layer->SetBackgroundColor(inputs.background_color);
- // TODO(crbug/1308932): Remove FromColor and make all SkColor4f.
- layer->SetSafeOpaqueBackgroundColor(SafeOpaqueBackgroundColor(
- SkColor4f::FromColor(commit_state.background_color)));
+ layer->SetSafeOpaqueBackgroundColor(SafeOpaqueBackgroundColor());
layer->SetBounds(inputs.bounds);
layer->SetTransformTreeIndex(transform_tree_index(property_trees));
layer->SetEffectTreeIndex(effect_tree_index(property_trees));
diff --git a/chromium/cc/layers/layer.h b/chromium/cc/layers/layer.h
index 588cecfa2a0..86870398556 100644
--- a/chromium/cc/layers/layer.h
+++ b/chromium/cc/layers/layer.h
@@ -169,8 +169,9 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
return layer_tree_inputs() && !layer_tree_inputs()->copy_requests.empty();
}
- // Set and get the background color for the layer. This color is not used by
- // basic Layers, but subclasses may make use of it.
+ // Set and get the background color for the layer. This color is used to
+ // calculate the safe opaque background color. Subclasses may also use the
+ // color for other purposes.
virtual void SetBackgroundColor(SkColor4f background_color);
SkColor4f background_color() const {
return inputs_.Read(*this).background_color;
@@ -185,17 +186,14 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
// contents_opaque().
// If the layer says contents_opaque() is true, in layer tree mode, this
// returns the value set by SetSafeOpaqueBackgroundColor() which should be an
- // opaque color, and in layer list mode, returns an opaque color calculated
- // from background_color() and the argument host_background_color.
+ // opaque color, and in layer list mode, returns background_color() which
+ // should be opaque (otherwise SetBackgroundColor() should have set
+ // contents_opaque to false).
// Otherwise, it returns something non-opaque. It prefers to return the
// background_color(), but if the background_color() is opaque (and this layer
// claims to not be), then SkColors::kTransparent is returned to avoid
// intrusive checkerboard where the layer is not covered by the
// background_color().
- SkColor4f SafeOpaqueBackgroundColor(SkColor4f host_background_color) const;
-
- // Same as the one-argument version, except that host_background_color is
- // layer_tree_host()->pending_commit_state()->background_color.
SkColor4f SafeOpaqueBackgroundColor() const;
// For layer tree mode only.
@@ -722,7 +720,7 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
// Internal method to be overridden by Layer subclasses that need to do work
// during a main frame. The method should compute any state that will need to
- // propogated to the compositor thread for the next commit, and return true
+ // propagated to the compositor thread for the next commit, and return true
// if there is anything new to commit. If all layers return false, the commit
// may be aborted.
virtual bool Update();
diff --git a/chromium/cc/layers/layer_impl.cc b/chromium/cc/layers/layer_impl.cc
index 1e9e856c2da..138ca367425 100644
--- a/chromium/cc/layers/layer_impl.cc
+++ b/chromium/cc/layers/layer_impl.cc
@@ -273,15 +273,14 @@ void LayerImpl::AppendDebugBorderQuad(
gfx::Rect visible_quad_rect(quad_rect);
auto* debug_border_quad =
render_pass->CreateAndAppendDrawQuad<viz::DebugBorderDrawQuad>();
- // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
debug_border_quad->SetNew(shared_quad_state, quad_rect, visible_quad_rect,
- color.toSkColor(), width);
+ color, width);
if (contents_opaque()) {
// When opaque, draw a second inner border that is thicker than the outer
// border, but more transparent.
static const float kFillOpacity = 0.3f;
SkColor4f fill_color = color;
- color.fA *= kFillOpacity;
+ fill_color.fA *= kFillOpacity;
float fill_width = width * 3;
gfx::Rect fill_rect = quad_rect;
fill_rect.Inset(fill_width / 2.f);
@@ -289,11 +288,10 @@ void LayerImpl::AppendDebugBorderQuad(
return;
gfx::Rect visible_fill_rect =
gfx::IntersectRects(visible_quad_rect, fill_rect);
- // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
auto* fill_quad =
render_pass->CreateAndAppendDrawQuad<viz::DebugBorderDrawQuad>();
fill_quad->SetNew(shared_quad_state, fill_rect, visible_fill_rect,
- fill_color.toSkColor(), fill_width);
+ fill_color, fill_width);
}
}
diff --git a/chromium/cc/layers/layer_impl_unittest.cc b/chromium/cc/layers/layer_impl_unittest.cc
index 095e57d61a4..eb85e3a7313 100644
--- a/chromium/cc/layers/layer_impl_unittest.cc
+++ b/chromium/cc/layers/layer_impl_unittest.cc
@@ -417,7 +417,8 @@ TEST_F(LayerImplScrollTest, ApplySentScrollsNoListener) {
scroll_tree(layer())->GetScrollOffsetBaseForTesting(
layer()->element_id()));
- scroll_tree(layer())->ApplySentScrollDeltasFromAbortedCommit();
+ scroll_tree(layer())->ApplySentScrollDeltasFromAbortedCommit(
+ /*main_frame_applied_deltas=*/true);
EXPECT_POINTF_EQ(scroll_offset + scroll_delta, CurrentScrollOffset(layer()));
EXPECT_VECTOR2DF_EQ(scroll_delta - sent_scroll_delta, ScrollDelta(layer()));
diff --git a/chromium/cc/layers/layer_unittest.cc b/chromium/cc/layers/layer_unittest.cc
index e822609d136..e2798ca1bd1 100644
--- a/chromium/cc/layers/layer_unittest.cc
+++ b/chromium/cc/layers/layer_unittest.cc
@@ -1402,7 +1402,7 @@ TEST_F(LayerTest, SafeOpaqueBackgroundColor) {
layer->SetBackgroundColor(layer_opaque ? SkColors::kRed
: SkColors::kTransparent);
layer_tree_host->set_background_color(
- host_opaque ? SK_ColorRED : SK_ColorTRANSPARENT);
+ host_opaque ? SkColors::kRed : SkColors::kTransparent);
layer_tree_host->property_trees()->set_needs_rebuild(true);
layer_tree_host->BuildPropertyTreesForTesting();
diff --git a/chromium/cc/layers/nine_patch_generator.cc b/chromium/cc/layers/nine_patch_generator.cc
index 7f8b7e33590..a2b627e563d 100644
--- a/chromium/cc/layers/nine_patch_generator.cc
+++ b/chromium/cc/layers/nine_patch_generator.cc
@@ -361,7 +361,7 @@ void NinePatchGenerator::AppendQuads(LayerImpl* layer_impl,
auto* quad = render_pass->CreateAndAppendDrawQuad<viz::TextureDrawQuad>();
quad->SetNew(shared_quad_state, output_rect, visible_rect, needs_blending,
resource, premultiplied_alpha, image_rect.origin(),
- image_rect.bottom_right(), SK_ColorTRANSPARENT,
+ image_rect.bottom_right(), SkColors::kTransparent,
vertex_opacity, flipped, nearest_neighbor_,
/*secure_output_only=*/false,
gfx::ProtectedVideoType::kClear);
diff --git a/chromium/cc/layers/painted_overlay_scrollbar_layer.cc b/chromium/cc/layers/painted_overlay_scrollbar_layer.cc
index 33ff15fb04b..7fd89fc5386 100644
--- a/chromium/cc/layers/painted_overlay_scrollbar_layer.cc
+++ b/chromium/cc/layers/painted_overlay_scrollbar_layer.cc
@@ -155,7 +155,7 @@ bool PaintedOverlayScrollbarLayer::PaintThumbIfNeeded() {
SkBitmap skbitmap;
skbitmap.allocN32Pixels(paint_size.width(), paint_size.height());
SkiaPaintCanvas canvas(skbitmap);
- canvas.clear(SK_ColorTRANSPARENT);
+ canvas.clear(SkColors::kTransparent);
scrollbar->PaintPart(&canvas, ScrollbarPart::THUMB, gfx::Rect(paint_size));
// Make sure that the pixels are no longer mutable to unavoid unnecessary
@@ -188,7 +188,7 @@ bool PaintedOverlayScrollbarLayer::PaintTickmarks() {
SkBitmap skbitmap;
skbitmap.allocN32Pixels(paint_size.width(), paint_size.height());
SkiaPaintCanvas canvas(skbitmap);
- canvas.clear(SK_ColorTRANSPARENT);
+ canvas.clear(SkColors::kTransparent);
scrollbar_.Write(*this)->PaintPart(
&canvas, ScrollbarPart::TRACK_BUTTONS_TICKMARKS, gfx::Rect(paint_size));
diff --git a/chromium/cc/layers/painted_overlay_scrollbar_layer_impl.cc b/chromium/cc/layers/painted_overlay_scrollbar_layer_impl.cc
index efa31ec9e4e..0cb95310ac2 100644
--- a/chromium/cc/layers/painted_overlay_scrollbar_layer_impl.cc
+++ b/chromium/cc/layers/painted_overlay_scrollbar_layer_impl.cc
@@ -162,11 +162,12 @@ void PaintedOverlayScrollbarLayerImpl::AppendTrackQuads(
float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
viz::TextureDrawQuad* quad =
render_pass->CreateAndAppendDrawQuad<viz::TextureDrawQuad>();
- quad->SetNew(
- shared_quad_state, scaled_track_quad_rect, scaled_visible_track_quad_rect,
- needs_blending, track_resource_id, premultipled_alpha, uv_top_left,
- uv_bottom_right, SK_ColorTRANSPARENT, opacity, flipped, nearest_neighbor,
- /*secure_output_only=*/false, gfx::ProtectedVideoType::kClear);
+ quad->SetNew(shared_quad_state, scaled_track_quad_rect,
+ scaled_visible_track_quad_rect, needs_blending,
+ track_resource_id, premultipled_alpha, uv_top_left,
+ uv_bottom_right, SkColors::kTransparent, opacity, flipped,
+ nearest_neighbor,
+ /*secure_output_only=*/false, gfx::ProtectedVideoType::kClear);
ValidateQuadResources(quad);
}
diff --git a/chromium/cc/layers/painted_scrollbar_layer.cc b/chromium/cc/layers/painted_scrollbar_layer.cc
index fb570bf43a0..ca107ea2712 100644
--- a/chromium/cc/layers/painted_scrollbar_layer.cc
+++ b/chromium/cc/layers/painted_scrollbar_layer.cc
@@ -256,7 +256,7 @@ UIResourceBitmap PaintedScrollbarLayer::RasterizeScrollbarPart(
<< "Failed to allocate memory for scrollbar at dimension : " << dimension;
SkiaPaintCanvas canvas(skbitmap);
- canvas.clear(SK_ColorTRANSPARENT);
+ canvas.clear(SkColors::kTransparent);
float scale_x = content_size.width() / static_cast<float>(size.width());
float scale_y = content_size.height() / static_cast<float>(size.height());
diff --git a/chromium/cc/layers/painted_scrollbar_layer_impl.cc b/chromium/cc/layers/painted_scrollbar_layer_impl.cc
index 63ac939b34a..3fffa290a18 100644
--- a/chromium/cc/layers/painted_scrollbar_layer_impl.cc
+++ b/chromium/cc/layers/painted_scrollbar_layer_impl.cc
@@ -130,7 +130,7 @@ void PaintedScrollbarLayerImpl::AppendQuads(
quad->SetNew(shared_quad_state, scaled_thumb_quad_rect,
scaled_visible_thumb_quad_rect, needs_blending,
thumb_resource_id, premultipled_alpha, uv_top_left,
- uv_bottom_right, SK_ColorTRANSPARENT, opacity, flipped,
+ uv_bottom_right, SkColors::kTransparent, opacity, flipped,
nearest_neighbor, /*secure_output_only=*/false,
gfx::ProtectedVideoType::kClear);
ValidateQuadResources(quad);
@@ -150,7 +150,7 @@ void PaintedScrollbarLayerImpl::AppendQuads(
quad->SetNew(shared_quad_state, scaled_track_quad_rect,
scaled_visible_track_quad_rect, needs_blending,
track_resource_id, premultipled_alpha, uv_top_left,
- uv_bottom_right, SK_ColorTRANSPARENT, opacity, flipped,
+ uv_bottom_right, SkColors::kTransparent, opacity, flipped,
nearest_neighbor, /*secure_output_only=*/false,
gfx::ProtectedVideoType::kClear);
ValidateQuadResources(quad);
diff --git a/chromium/cc/layers/picture_layer_impl.cc b/chromium/cc/layers/picture_layer_impl.cc
index 39e68be28b6..11be1253895 100644
--- a/chromium/cc/layers/picture_layer_impl.cc
+++ b/chromium/cc/layers/picture_layer_impl.cc
@@ -230,10 +230,9 @@ void PictureLayerImpl::AppendQuads(viz::CompositorRenderPass* render_pass,
Occlusion occlusion = draw_properties().occlusion_in_content_space;
EffectNode* effect_node = GetEffectTree().Node(effect_tree_index());
- // TODO(crbug/1308932): Remove FromColor and make all SkColor4f.
SolidColorLayerImpl::AppendSolidQuads(
render_pass, occlusion, shared_quad_state, scaled_visible_layer_rect,
- SkColor4f::FromColor(raster_source_->GetSolidColor()),
+ raster_source_->GetSolidColor(),
!layer_tree_impl()->settings().enable_edge_anti_aliasing,
effect_node->blend_mode, append_quads_data);
return;
@@ -400,24 +399,20 @@ void PictureLayerImpl::AppendQuads(viz::CompositorRenderPass* render_pass,
gfx::Rect geometry_rect = iter.geometry_rect();
geometry_rect.Offset(quad_offset);
gfx::Rect visible_geometry_rect = geometry_rect;
- // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
debug_border_quad->SetNew(shared_quad_state, geometry_rect,
- visible_geometry_rect, color.toSkColor(),
- width);
+ visible_geometry_rect, color, width);
}
}
if (layer_tree_impl()->debug_state().highlight_non_lcd_text_layers) {
- // TODO(crbug/1308932): Remove all instances of toSkColor below and make all
- // SkColor4f.
SkColor4f color =
DebugColors::NonLCDTextHighlightColor(lcd_text_disallowed_reason());
if (color != SkColors::kTransparent &&
GetRasterSource()->GetDisplayItemList()->AreaOfDrawText(
gfx::Rect(bounds()))) {
render_pass->CreateAndAppendDrawQuad<viz::SolidColorDrawQuad>()->SetNew(
- shared_quad_state, debug_border_rect, debug_border_rect,
- color.toSkColor(), append_quads_data);
+ shared_quad_state, debug_border_rect, debug_border_rect, color,
+ append_quads_data);
}
}
@@ -493,9 +488,7 @@ void PictureLayerImpl::AppendQuads(viz::CompositorRenderPass* render_pass,
break;
}
case TileDrawInfo::SOLID_COLOR_MODE: {
- float alpha =
- (SkColorGetA(draw_info.solid_color()) * (1.0f / 255.0f)) *
- shared_quad_state->opacity;
+ float alpha = draw_info.solid_color().fA * shared_quad_state->opacity;
if (alpha >= std::numeric_limits<float>::epsilon()) {
auto* quad =
render_pass->CreateAndAppendDrawQuad<viz::SolidColorDrawQuad>();
@@ -522,9 +515,8 @@ void PictureLayerImpl::AppendQuads(viz::CompositorRenderPass* render_pass,
}
auto* quad =
render_pass->CreateAndAppendDrawQuad<viz::SolidColorDrawQuad>();
- // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
quad->SetNew(shared_quad_state, offset_geometry_rect,
- offset_visible_geometry_rect, color.toSkColor(), false);
+ offset_visible_geometry_rect, color, false);
ValidateQuadResources(quad);
if (geometry_rect.Intersects(scaled_viewport_for_tile_priority)) {
@@ -547,6 +539,14 @@ void PictureLayerImpl::AppendQuads(viz::CompositorRenderPass* render_pass,
append_quads_data->checkerboarded_no_recording_content_area +=
visible_geometry_area - checkerboarded_has_recording_area;
+ // Report data on any missing images that might be the largest
+ // contentful image.
+ if (*iter) {
+ UMA_HISTOGRAM_BOOLEAN(
+ "Compositing.DecodeLCPCandidateImage.MissedDeadline",
+ iter->HasMissingLCPCandidateImages());
+ }
+
continue;
}
@@ -1249,6 +1249,10 @@ bool PictureLayerImpl::CanRecreateHighResTilingForLCDTextAndRasterTransform(
// will be deleted.
if (layer_tree_impl()->IsSyncTree() && layer_tree_impl()->IsReadyToActivate())
return false;
+ // To reduce memory usage, don't recreate highres tiling during scroll
+ if (ScrollInteractionInProgress())
+ return false;
+
return true;
}
diff --git a/chromium/cc/layers/picture_layer_impl_unittest.cc b/chromium/cc/layers/picture_layer_impl_unittest.cc
index ba9a96637b4..2f8c8ee5fe8 100644
--- a/chromium/cc/layers/picture_layer_impl_unittest.cc
+++ b/chromium/cc/layers/picture_layer_impl_unittest.cc
@@ -1722,7 +1722,7 @@ TEST_F(LegacySWPictureLayerImplTest, FarScrolledSolidColorQuadsShifted) {
ASSERT_GT(tiles.size(), 0u);
for (auto* tile : tiles)
- tile->draw_info().SetSolidColorForTesting(SK_ColorBLUE);
+ tile->draw_info().SetSolidColorForTesting(SkColors::kBlue);
AppendQuadsData data;
active_layer()->WillDraw(DRAW_MODE_HARDWARE, nullptr);
@@ -1917,7 +1917,7 @@ TEST_F(NoLowResPictureLayerImplTest,
num_inside++;
// Mark everything in viewport for tile priority as ready to draw.
TileDrawInfo& draw_info = tile->draw_info();
- draw_info.SetSolidColorForTesting(SK_ColorRED);
+ draw_info.SetSolidColorForTesting(SkColors::kRed);
} else {
num_outside++;
EXPECT_FALSE(tile->required_for_activation());
@@ -3371,7 +3371,7 @@ TEST_F(LegacySWPictureLayerImplTest, TilingSetRasterQueue) {
++tile_it) {
Tile* tile = *tile_it;
TileDrawInfo& draw_info = tile->draw_info();
- draw_info.SetSolidColorForTesting(SK_ColorRED);
+ draw_info.SetSolidColorForTesting(SkColors::kRed);
}
queue = std::make_unique<TilingSetRasterQueueAll>(
@@ -4960,7 +4960,7 @@ void PictureLayerImplTest::TestQuadsForSolidColor(bool test_for_solid,
for (auto it = tiles.begin(); it != tiles.end(); ++it, ++i) {
if (i < 5) {
TileDrawInfo& draw_info = (*it)->draw_info();
- draw_info.SetSolidColorForTesting(0);
+ draw_info.SetSolidColorForTesting(SkColors::kTransparent);
} else {
resource_tiles.push_back(*it);
}
diff --git a/chromium/cc/layers/picture_layer_unittest.cc b/chromium/cc/layers/picture_layer_unittest.cc
index 986784742ad..93474da9d80 100644
--- a/chromium/cc/layers/picture_layer_unittest.cc
+++ b/chromium/cc/layers/picture_layer_unittest.cc
@@ -401,14 +401,14 @@ TEST(PictureLayerTest, RecordingScaleIsCorrectlySet) {
client.set_bounds(layer_bounds);
// Fill layer with solid color.
PaintFlags solid_flags;
- SkColor solid_color = SkColorSetARGB(255, 12, 23, 34);
+ SkColor4f solid_color{0.1f, 0.15f, 0.2f, 1.0f};
solid_flags.setColor(solid_color);
client.add_draw_rect(
gfx::ScaleToEnclosingRect(gfx::Rect(layer_bounds), recording_scale),
solid_flags);
// Add 1 pixel of non solid color.
- SkColor non_solid_color = SkColorSetARGB(128, 45, 56, 67);
+ SkColor4f non_solid_color{0.25f, 0.3f, 0.35f, 0.5f};
PaintFlags non_solid_flags;
non_solid_flags.setColor(non_solid_color);
client.add_draw_rect(gfx::Rect(std::round(390 * recording_scale),
@@ -444,7 +444,7 @@ TEST(PictureLayerTest, RecordingScaleIsCorrectlySet) {
layer->SetNeedsDisplayRect(invalidation_bounds);
layer->Update();
- // Once the recording scale is set and propogated to the recording source,
+ // Once the recording scale is set and propagated to the recording source,
// the solid color analysis should work as expected and return false.
EXPECT_FALSE(recording_source->is_solid_color());
}
diff --git a/chromium/cc/layers/recording_source_unittest.cc b/chromium/cc/layers/recording_source_unittest.cc
index b3ddae76a0c..11869bb0a08 100644
--- a/chromium/cc/layers/recording_source_unittest.cc
+++ b/chromium/cc/layers/recording_source_unittest.cc
@@ -336,10 +336,10 @@ TEST(RecordingSourceTest, AnalyzeIsSolid) {
recording_source->SetRecordingScaleFactor(recording_scale);
PaintFlags solid_flags;
- SkColor solid_color = SkColorSetARGB(255, 12, 23, 34);
+ SkColor4f solid_color{0.1f, 0.2f, 0.3f, 1.0f};
solid_flags.setColor(solid_color);
- SkColor non_solid_color = SkColorSetARGB(128, 45, 56, 67);
+ SkColor4f non_solid_color{0.2f, 0.3f, 0.4f, 0.5f};
PaintFlags non_solid_flags;
non_solid_flags.setColor(non_solid_color);
diff --git a/chromium/cc/layers/render_surface_impl.cc b/chromium/cc/layers/render_surface_impl.cc
index d274baf743c..01d48a8b513 100644
--- a/chromium/cc/layers/render_surface_impl.cc
+++ b/chromium/cc/layers/render_surface_impl.cc
@@ -110,9 +110,8 @@ SkBlendMode RenderSurfaceImpl::BlendMode() const {
return OwningEffectNode()->blend_mode;
}
-SkColor RenderSurfaceImpl::GetDebugBorderColor() const {
- // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
- return DebugColors::SurfaceBorderColor().toSkColor();
+SkColor4f RenderSurfaceImpl::GetDebugBorderColor() const {
+ return DebugColors::SurfaceBorderColor();
}
float RenderSurfaceImpl::GetDebugBorderWidth() const {
diff --git a/chromium/cc/layers/render_surface_impl.h b/chromium/cc/layers/render_surface_impl.h
index 057cf802842..f7a26dca966 100644
--- a/chromium/cc/layers/render_surface_impl.h
+++ b/chromium/cc/layers/render_surface_impl.h
@@ -90,7 +90,7 @@ class CC_EXPORT RenderSurfaceImpl {
return nearest_occlusion_immune_ancestor_;
}
- SkColor GetDebugBorderColor() const;
+ SkColor4f GetDebugBorderColor() const;
float GetDebugBorderWidth() const;
void SetDrawTransform(const gfx::Transform& draw_transform) {
diff --git a/chromium/cc/layers/solid_color_layer_impl.cc b/chromium/cc/layers/solid_color_layer_impl.cc
index 7e6332cf236..d2e8930c832 100644
--- a/chromium/cc/layers/solid_color_layer_impl.cc
+++ b/chromium/cc/layers/solid_color_layer_impl.cc
@@ -57,9 +57,8 @@ void SolidColorLayerImpl::AppendSolidQuads(
return;
auto* quad = render_pass->CreateAndAppendDrawQuad<viz::SolidColorDrawQuad>();
- // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
- quad->SetNew(shared_quad_state, visible_layer_rect, visible_quad_rect,
- color.toSkColor(), force_anti_aliasing_off);
+ quad->SetNew(shared_quad_state, visible_layer_rect, visible_quad_rect, color,
+ force_anti_aliasing_off);
}
void SolidColorLayerImpl::AppendQuads(viz::CompositorRenderPass* render_pass,
diff --git a/chromium/cc/layers/solid_color_scrollbar_layer_impl.cc b/chromium/cc/layers/solid_color_scrollbar_layer_impl.cc
index f1b8b88edf3..7494659d3d9 100644
--- a/chromium/cc/layers/solid_color_scrollbar_layer_impl.cc
+++ b/chromium/cc/layers/solid_color_scrollbar_layer_impl.cc
@@ -50,9 +50,7 @@ SolidColorScrollbarLayerImpl::SolidColorScrollbarLayerImpl(
/*is_overlay*/ true),
thumb_thickness_(thumb_thickness),
track_start_(track_start),
- // TODO(crbug/1308932): Remove FromColor and make all SkColor4f.
- color_(SkColor4f::FromColor(
- tree_impl->settings().solid_color_scrollbar_color)) {}
+ color_(tree_impl->settings().solid_color_scrollbar_color) {}
void SolidColorScrollbarLayerImpl::PushPropertiesTo(LayerImpl* layer) {
ScrollbarLayerImplBase::PushPropertiesTo(layer);
@@ -108,9 +106,8 @@ void SolidColorScrollbarLayerImpl::AppendQuads(
return;
auto* quad = render_pass->CreateAndAppendDrawQuad<viz::SolidColorDrawQuad>();
- // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
- quad->SetNew(shared_quad_state, thumb_quad_rect, visible_quad_rect,
- color_.toSkColor(), false);
+ quad->SetNew(shared_quad_state, thumb_quad_rect, visible_quad_rect, color_,
+ false);
}
const char* SolidColorScrollbarLayerImpl::LayerTypeAsString() const {
diff --git a/chromium/cc/layers/surface_layer_impl.cc b/chromium/cc/layers/surface_layer_impl.cc
index c3050488efb..6727217d03c 100644
--- a/chromium/cc/layers/surface_layer_impl.cc
+++ b/chromium/cc/layers/surface_layer_impl.cc
@@ -182,9 +182,8 @@ void SurfaceLayerImpl::AppendQuads(viz::CompositorRenderPass* render_pass,
if (surface_range_.IsValid()) {
auto* quad = render_pass->CreateAndAppendDrawQuad<viz::SurfaceDrawQuad>();
- // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
quad->SetNew(shared_quad_state, quad_rect, visible_quad_rect,
- surface_range_, background_color().toSkColor(),
+ surface_range_, background_color(),
stretch_content_to_fill_bounds_);
quad->is_reflection = is_reflection_;
// Add the primary surface ID as a dependency.
@@ -200,10 +199,8 @@ void SurfaceLayerImpl::AppendQuads(viz::CompositorRenderPass* render_pass,
} else {
auto* quad =
render_pass->CreateAndAppendDrawQuad<viz::SolidColorDrawQuad>();
- // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
quad->SetNew(shared_quad_state, quad_rect, visible_quad_rect,
- background_color().toSkColor(),
- false /* force_anti_aliasing_off */);
+ background_color(), false /* force_anti_aliasing_off */);
}
// Unless the client explicitly specifies otherwise, don't block on
@@ -222,9 +219,11 @@ gfx::Rect SurfaceLayerImpl::GetEnclosingVisibleRectInTargetSpace() const {
void SurfaceLayerImpl::GetDebugBorderProperties(SkColor4f* color,
float* width) const {
- *color = DebugColors::SurfaceLayerBorderColor();
- *width = DebugColors::SurfaceLayerBorderWidth(
- layer_tree_impl() ? layer_tree_impl()->device_scale_factor() : 1);
+ if (color)
+ *color = DebugColors::SurfaceLayerBorderColor();
+ if (width)
+ *width = DebugColors::SurfaceLayerBorderWidth(
+ layer_tree_impl() ? layer_tree_impl()->device_scale_factor() : 1);
}
void SurfaceLayerImpl::AppendRainbowDebugBorder(
@@ -236,17 +235,16 @@ void SurfaceLayerImpl::AppendRainbowDebugBorder(
render_pass->CreateAndAppendSharedQuadState();
PopulateSharedQuadState(shared_quad_state, contents_opaque());
- SkColor4f color;
- float border_width;
- GetDebugBorderProperties(&color, &border_width);
-
- SkColor colors[] = {
- 0x80ff0000, // Red.
- 0x80ffa500, // Orange.
- 0x80ffff00, // Yellow.
- 0x80008000, // Green.
- 0x800000ff, // Blue.
- 0x80ee82ee, // Violet.
+ float border_width = DebugColors::SurfaceLayerBorderWidth(
+ layer_tree_impl() ? layer_tree_impl()->device_scale_factor() : 1);
+
+ SkColor4f colors[] = {
+ {1.0f, 0.0f, 0.0f, 0.5f}, // Red.
+ {1.0f, 0.65f, 0.0f, 0.5f}, // Orange.
+ {1.0f, 1.0f, 0.0f, 0.5f}, // Yellow.
+ {0.0f, 0.5f, 0.0f, 0.5f}, // Green.
+ {0.0f, 0.0f, 1.0f, 0.50f}, // Blue.
+ {0.93f, 0.51f, 0.93f, 0.5f}, // Violet.
};
const int kNumColors = std::size(colors);
@@ -290,10 +288,8 @@ void SurfaceLayerImpl::AppendRainbowDebugBorder(
render_pass->CreateAndAppendDrawQuad<viz::SolidColorDrawQuad>();
// The inner fill is more transparent then the border.
static const float kFillOpacity = 0.1f;
- SkColor fill_color = SkColorSetA(
- colors[i % kNumColors],
- static_cast<uint8_t>(SkColorGetA(colors[i % kNumColors]) *
- kFillOpacity));
+ SkColor4f fill_color = colors[i % kNumColors];
+ fill_color.fA *= kFillOpacity;
gfx::Rect fill_rect(x, 0, width, bounds().height());
solid_quad->SetNew(shared_quad_state, fill_rect, fill_rect, fill_color,
force_anti_aliasing_off);
diff --git a/chromium/cc/layers/texture_layer_impl.cc b/chromium/cc/layers/texture_layer_impl.cc
index a41414dbaf3..1e60781504a 100644
--- a/chromium/cc/layers/texture_layer_impl.cc
+++ b/chromium/cc/layers/texture_layer_impl.cc
@@ -147,11 +147,10 @@ void TextureLayerImpl::AppendQuads(viz::CompositorRenderPass* render_pass,
return;
float vertex_opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
- // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
auto* quad = render_pass->CreateAndAppendDrawQuad<viz::TextureDrawQuad>();
quad->SetNew(shared_quad_state, quad_rect, visible_quad_rect, needs_blending,
resource_id_, premultiplied_alpha_, uv_top_left_,
- uv_bottom_right_, bg_color.toSkColor(), vertex_opacity, flipped_,
+ uv_bottom_right_, bg_color, vertex_opacity, flipped_,
nearest_neighbor_, /*secure_output=*/false,
gfx::ProtectedVideoType::kClear);
quad->set_resource_size_in_pixels(transferable_resource_.size);
diff --git a/chromium/cc/layers/ui_resource_layer_impl.cc b/chromium/cc/layers/ui_resource_layer_impl.cc
index 9688bb7a45f..557bf8a0b9c 100644
--- a/chromium/cc/layers/ui_resource_layer_impl.cc
+++ b/chromium/cc/layers/ui_resource_layer_impl.cc
@@ -130,7 +130,8 @@ void UIResourceLayerImpl::AppendQuads(viz::CompositorRenderPass* render_pass,
auto* quad = render_pass->CreateAndAppendDrawQuad<viz::TextureDrawQuad>();
quad->SetNew(shared_quad_state, quad_rect, visible_quad_rect, needs_blending,
resource, premultiplied_alpha, uv_top_left_, uv_bottom_right_,
- SK_ColorTRANSPARENT, vertex_opacity_, flipped, nearest_neighbor,
+ SkColors::kTransparent, vertex_opacity_, flipped,
+ nearest_neighbor,
/*secure_output_only=*/false, gfx::ProtectedVideoType::kClear);
ValidateQuadResources(quad);
}
diff --git a/chromium/cc/layers/ui_resource_layer_unittest.cc b/chromium/cc/layers/ui_resource_layer_unittest.cc
index 88569c18c47..bb9f09ecad1 100644
--- a/chromium/cc/layers/ui_resource_layer_unittest.cc
+++ b/chromium/cc/layers/ui_resource_layer_unittest.cc
@@ -7,6 +7,7 @@
#include "base/threading/thread_task_runner_handle.h"
#include "cc/animation/animation_host.h"
#include "cc/resources/scoped_ui_resource.h"
+#include "cc/resources/ui_resource_manager.h"
#include "cc/test/fake_layer_tree_host.h"
#include "cc/test/layer_tree_impl_test_base.h"
#include "cc/test/stub_layer_tree_host_single_thread_client.h"
@@ -192,5 +193,37 @@ TEST_F(UIResourceLayerTest, SharedBitmap) {
EXPECT_EQ(other_lth_resource_id, layer1->resource_id());
}
+TEST_F(UIResourceLayerTest, SharedBitmapCacheSizeLimit) {
+ scoped_refptr<TestUIResourceLayer> layer = TestUIResourceLayer::Create();
+ layer_tree_host()->SetRootLayer(layer);
+
+ // Number of bitmaps that are created then get their references dropped.
+ constexpr size_t kDroppedResources = 100u;
+
+ // Populate the shared bitmap cache.
+ auto* manager = layer_tree_host()->GetUIResourceManager();
+ while (manager->owned_shared_resources_size_for_test() < kDroppedResources) {
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(10, 10);
+ bitmap.setImmutable();
+ layer->SetBitmap(bitmap);
+ }
+
+ // No eviction because bitmaps are references by UIResourcesRequests.
+ EXPECT_EQ(manager->owned_shared_resources_size_for_test(), kDroppedResources);
+
+ // Pretend UIResourcesRequests are processed to drop bitmap references.
+ manager->TakeUIResourcesRequests();
+
+ // Create one more shared bitmap resource and the eviction happens.
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(10, 10);
+ bitmap.setImmutable();
+ layer->SetBitmap(bitmap);
+
+ // The cache should trimmed down.
+ EXPECT_EQ(manager->owned_shared_resources_size_for_test(), 1u);
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/layers/video_layer_impl.cc b/chromium/cc/layers/video_layer_impl.cc
index 91872c8cee7..c0b9ce25c85 100644
--- a/chromium/cc/layers/video_layer_impl.cc
+++ b/chromium/cc/layers/video_layer_impl.cc
@@ -19,7 +19,6 @@
#include "cc/trees/occlusion.h"
#include "cc/trees/task_runner_provider.h"
#include "components/viz/client/client_resource_provider.h"
-#include "components/viz/common/quads/stream_video_draw_quad.h"
#include "components/viz/common/quads/texture_draw_quad.h"
#include "components/viz/common/quads/yuv_video_draw_quad.h"
#include "media/base/video_frame.h"
diff --git a/chromium/cc/layers/video_layer_impl_unittest.cc b/chromium/cc/layers/video_layer_impl_unittest.cc
index 6a205ea443b..dd0e14e4db0 100644
--- a/chromium/cc/layers/video_layer_impl_unittest.cc
+++ b/chromium/cc/layers/video_layer_impl_unittest.cc
@@ -13,7 +13,6 @@
#include "cc/trees/single_thread_proxy.h"
#include "components/viz/common/gpu/context_provider.h"
#include "components/viz/common/quads/draw_quad.h"
-#include "components/viz/common/quads/stream_video_draw_quad.h"
#include "components/viz/common/quads/texture_draw_quad.h"
#include "components/viz/common/quads/yuv_video_draw_quad.h"
#include "components/viz/service/display/output_surface.h"
diff --git a/chromium/cc/metrics/compositor_frame_reporter.cc b/chromium/cc/metrics/compositor_frame_reporter.cc
index fb5bdb10ff0..f1545f64b96 100644
--- a/chromium/cc/metrics/compositor_frame_reporter.cc
+++ b/chromium/cc/metrics/compositor_frame_reporter.cc
@@ -92,6 +92,26 @@ constexpr int kMaxEventLatencyHistogramIndex =
constexpr base::TimeDelta kEventLatencyHistogramMin = base::Microseconds(1);
constexpr base::TimeDelta kEventLatencyHistogramMax = base::Seconds(5);
constexpr int kEventLatencyHistogramBucketCount = 100;
+constexpr base::TimeDelta kHighLatencyMin = base::Milliseconds(75);
+
+// Number of breakdown stages of the current PipelineReporter
+constexpr int kNumOfCompositorStages =
+ static_cast<int>(StageType::kStageTypeCount) - 1;
+// Number of breakdown stages of the blink
+constexpr int kNumOfBlinkStages =
+ static_cast<int>(BlinkBreakdown::kBreakdownCount);
+// Number of breakdown stages of the viz
+constexpr int kNumOfVizStages = static_cast<int>(VizBreakdown::kBreakdownCount);
+// Number of dispatch stages of the current EventLatency
+constexpr int kNumDispatchStages =
+ static_cast<int>(EventMetrics::DispatchStage::kMaxValue);
+// Stores the weight of the most recent data point used in percentage when
+// predicting substages' latency. (It is stored and calculated in percentage
+// since TimeDelta calculate based on microseconds instead of nanoseconds,
+// therefore, decimals of stage durations in microseconds may be lost.)
+constexpr double kWeightOfCurStageInPercent = 25;
+// Used for comparing doubles
+constexpr double kEpsilon = 0.001;
std::string GetCompositorLatencyHistogramName(
FrameReportType report_type,
@@ -116,12 +136,11 @@ std::string GetEventLatencyHistogramBaseName(
const EventMetrics& event_metrics) {
auto* scroll_metrics = event_metrics.AsScroll();
auto* pinch_metrics = event_metrics.AsPinch();
- return base::StrCat(
- {"EventLatency.", event_metrics.GetTypeName(),
- scroll_metrics || pinch_metrics ? "." : "",
- scroll_metrics
- ? scroll_metrics->GetScrollTypeName()
- : pinch_metrics ? pinch_metrics->GetPinchTypeName() : ""});
+ return base::StrCat({"EventLatency.", event_metrics.GetTypeName(),
+ scroll_metrics || pinch_metrics ? "." : "",
+ scroll_metrics ? scroll_metrics->GetScrollTypeName()
+ : pinch_metrics ? pinch_metrics->GetPinchTypeName()
+ : ""});
}
constexpr char kTraceCategory[] =
@@ -131,6 +150,40 @@ base::TimeTicks ComputeSafeDeadlineForFrame(const viz::BeginFrameArgs& args) {
return args.frame_time + (args.interval * 1.5);
}
+// Returns the value of the exponentially weighted average for
+// SetEventLatencyPredictions.
+base::TimeDelta CalculateWeightedAverage(base::TimeDelta previous_value,
+ base::TimeDelta current_value) {
+ if (previous_value.is_negative())
+ return current_value;
+ return (kWeightOfCurStageInPercent * current_value +
+ (100 - kWeightOfCurStageInPercent) * previous_value) /
+ 100;
+}
+
+// Calculate new prediction of latency based on old prediction and current
+// latency
+base::TimeDelta PredictLatency(base::TimeDelta previous_prediction,
+ base::TimeDelta current_latency) {
+ return (kWeightOfCurStageInPercent * current_latency +
+ (100 - kWeightOfCurStageInPercent) * previous_prediction) /
+ 100;
+}
+
+double DetermineHighestContribution(
+ double contribution_change,
+ double highest_contribution_change,
+ const std::string& stage_name,
+ std::vector<std::string>& high_latency_stages) {
+ if (std::abs(contribution_change - highest_contribution_change) < kEpsilon) {
+ high_latency_stages.push_back(stage_name);
+ } else if (contribution_change > highest_contribution_change) {
+ highest_contribution_change = contribution_change;
+ high_latency_stages = {stage_name};
+ }
+ return highest_contribution_change;
+}
+
} // namespace
// CompositorFrameReporter::ProcessedBlinkBreakdown::Iterator ==================
@@ -318,6 +371,21 @@ CompositorFrameReporter::ProcessedVizBreakdown::CreateIterator(
buffer_ready_available_);
}
+// CompositorFrameReporter::CompositorLatencyInfo ==============================
+
+CompositorFrameReporter::CompositorLatencyInfo::CompositorLatencyInfo() =
+ default;
+CompositorFrameReporter::CompositorLatencyInfo::CompositorLatencyInfo(
+ base::TimeDelta init_value)
+ : top_level_stages(kNumOfCompositorStages, init_value),
+ blink_breakdown_stages(kNumOfBlinkStages, init_value),
+ viz_breakdown_stages(kNumOfVizStages, init_value),
+ total_latency(init_value),
+ total_blink_latency(init_value),
+ total_viz_latency(init_value) {}
+CompositorFrameReporter::CompositorLatencyInfo::~CompositorLatencyInfo() =
+ default;
+
// CompositorFrameReporter =====================================================
CompositorFrameReporter::CompositorFrameReporter(
@@ -357,6 +425,8 @@ CompositorFrameReporter::CompositorFrameReporter(
FrameSequenceTrackerType::kSETMainThreadAnimation)) ||
active_trackers_.test(static_cast<size_t>(
FrameSequenceTrackerType::kMainThreadAnimation)));
+ is_forked_ = false;
+ is_backfill_ = false;
}
// static
@@ -508,6 +578,7 @@ CompositorFrameReporter::CopyReporterAtBeginImplStage() {
StageType::kBeginImplFrameToSendBeginMainFrame;
new_reporter->current_stage_.start_time = stage_history_.front().start_time;
new_reporter->set_tick_clock(tick_clock_);
+ new_reporter->set_is_forked(true);
// Set up the new reporter so that it depends on |this| for partial update
// information.
@@ -528,6 +599,16 @@ CompositorFrameReporter::StageData::StageData(StageType stage_type,
CompositorFrameReporter::StageData::StageData(const StageData&) = default;
CompositorFrameReporter::StageData::~StageData() = default;
+CompositorFrameReporter::EventLatencyInfo::EventLatencyInfo(
+ const int num_dispatch_stages,
+ const int num_compositor_stages)
+ : dispatch_durations(num_dispatch_stages, base::Microseconds(-1)),
+ transition_duration(base::Microseconds(-1)),
+ compositor_durations(num_compositor_stages, base::Microseconds(-1)),
+ total_duration(base::Microseconds(-1)),
+ transition_name("") {}
+CompositorFrameReporter::EventLatencyInfo::~EventLatencyInfo() = default;
+
void CompositorFrameReporter::StartStage(
CompositorFrameReporter::StageType stage_type,
base::TimeTicks start_time) {
@@ -639,10 +720,12 @@ void CompositorFrameReporter::TerminateReporter() {
if (frame_termination_status_ == FrameTerminationStatus::kUnknown)
TerminateFrame(FrameTerminationStatus::kUnknown, Now());
- processed_blink_breakdown_ = std::make_unique<ProcessedBlinkBreakdown>(
- blink_start_time_, begin_main_frame_start_, blink_breakdown_);
- processed_viz_breakdown_ =
- std::make_unique<ProcessedVizBreakdown>(viz_start_time_, viz_breakdown_);
+ if (!processed_blink_breakdown_)
+ processed_blink_breakdown_ = std::make_unique<ProcessedBlinkBreakdown>(
+ blink_start_time_, begin_main_frame_start_, blink_breakdown_);
+ if (!processed_viz_breakdown_)
+ processed_viz_breakdown_ = std::make_unique<ProcessedVizBreakdown>(
+ viz_start_time_, viz_breakdown_);
DCHECK_EQ(current_stage_.start_time, base::TimeTicks());
const FrameInfo frame_info = GenerateFrameInfo();
@@ -890,9 +973,9 @@ void CompositorFrameReporter::ReportCompositorLatencyHistogram(
const int stage_type_index =
blink_breakdown
? kBlinkBreakdownInitialIndex + static_cast<int>(*blink_breakdown)
- : viz_breakdown
- ? kVizBreakdownInitialIndex + static_cast<int>(*viz_breakdown)
- : static_cast<int>(stage_type);
+ : viz_breakdown
+ ? kVizBreakdownInitialIndex + static_cast<int>(*viz_breakdown)
+ : static_cast<int>(stage_type);
const int histogram_index =
(stage_type_index == static_cast<int>(StageType::kTotalLatency)
? kStagesWithBreakdownCount + frame_sequence_tracker_type_index
@@ -1075,6 +1158,18 @@ void CompositorFrameReporter::ReportCompositorLatencyTraceEvents(
has_smooth_input_main |= event_metrics->HasSmoothInputEvent();
}
reporter->set_has_smooth_input_main(has_smooth_input_main);
+ reporter->set_has_high_latency(
+ (frame_termination_time_ - args_.frame_time) > kHighLatencyMin);
+
+ if (is_forked_) {
+ reporter->set_frame_type(ChromeFrameReporter::FORKED);
+ } else if (is_backfill_) {
+ reporter->set_frame_type(ChromeFrameReporter::BACKFILL);
+ }
+
+ for (auto stage : high_latency_substages_) {
+ reporter->add_high_latency_contribution_stage(stage);
+ }
// TODO(crbug.com/1086974): Set 'drop reason' if applicable.
});
@@ -1205,6 +1300,279 @@ void CompositorFrameReporter::AdoptReporter(
DiscardOldPartialUpdateReporters();
}
+void CompositorFrameReporter::CalculateCompositorLatencyPrediction(
+ CompositorLatencyInfo& previous_predictions,
+ base::TimeDelta prediction_deviation_threshold) {
+ // `stage_history_` should not be empty since we are calling this function
+ // from DidPresentCompositorFrame(), which means there has to be some sort of
+ // stage data.
+ DCHECK(!stage_history_.empty());
+
+ // If the bad case of having `total_latency` of `previous_predictions` happens
+ // then it would mess up the prediction calculation, therefore, we want to
+ // reset the prediction by setting everything back to -1.
+ if (previous_predictions.total_latency.is_zero())
+ previous_predictions = CompositorLatencyInfo(base::Microseconds(-1));
+
+ base::TimeDelta total_pipeline_latency =
+ stage_history_.back().end_time - stage_history_[0].start_time;
+
+ // Do not record current breakdown stages' duration if the total latency of
+ // the current PipelineReporter is 0s. And no further predictions could be
+ // made in this case.
+ if (total_pipeline_latency.is_zero())
+ return;
+
+ processed_blink_breakdown_ = std::make_unique<ProcessedBlinkBreakdown>(
+ blink_start_time_, begin_main_frame_start_, blink_breakdown_);
+ processed_viz_breakdown_ =
+ std::make_unique<ProcessedVizBreakdown>(viz_start_time_, viz_breakdown_);
+
+ // Note that `current_stage_durations` would always have the same length as
+ // `previous_predictions`, since each index represent the breakdown stages of
+ // the PipelineReporter listed at enum class, StageType.
+ CompositorLatencyInfo current_stage_durations(base::Microseconds(0));
+ current_stage_durations.total_latency = total_pipeline_latency;
+
+ for (auto stage : stage_history_) {
+ if (stage.stage_type == StageType::kTotalLatency)
+ continue;
+ base::TimeDelta substageLatency = stage.end_time - stage.start_time;
+ current_stage_durations
+ .top_level_stages[static_cast<int>(stage.stage_type)] = substageLatency;
+ }
+
+ for (auto it = processed_blink_breakdown_->CreateIterator(); it.IsValid();
+ it.Advance()) {
+ current_stage_durations
+ .blink_breakdown_stages[static_cast<int>(it.GetBreakdown())] =
+ it.GetLatency();
+ current_stage_durations.total_blink_latency += it.GetLatency();
+ }
+
+ for (auto it = processed_viz_breakdown_->CreateIterator(true); it.IsValid();
+ it.Advance()) {
+ current_stage_durations
+ .viz_breakdown_stages[static_cast<int>(it.GetBreakdown())] =
+ it.GetDuration();
+ current_stage_durations.total_viz_latency += it.GetDuration();
+ }
+
+ // Do not record current pipeline details or update predictions if no frame
+ // is submitted.
+ if (current_stage_durations
+ .top_level_stages[static_cast<int>(
+ StageType::kSubmitCompositorFrameToPresentationCompositorFrame)]
+ .is_zero())
+ return;
+
+ // The previous prediction is initialized to be -1, so check if the current
+ // PipelineReporter is the first reporter ever to be calculated.
+ if (previous_predictions.total_latency == base::Microseconds(-1)) {
+ previous_predictions = current_stage_durations;
+ } else {
+ if ((current_stage_durations.total_latency -
+ previous_predictions.total_latency) >= prediction_deviation_threshold)
+ FindHighLatencyAttribution(previous_predictions, current_stage_durations);
+
+ for (int i = 0; i < kNumOfCompositorStages; i++) {
+ previous_predictions.top_level_stages[i] =
+ PredictLatency(previous_predictions.top_level_stages[i],
+ current_stage_durations.top_level_stages[i]);
+ }
+ previous_predictions.total_latency =
+ PredictLatency(previous_predictions.total_latency,
+ current_stage_durations.total_latency);
+
+ if (!current_stage_durations.total_blink_latency.is_zero()) {
+ for (int i = 0; i < kNumOfBlinkStages; i++) {
+ previous_predictions.blink_breakdown_stages[i] =
+ previous_predictions.total_blink_latency.is_zero()
+ ? current_stage_durations.blink_breakdown_stages[i]
+ : PredictLatency(
+ previous_predictions.blink_breakdown_stages[i],
+ current_stage_durations.blink_breakdown_stages[i]);
+ }
+ previous_predictions.total_blink_latency =
+ previous_predictions.total_blink_latency.is_zero()
+ ? current_stage_durations.total_blink_latency
+ : PredictLatency(previous_predictions.total_blink_latency,
+ current_stage_durations.total_blink_latency);
+ }
+
+ // TODO(crbug.com/1349930): implement check that ensure the prediction is
+ // correct by checking if platform supports breakdown of the stage
+ // SubmitCompositorFrameToPresentationCompositorFrame.SwapStartToSwapEnd,
+ // then SwapStartToSwapEnd should always be 0s and data for breakdown of it
+ // should always be available. (See enum class `VizBreakdown` for stage
+ // details.)
+ if (!current_stage_durations.total_viz_latency.is_zero()) {
+ for (int i = 0; i < kNumOfVizStages; i++) {
+ previous_predictions.viz_breakdown_stages[i] =
+ previous_predictions.total_viz_latency.is_zero()
+ ? current_stage_durations.viz_breakdown_stages[i]
+ : PredictLatency(
+ previous_predictions.viz_breakdown_stages[i],
+ current_stage_durations.viz_breakdown_stages[i]);
+ }
+ previous_predictions.total_viz_latency =
+ previous_predictions.total_viz_latency.is_zero()
+ ? current_stage_durations.total_viz_latency
+ : PredictLatency(previous_predictions.total_viz_latency,
+ current_stage_durations.total_viz_latency);
+ }
+ }
+}
+
+void CompositorFrameReporter::CalculateEventLatencyPrediction(
+ CompositorFrameReporter::EventLatencyInfo& predicted_event_latency,
+ base::TimeDelta prediction_deviation_threshold) {
+ if (events_metrics_.empty())
+ return;
+
+ // TODO(crbug.com/1334827): Explore calculating predictions for multiple
+ // events. Currently only kGestureScrollUpdate event predictions
+ // are being calculated, consider including other stages in future changes.
+ auto event_it = std::find_if(
+ events_metrics_.begin(), events_metrics_.end(),
+ [](const std::unique_ptr<EventMetrics>& event) {
+ return event &&
+ event->type() == EventMetrics::EventType::kGestureScrollUpdate;
+ });
+ if (event_it == events_metrics_.end())
+ return;
+ auto& event_metrics = *event_it;
+
+ base::TimeTicks dispatch_start_time =
+ event_metrics->GetDispatchStageTimestamp(
+ EventMetrics::DispatchStage::kGenerated);
+
+ // Determine the last valid stage in case kRendererMainFinished or
+ // kRendererCompositorFinished stages do not exist, otherwise there is not
+ // enough information for the prediction.
+ EventMetrics::DispatchStage last_valid_stage =
+ EventMetrics::DispatchStage::kGenerated;
+ if (event_metrics->GetDispatchStageTimestamp(
+ EventMetrics::DispatchStage::kRendererMainFinished) >
+ dispatch_start_time) {
+ last_valid_stage = EventMetrics::DispatchStage::kRendererMainFinished;
+ } else if (event_metrics->GetDispatchStageTimestamp(
+ EventMetrics::DispatchStage::kRendererCompositorFinished) >
+ dispatch_start_time) {
+ last_valid_stage = EventMetrics::DispatchStage::kRendererCompositorFinished;
+ }
+
+ base::TimeTicks dispatch_end_time =
+ event_metrics->GetDispatchStageTimestamp(last_valid_stage);
+ base::TimeDelta total_dispatch_duration =
+ dispatch_end_time - dispatch_start_time;
+ if (total_dispatch_duration.is_negative())
+ return;
+
+ CompositorFrameReporter::EventLatencyInfo actual_event_latency(
+ kNumDispatchStages, kNumOfCompositorStages);
+ actual_event_latency.total_duration = base::Microseconds(0);
+
+ // Determine dispatch stage durations.
+ base::TimeTicks previous_timetick = dispatch_start_time;
+ for (auto stage = EventMetrics::DispatchStage::kGenerated;
+ stage <= last_valid_stage;
+ stage = static_cast<EventMetrics::DispatchStage>(
+ static_cast<int>(stage) + 1)) {
+ if (stage != EventMetrics::DispatchStage::kGenerated) {
+ base::TimeTicks current_timetick =
+ event_metrics->GetDispatchStageTimestamp(stage);
+ // Only update stage if the current_timetick is later than the
+ // previous_timetick.
+ if (current_timetick > previous_timetick) {
+ base::TimeDelta stage_duration = current_timetick - previous_timetick;
+ actual_event_latency.dispatch_durations[static_cast<int>(stage) - 1] =
+ stage_duration;
+ actual_event_latency.total_duration += stage_duration;
+ previous_timetick = current_timetick;
+ }
+ }
+ }
+
+ // Determine dispatch-to-compositor transition stage duration.
+ auto stage_it = std::find_if(
+ stage_history_.begin(), stage_history_.end(),
+ [dispatch_end_time](const CompositorFrameReporter::StageData& stage) {
+ return stage.start_time >= dispatch_end_time;
+ });
+ if (stage_it != stage_history_.end()) {
+ if (dispatch_end_time < stage_it->start_time) {
+ base::TimeDelta stage_duration = stage_it->start_time - dispatch_end_time;
+ actual_event_latency.transition_duration = stage_duration;
+ actual_event_latency.total_duration += stage_duration;
+ actual_event_latency.transition_name =
+ EventLatencyTracingRecorder::GetDispatchToCompositorBreakdownName(
+ last_valid_stage, stage_it->stage_type);
+ }
+ }
+
+ // Determine compositor stage durations, which start from stage_it for
+ // EventLatency.
+ for (auto stage = stage_it; stage != stage_history_.end(); stage++) {
+ base::TimeDelta stage_duration = stage->end_time - stage->start_time;
+ if (stage_duration.is_positive()) {
+ actual_event_latency
+ .compositor_durations[static_cast<int>(stage->stage_type)] =
+ stage_duration;
+ actual_event_latency.total_duration += stage_duration;
+ }
+ }
+
+ // High latency attribution.
+ if (predicted_event_latency.total_duration.is_positive() &&
+ actual_event_latency.total_duration -
+ predicted_event_latency.total_duration >=
+ prediction_deviation_threshold) {
+ FindEventLatencyAttribution(event_metrics.get(), predicted_event_latency,
+ actual_event_latency);
+ }
+
+ // Calculate new dispatch stage predictions.
+ base::TimeDelta predicted_total_duration = base::Microseconds(0);
+ for (int i = 0; i < kNumDispatchStages; i++) {
+ if (actual_event_latency.dispatch_durations[i].is_positive()) {
+ predicted_event_latency.dispatch_durations[i] = CalculateWeightedAverage(
+ predicted_event_latency.dispatch_durations[i],
+ actual_event_latency.dispatch_durations[i]);
+ }
+ if (predicted_event_latency.dispatch_durations[i].is_positive()) {
+ predicted_total_duration += predicted_event_latency.dispatch_durations[i];
+ }
+ }
+
+ // Calculate new dispatch-to-compositor transition stage predictions.
+ if (actual_event_latency.transition_duration.is_positive()) {
+ predicted_event_latency.transition_duration =
+ CalculateWeightedAverage(predicted_event_latency.transition_duration,
+ actual_event_latency.transition_duration);
+ if (predicted_event_latency.transition_duration.is_positive())
+ predicted_total_duration += predicted_event_latency.transition_duration;
+ }
+
+ // Calculate new compositor stage predictions.
+ // TODO(crbug.com/1334827): Explore using existing PipelineReporter
+ // predictions for the compositor stage.
+ for (int i = 0; i < kNumOfCompositorStages; i++) {
+ if (actual_event_latency.compositor_durations[i].is_positive()) {
+ predicted_event_latency.compositor_durations[i] =
+ CalculateWeightedAverage(
+ predicted_event_latency.compositor_durations[i],
+ actual_event_latency.compositor_durations[i]);
+ }
+ if (predicted_event_latency.compositor_durations[i].is_positive()) {
+ predicted_total_duration +=
+ predicted_event_latency.compositor_durations[i];
+ }
+ }
+
+ predicted_event_latency.total_duration = predicted_total_duration;
+}
+
void CompositorFrameReporter::SetPartialUpdateDecider(
CompositorFrameReporter* decider) {
DCHECK(decider);
@@ -1345,4 +1713,182 @@ FrameInfo CompositorFrameReporter::GenerateFrameInfo() const {
return info;
}
+void CompositorFrameReporter::FindHighLatencyAttribution(
+ CompositorLatencyInfo& previous_predictions,
+ CompositorLatencyInfo& current_stage_durations) {
+ if (previous_predictions.total_latency.is_zero() ||
+ current_stage_durations.total_latency.is_zero())
+ return;
+
+ double contribution_change = -1;
+ double highest_contribution_change = -1;
+ std::vector<int> highest_contribution_change_index;
+ std::vector<int> highest_blink_contribution_change_index;
+ std::vector<int> highest_viz_contribution_change_index;
+
+ for (int i = 0; i < kNumOfCompositorStages; i++) {
+ switch (i) {
+ case static_cast<int>(StageType::kSendBeginMainFrameToCommit):
+ if (current_stage_durations.top_level_stages[i].is_zero() ||
+ previous_predictions.total_blink_latency.is_zero() ||
+ current_stage_durations.total_blink_latency.is_zero())
+ continue;
+
+ for (int j = 0; j < kNumOfBlinkStages; j++) {
+ contribution_change =
+ (current_stage_durations.blink_breakdown_stages[j] /
+ current_stage_durations.total_latency) -
+ (previous_predictions.blink_breakdown_stages[j] /
+ previous_predictions.total_latency);
+
+ if (contribution_change > highest_contribution_change) {
+ highest_contribution_change = contribution_change;
+ highest_contribution_change_index.clear();
+ highest_viz_contribution_change_index.clear();
+ highest_blink_contribution_change_index = {j};
+ } else if (std::abs(contribution_change -
+ highest_contribution_change) < kEpsilon) {
+ highest_blink_contribution_change_index.push_back(j);
+ }
+ }
+ break;
+
+ case static_cast<int>(
+ StageType::kSubmitCompositorFrameToPresentationCompositorFrame):
+ if (current_stage_durations.top_level_stages[i].is_zero() ||
+ previous_predictions.total_viz_latency.is_zero() ||
+ current_stage_durations.total_viz_latency.is_zero())
+ continue;
+
+ for (int j = 0; j < kNumOfVizStages; j++) {
+ contribution_change =
+ (current_stage_durations.viz_breakdown_stages[j] /
+ current_stage_durations.total_latency) -
+ (previous_predictions.viz_breakdown_stages[j] /
+ previous_predictions.total_latency);
+
+ if (contribution_change > highest_contribution_change) {
+ highest_contribution_change = contribution_change;
+ highest_contribution_change_index.clear();
+ highest_blink_contribution_change_index.clear();
+ highest_viz_contribution_change_index = {j};
+ } else if (std::abs(contribution_change -
+ highest_contribution_change) < kEpsilon) {
+ highest_viz_contribution_change_index.push_back(j);
+ }
+ }
+ break;
+
+ default:
+ contribution_change = (current_stage_durations.top_level_stages[i] /
+ current_stage_durations.total_latency) -
+ (previous_predictions.top_level_stages[i] /
+ previous_predictions.total_latency);
+
+ if (contribution_change > highest_contribution_change) {
+ highest_contribution_change = contribution_change;
+ highest_blink_contribution_change_index.clear();
+ highest_viz_contribution_change_index.clear();
+ highest_contribution_change_index = {i};
+ } else if (std::abs(contribution_change - highest_contribution_change) <
+ kEpsilon) {
+ highest_contribution_change_index.push_back(i);
+ }
+ break;
+ }
+ }
+
+ // It is not expensive to go through vector of indexes again since it is
+ // usually very small (possibilities of breakdown stages having the same
+ // change contribution is small).
+ for (auto index : highest_contribution_change_index) {
+ high_latency_substages_.push_back(
+ GetStageName(static_cast<StageType>(index)));
+ }
+ for (auto index : highest_blink_contribution_change_index) {
+ high_latency_substages_.push_back(
+ GetStageName(StageType::kSendBeginMainFrameToCommit, absl::nullopt,
+ static_cast<BlinkBreakdown>(index)));
+ }
+ for (auto index : highest_viz_contribution_change_index) {
+ high_latency_substages_.push_back(GetStageName(
+ StageType::kSubmitCompositorFrameToPresentationCompositorFrame,
+ static_cast<VizBreakdown>(index)));
+ }
+}
+
+void CompositorFrameReporter::FindEventLatencyAttribution(
+ EventMetrics* event_metrics,
+ CompositorFrameReporter::EventLatencyInfo& predicted_event_latency,
+ CompositorFrameReporter::EventLatencyInfo& actual_event_latency) {
+ if (!event_metrics)
+ return;
+
+ std::vector<std::string> high_latency_stages;
+ double contribution_change = -1;
+ double highest_contribution_change = -1;
+
+ // Check dispatch stage change
+ EventMetrics::DispatchStage dispatch_stage =
+ EventMetrics::DispatchStage::kGenerated;
+ base::TimeTicks dispatch_timestamp =
+ event_metrics->GetDispatchStageTimestamp(dispatch_stage);
+ while (dispatch_stage != EventMetrics::DispatchStage::kMaxValue) {
+ DCHECK(!dispatch_timestamp.is_null());
+ auto end_stage = static_cast<EventMetrics::DispatchStage>(
+ static_cast<int>(dispatch_stage) + 1);
+ base::TimeTicks end_timestamp =
+ event_metrics->GetDispatchStageTimestamp(end_stage);
+ while (end_timestamp.is_null() &&
+ end_stage != EventMetrics::DispatchStage::kMaxValue) {
+ end_stage = static_cast<EventMetrics::DispatchStage>(
+ static_cast<int>(end_stage) + 1);
+ end_timestamp = event_metrics->GetDispatchStageTimestamp(end_stage);
+ }
+ if (end_timestamp.is_null())
+ break;
+
+ contribution_change =
+ (actual_event_latency
+ .dispatch_durations[static_cast<int>(end_stage) - 1] /
+ actual_event_latency.total_duration) -
+ (predicted_event_latency
+ .dispatch_durations[static_cast<int>(end_stage) - 1] /
+ predicted_event_latency.total_duration);
+ std::string dispatch_stage_name =
+ EventLatencyTracingRecorder::GetDispatchBreakdownName(dispatch_stage,
+ end_stage);
+ highest_contribution_change = DetermineHighestContribution(
+ contribution_change, highest_contribution_change, dispatch_stage_name,
+ high_latency_stages);
+
+ dispatch_stage = end_stage;
+ dispatch_timestamp = end_timestamp;
+ }
+
+ // Check dispatch-to-compositor stage change
+ contribution_change = (actual_event_latency.transition_duration /
+ actual_event_latency.total_duration) -
+ (predicted_event_latency.transition_duration /
+ predicted_event_latency.total_duration);
+ highest_contribution_change = DetermineHighestContribution(
+ contribution_change, highest_contribution_change,
+ actual_event_latency.transition_name, high_latency_stages);
+
+ // Check compositor stage change
+ for (int i = 0; i < kNumOfCompositorStages; i++) {
+ contribution_change = (actual_event_latency.compositor_durations[i] /
+ actual_event_latency.total_duration) -
+ (predicted_event_latency.compositor_durations[i] /
+ predicted_event_latency.total_duration);
+ highest_contribution_change = DetermineHighestContribution(
+ contribution_change, highest_contribution_change,
+ GetStageName(static_cast<StageType>(i)), high_latency_stages);
+ }
+
+ for (auto stage : high_latency_stages) {
+ event_metrics->SetHighLatencyStage(stage);
+ }
+}
+
} // namespace cc
diff --git a/chromium/cc/metrics/compositor_frame_reporter.h b/chromium/cc/metrics/compositor_frame_reporter.h
index ad0b1084a34..c04a7cff6cc 100644
--- a/chromium/cc/metrics/compositor_frame_reporter.h
+++ b/chromium/cc/metrics/compositor_frame_reporter.h
@@ -133,6 +133,9 @@ class CC_EXPORT CompositorFrameReporter {
kBreakdownCount
};
+ // To distinguish between impl and main reporter
+ enum class ReporterType { kImpl = 0, kMain = 1 };
+
struct CC_EXPORT StageData {
StageType stage_type;
base::TimeTicks start_time;
@@ -145,6 +148,18 @@ class CC_EXPORT CompositorFrameReporter {
~StageData();
};
+ struct CC_EXPORT EventLatencyInfo {
+ std::vector<base::TimeDelta> dispatch_durations;
+ base::TimeDelta transition_duration;
+ std::vector<base::TimeDelta> compositor_durations;
+ base::TimeDelta total_duration;
+ std::string transition_name;
+ EventLatencyInfo(const int num_dispatch_stages,
+ const int num_compositor_stages);
+ EventLatencyInfo(const EventLatencyInfo&);
+ ~EventLatencyInfo();
+ };
+
using SmoothThread = FrameInfo::SmoothThread;
// Holds a processed list of Blink breakdowns with an `Iterator` class to
@@ -229,6 +244,21 @@ class CC_EXPORT CompositorFrameReporter {
base::TimeTicks swap_start_;
};
+ // Wrapper for all level of breakdown stages' prediction
+ struct CC_EXPORT CompositorLatencyInfo {
+ CompositorLatencyInfo();
+ explicit CompositorLatencyInfo(base::TimeDelta init_value);
+ ~CompositorLatencyInfo();
+
+ std::vector<base::TimeDelta> top_level_stages;
+ std::vector<base::TimeDelta> blink_breakdown_stages;
+ std::vector<base::TimeDelta> viz_breakdown_stages;
+
+ base::TimeDelta total_latency;
+ base::TimeDelta total_blink_latency;
+ base::TimeDelta total_viz_latency;
+ };
+
CompositorFrameReporter(const ActiveTrackers& active_trackers,
const viz::BeginFrameArgs& args,
bool should_report_histograms,
@@ -330,6 +360,9 @@ class CC_EXPORT CompositorFrameReporter {
is_accompanied_by_main_thread_update;
}
+ void set_is_forked(bool is_forked) { is_forked_ = is_forked; }
+ void set_is_backfill(bool is_backfill) { is_backfill_ = is_backfill; }
+
const viz::BeginFrameId& frame_id() const { return args_.frame_id; }
// Adopts |cloned_reporter|, i.e. keeps |cloned_reporter| alive until after
@@ -346,6 +379,36 @@ class CC_EXPORT CompositorFrameReporter {
using FrameReportTypes =
std::bitset<static_cast<size_t>(FrameReportType::kMaxValue) + 1>;
+ // This function is called to calculate breakdown stage duration's prediction
+ // based on the `previous_predictions` and update the `previous_predictions`
+ // to the new prediction calculated.
+ void CalculateCompositorLatencyPrediction(
+ CompositorLatencyInfo& previous_predictions,
+ base::TimeDelta prediction_deviation_threshold);
+
+ // Sets EventLatency stage duration predictions based on previous trace
+ // durations using exponentially weighted averages.
+ void CalculateEventLatencyPrediction(
+ CompositorFrameReporter::EventLatencyInfo& predicted_event_latency,
+ base::TimeDelta prediction_deviation_threshold);
+
+ ReporterType get_reporter_type() { return reporter_type_; }
+
+ void set_reporter_type_to_impl() { reporter_type_ = ReporterType::kImpl; }
+ void set_reporter_type_to_main() { reporter_type_ = ReporterType::kMain; }
+
+ const std::vector<std::string>& high_latency_substages_for_testing() {
+ return high_latency_substages_;
+ }
+
+ void ClearHighLatencySubstagesForTesting() {
+ high_latency_substages_.clear();
+ }
+
+ std::vector<std::unique_ptr<EventMetrics>>& events_metrics_for_testing() {
+ return events_metrics_;
+ }
+
protected:
void set_has_partial_update(bool has_partial_update) {
has_partial_update_ = has_partial_update;
@@ -398,6 +461,15 @@ class CC_EXPORT CompositorFrameReporter {
// updates (see comments on EventMetrics::requires_main_thread_update_).
EventMetrics::List TakeMainBlockedEventsMetrics();
+ void FindHighLatencyAttribution(
+ CompositorLatencyInfo& previous_predictions,
+ CompositorLatencyInfo& current_stage_durations);
+
+ void FindEventLatencyAttribution(
+ EventMetrics* event_metrics,
+ CompositorFrameReporter::EventLatencyInfo& predicted_event_latency,
+ CompositorFrameReporter::EventLatencyInfo& actual_event_latency);
+
// Whether UMA histograms should be reported or not.
const bool should_report_histograms_;
@@ -458,6 +530,14 @@ class CC_EXPORT CompositorFrameReporter {
// with checkerboarding).
bool has_missing_content_ = false;
+ // Indicates whether the frame is forked (i.e. a PipelineReporter event starts
+ // at the same frame sequence as another PipelineReporter).
+ bool is_forked_ = false;
+
+ // Indicates whether the frame is backfill (i.e. dropped frames when there are
+ // no partial compositor updates).
+ bool is_backfill_ = false;
+
// For a reporter A, if the main-thread takes a long time to respond
// to a begin-main-frame, then all reporters created (and terminated) until
// the main-thread responds depends on this reporter to decide whether those
@@ -479,6 +559,10 @@ class CC_EXPORT CompositorFrameReporter {
const GlobalMetricsTrackers global_trackers_;
+ std::vector<std::string> high_latency_substages_;
+
+ ReporterType reporter_type_;
+
base::WeakPtrFactory<CompositorFrameReporter> weak_factory_{this};
};
diff --git a/chromium/cc/metrics/compositor_frame_reporter_unittest.cc b/chromium/cc/metrics/compositor_frame_reporter_unittest.cc
index 014a1a4a3f3..105435c5696 100644
--- a/chromium/cc/metrics/compositor_frame_reporter_unittest.cc
+++ b/chromium/cc/metrics/compositor_frame_reporter_unittest.cc
@@ -32,12 +32,12 @@ using ::testing::NotNull;
class CompositorFrameReporterTest : public testing::Test {
public:
CompositorFrameReporterTest() : pipeline_reporter_(CreatePipelineReporter()) {
- AdvanceNowByMs(1);
+ AdvanceNowByUs(1);
dropped_frame_counter_.set_total_counter(&total_frame_counter_);
}
protected:
- base::TimeTicks AdvanceNowByMs(int advance_ms) {
+ base::TimeTicks AdvanceNowByUs(int advance_ms) {
test_tick_clock_.Advance(base::Microseconds(advance_ms));
return test_tick_clock_.NowTicks();
}
@@ -57,44 +57,86 @@ class CompositorFrameReporterTest : public testing::Test {
breakdown->update_layers = base::Microseconds(1);
// Advance now by the sum of the breakdowns.
- AdvanceNowByMs(10 + 9 + 8 + 7 + 6 + 5 + 3 + 2 + 1);
+ AdvanceNowByUs(10 + 9 + 8 + 7 + 6 + 5 + 3 + 2 + 1);
return breakdown;
}
viz::FrameTimingDetails BuildVizBreakdown() {
viz::FrameTimingDetails viz_breakdown;
- viz_breakdown.received_compositor_frame_timestamp = AdvanceNowByMs(1);
- viz_breakdown.draw_start_timestamp = AdvanceNowByMs(2);
- viz_breakdown.swap_timings.swap_start = AdvanceNowByMs(3);
- viz_breakdown.swap_timings.swap_end = AdvanceNowByMs(4);
- viz_breakdown.presentation_feedback.timestamp = AdvanceNowByMs(5);
+ viz_breakdown.received_compositor_frame_timestamp = AdvanceNowByUs(1);
+ viz_breakdown.draw_start_timestamp = AdvanceNowByUs(2);
+ viz_breakdown.swap_timings.swap_start = AdvanceNowByUs(3);
+ viz_breakdown.swap_timings.swap_end = AdvanceNowByUs(4);
+ viz_breakdown.presentation_feedback.timestamp = AdvanceNowByUs(5);
return viz_breakdown;
}
std::unique_ptr<EventMetrics> SetupEventMetrics(
std::unique_ptr<EventMetrics> metrics) {
if (metrics) {
- AdvanceNowByMs(3);
+ AdvanceNowByUs(3);
metrics->SetDispatchStageTimestamp(
EventMetrics::DispatchStage::kRendererCompositorStarted);
- AdvanceNowByMs(3);
+ AdvanceNowByUs(3);
metrics->SetDispatchStageTimestamp(
EventMetrics::DispatchStage::kRendererCompositorFinished);
}
return metrics;
}
+ // Sets up the dispatch durations of each EventMetrics according to
+ // stage_durations. Stages with a duration of -1 will be skipped.
+ std::unique_ptr<EventMetrics> SetupEventMetricsWithDispatchTimes(
+ std::unique_ptr<EventMetrics> metrics,
+ const std::vector<int>& stage_durations) {
+ if (metrics) {
+ int num_stages = stage_durations.size();
+ // Start indexing from 1 because the 0th index held duration from
+ // kGenerated to kArrivedInRendererCompositor, which was already used in
+ // when the EventMetrics was created.
+ for (int i = 1; i < num_stages; i++) {
+ if (stage_durations[i] >= 0) {
+ AdvanceNowByUs(stage_durations[i]);
+ metrics->SetDispatchStageTimestamp(
+ EventMetrics::DispatchStage(i + 1));
+ }
+ }
+ }
+ return metrics;
+ }
+
std::unique_ptr<EventMetrics> CreateEventMetrics(ui::EventType type) {
- const base::TimeTicks event_time = AdvanceNowByMs(3);
- AdvanceNowByMs(3);
+ const base::TimeTicks event_time = AdvanceNowByUs(3);
+ AdvanceNowByUs(3);
return SetupEventMetrics(
EventMetrics::CreateForTesting(type, event_time, &test_tick_clock_));
}
+ // Creates EventMetrics with elements in stage_durations representing each
+ // dispatch stage's desired duration respectively, with the 0th index
+ // representing the duration from kGenerated to kArrivedInRendererCompositor.
+ // stage_durations must have at least 1 element for the first required stage
+ // Use -1 for stages that want to be skipped.
+ std::unique_ptr<EventMetrics> CreateScrollUpdateEventMetricsWithDispatchTimes(
+ bool is_inertial,
+ ScrollUpdateEventMetrics::ScrollUpdateType scroll_update_type,
+ const std::vector<int>& stage_durations) {
+ DCHECK_GT((int)stage_durations.size(), 0);
+ const base::TimeTicks event_time = AdvanceNowByUs(3);
+ AdvanceNowByUs(stage_durations[0]);
+ // Creates a kGestureScrollUpdate event.
+ return SetupEventMetricsWithDispatchTimes(
+ ScrollUpdateEventMetrics::CreateForTesting(
+ ui::ET_GESTURE_SCROLL_UPDATE, ui::ScrollInputType::kWheel,
+ is_inertial, scroll_update_type, /*delta=*/10.0f, event_time,
+ &test_tick_clock_),
+ stage_durations);
+ }
+
std::unique_ptr<EventMetrics> CreateScrollBeginMetrics() {
- const base::TimeTicks event_time = AdvanceNowByMs(3);
- AdvanceNowByMs(3);
+ const base::TimeTicks event_time = AdvanceNowByUs(3);
+ AdvanceNowByUs(3);
return SetupEventMetrics(ScrollEventMetrics::CreateForTesting(
ui::ET_GESTURE_SCROLL_BEGIN, ui::ScrollInputType::kWheel,
/*is_inertial=*/false, event_time, &test_tick_clock_));
@@ -103,8 +145,8 @@ class CompositorFrameReporterTest : public testing::Test {
std::unique_ptr<EventMetrics> CreateScrollUpdateEventMetrics(
bool is_inertial,
ScrollUpdateEventMetrics::ScrollUpdateType scroll_update_type) {
- const base::TimeTicks event_time = AdvanceNowByMs(3);
- AdvanceNowByMs(3);
+ const base::TimeTicks event_time = AdvanceNowByUs(3);
+ AdvanceNowByUs(3);
return SetupEventMetrics(ScrollUpdateEventMetrics::CreateForTesting(
ui::ET_GESTURE_SCROLL_UPDATE, ui::ScrollInputType::kWheel, is_inertial,
scroll_update_type, /*delta=*/10.0f, event_time, &test_tick_clock_));
@@ -113,8 +155,8 @@ class CompositorFrameReporterTest : public testing::Test {
std::unique_ptr<EventMetrics> CreatePinchEventMetrics(
ui::EventType type,
ui::ScrollInputType input_type) {
- const base::TimeTicks event_time = AdvanceNowByMs(3);
- AdvanceNowByMs(3);
+ const base::TimeTicks event_time = AdvanceNowByUs(3);
+ AdvanceNowByUs(3);
return SetupEventMetrics(PinchEventMetrics::CreateForTesting(
type, input_type, event_time, &test_tick_clock_));
}
@@ -144,6 +186,28 @@ class CompositorFrameReporterTest : public testing::Test {
return reporter;
}
+ void IntToTimeDeltaVector(std::vector<base::TimeDelta>& timedelta_vector,
+ std::vector<int> int_vector) {
+ size_t vector_size = int_vector.size();
+ for (size_t i = 0; i < vector_size; i++) {
+ timedelta_vector[i] = base::Microseconds(int_vector[i]);
+ }
+ }
+
+ void VerifyLatencyInfo(
+ CompositorFrameReporter::CompositorLatencyInfo& expected_info,
+ CompositorFrameReporter::CompositorLatencyInfo& actual_info) {
+ EXPECT_EQ(expected_info.top_level_stages, actual_info.top_level_stages);
+ EXPECT_EQ(expected_info.blink_breakdown_stages,
+ actual_info.blink_breakdown_stages);
+ EXPECT_EQ(expected_info.viz_breakdown_stages,
+ actual_info.viz_breakdown_stages);
+ EXPECT_EQ(expected_info.total_latency, actual_info.total_latency);
+ EXPECT_EQ(expected_info.total_blink_latency,
+ actual_info.total_blink_latency);
+ EXPECT_EQ(expected_info.total_viz_latency, actual_info.total_viz_latency);
+ }
+
// This should be defined before |pipeline_reporter_| so it is created before
// and destroyed after that.
base::SimpleTestTickClock test_tick_clock_;
@@ -151,6 +215,14 @@ class CompositorFrameReporterTest : public testing::Test {
DroppedFrameCounter dropped_frame_counter_;
TotalFrameCounter total_frame_counter_;
std::unique_ptr<CompositorFrameReporter> pipeline_reporter_;
+
+ // Number of breakdown stages of the current PipelineReporter
+ const int kNumOfCompositorStages =
+ static_cast<int>(CompositorFrameReporter::StageType::kStageTypeCount) - 1;
+ const int kNumDispatchStages =
+ static_cast<int>(EventMetrics::DispatchStage::kMaxValue);
+ const base::TimeDelta kLatencyPredictionDeviationThreshold =
+ base::Milliseconds(8.33);
};
TEST_F(CompositorFrameReporterTest, MainFrameAbortedReportingTest) {
@@ -161,25 +233,25 @@ TEST_F(CompositorFrameReporterTest, MainFrameAbortedReportingTest) {
Now());
EXPECT_EQ(0u, pipeline_reporter_->stage_history_size_for_testing());
- AdvanceNowByMs(3);
+ AdvanceNowByUs(3);
pipeline_reporter_->StartStage(
CompositorFrameReporter::StageType::kSendBeginMainFrameToCommit, Now());
EXPECT_EQ(1u, pipeline_reporter_->stage_history_size_for_testing());
- AdvanceNowByMs(3);
+ AdvanceNowByUs(3);
pipeline_reporter_->StartStage(
CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame,
Now());
EXPECT_EQ(2u, pipeline_reporter_->stage_history_size_for_testing());
- AdvanceNowByMs(3);
+ AdvanceNowByUs(3);
pipeline_reporter_->StartStage(
CompositorFrameReporter::StageType::
kSubmitCompositorFrameToPresentationCompositorFrame,
Now());
EXPECT_EQ(3u, pipeline_reporter_->stage_history_size_for_testing());
- AdvanceNowByMs(3);
+ AdvanceNowByUs(3);
pipeline_reporter_->TerminateFrame(
CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame, Now());
EXPECT_EQ(4u, pipeline_reporter_->stage_history_size_for_testing());
@@ -206,12 +278,12 @@ TEST_F(CompositorFrameReporterTest, ReplacedByNewReporterReportingTest) {
Now());
EXPECT_EQ(0u, pipeline_reporter_->stage_history_size_for_testing());
- AdvanceNowByMs(3);
+ AdvanceNowByUs(3);
pipeline_reporter_->StartStage(
CompositorFrameReporter::StageType::kEndCommitToActivation, Now());
EXPECT_EQ(1u, pipeline_reporter_->stage_history_size_for_testing());
- AdvanceNowByMs(2);
+ AdvanceNowByUs(2);
pipeline_reporter_->TerminateFrame(
CompositorFrameReporter::FrameTerminationStatus::kReplacedByNewReporter,
Now());
@@ -230,13 +302,13 @@ TEST_F(CompositorFrameReporterTest, SubmittedFrameReportingTest) {
CompositorFrameReporter::StageType::kActivation, Now());
EXPECT_EQ(0u, pipeline_reporter_->stage_history_size_for_testing());
- AdvanceNowByMs(3);
+ AdvanceNowByUs(3);
pipeline_reporter_->StartStage(
CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame,
Now());
EXPECT_EQ(1u, pipeline_reporter_->stage_history_size_for_testing());
- AdvanceNowByMs(2);
+ AdvanceNowByUs(2);
pipeline_reporter_->TerminateFrame(
CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame, Now());
EXPECT_EQ(2u, pipeline_reporter_->stage_history_size_for_testing());
@@ -266,12 +338,12 @@ TEST_F(CompositorFrameReporterTest, SubmittedDroppedFrameReportingTest) {
CompositorFrameReporter::StageType::kSendBeginMainFrameToCommit, Now());
EXPECT_EQ(0u, pipeline_reporter_->stage_history_size_for_testing());
- AdvanceNowByMs(3);
+ AdvanceNowByUs(3);
pipeline_reporter_->StartStage(CompositorFrameReporter::StageType::kCommit,
Now());
EXPECT_EQ(1u, pipeline_reporter_->stage_history_size_for_testing());
- AdvanceNowByMs(2);
+ AdvanceNowByUs(2);
pipeline_reporter_->TerminateFrame(
CompositorFrameReporter::FrameTerminationStatus::kDidNotPresentFrame,
Now());
@@ -313,24 +385,24 @@ TEST_F(CompositorFrameReporterTest,
std::make_move_iterator(std::end(event_metrics_ptrs)));
std::vector<base::TimeTicks> event_times = GetEventTimestamps(events_metrics);
- AdvanceNowByMs(3);
+ AdvanceNowByUs(3);
pipeline_reporter_->StartStage(
CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame,
Now());
- AdvanceNowByMs(3);
+ AdvanceNowByUs(3);
pipeline_reporter_->StartStage(
CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame,
Now());
- AdvanceNowByMs(3);
+ AdvanceNowByUs(3);
pipeline_reporter_->StartStage(
CompositorFrameReporter::StageType::
kSubmitCompositorFrameToPresentationCompositorFrame,
Now());
pipeline_reporter_->AddEventsMetrics(std::move(events_metrics));
- const base::TimeTicks presentation_time = AdvanceNowByMs(3);
+ const base::TimeTicks presentation_time = AdvanceNowByUs(3);
pipeline_reporter_->TerminateFrame(
CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame,
presentation_time);
@@ -405,24 +477,24 @@ TEST_F(CompositorFrameReporterTest,
std::make_move_iterator(std::end(event_metrics_ptrs)));
std::vector<base::TimeTicks> event_times = GetEventTimestamps(events_metrics);
- AdvanceNowByMs(3);
+ AdvanceNowByUs(3);
pipeline_reporter_->StartStage(
CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame,
Now());
- AdvanceNowByMs(3);
+ AdvanceNowByUs(3);
pipeline_reporter_->StartStage(
CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame,
Now());
- AdvanceNowByMs(3);
+ AdvanceNowByUs(3);
pipeline_reporter_->StartStage(
CompositorFrameReporter::StageType::
kSubmitCompositorFrameToPresentationCompositorFrame,
Now());
pipeline_reporter_->AddEventsMetrics(std::move(events_metrics));
- AdvanceNowByMs(3);
+ AdvanceNowByUs(3);
viz::FrameTimingDetails viz_breakdown = BuildVizBreakdown();
pipeline_reporter_->SetVizBreakdown(viz_breakdown);
pipeline_reporter_->TerminateFrame(
@@ -493,24 +565,24 @@ TEST_F(CompositorFrameReporterTest,
std::make_move_iterator(std::end(event_metrics_ptrs)));
std::vector<base::TimeTicks> event_times = GetEventTimestamps(events_metrics);
- AdvanceNowByMs(3);
+ AdvanceNowByUs(3);
pipeline_reporter_->StartStage(
CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame,
Now());
- AdvanceNowByMs(3);
+ AdvanceNowByUs(3);
pipeline_reporter_->StartStage(
CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame,
Now());
- AdvanceNowByMs(3);
+ AdvanceNowByUs(3);
pipeline_reporter_->StartStage(
CompositorFrameReporter::StageType::
kSubmitCompositorFrameToPresentationCompositorFrame,
Now());
pipeline_reporter_->AddEventsMetrics(std::move(events_metrics));
- AdvanceNowByMs(3);
+ AdvanceNowByUs(3);
viz::FrameTimingDetails viz_breakdown = BuildVizBreakdown();
pipeline_reporter_->SetVizBreakdown(viz_breakdown);
pipeline_reporter_->TerminateFrame(
@@ -575,24 +647,24 @@ TEST_F(CompositorFrameReporterTest,
std::make_move_iterator(std::begin(event_metrics_ptrs)),
std::make_move_iterator(std::end(event_metrics_ptrs)));
- AdvanceNowByMs(3);
+ AdvanceNowByUs(3);
pipeline_reporter_->StartStage(
CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame,
Now());
- AdvanceNowByMs(3);
+ AdvanceNowByUs(3);
pipeline_reporter_->StartStage(
CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame,
Now());
- AdvanceNowByMs(3);
+ AdvanceNowByUs(3);
pipeline_reporter_->StartStage(
CompositorFrameReporter::StageType::
kSubmitCompositorFrameToPresentationCompositorFrame,
Now());
pipeline_reporter_->AddEventsMetrics(std::move(events_metrics));
- AdvanceNowByMs(3);
+ AdvanceNowByUs(3);
pipeline_reporter_->TerminateFrame(
CompositorFrameReporter::FrameTerminationStatus::kDidNotPresentFrame,
Now());
@@ -720,5 +792,1367 @@ TEST_F(CompositorFrameReporterTest, PartialUpdateDependentQueues) {
pipeline_reporter_->owned_partial_update_dependents_size_for_testing());
}
+TEST_F(CompositorFrameReporterTest, StageLatencyGeneralPrediction) {
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame,
+ Now());
+
+ AdvanceNowByUs(3);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kSendBeginMainFrameToCommit, Now());
+ AdvanceNowByUs(4);
+ base::TimeTicks begin_main_frame_start_time = Now();
+ std::unique_ptr<BeginMainFrameMetrics> blink_breakdown =
+ BuildBlinkBreakdown();
+ pipeline_reporter_->SetBlinkBreakdown(std::move(blink_breakdown),
+ begin_main_frame_start_time);
+
+ pipeline_reporter_->StartStage(CompositorFrameReporter::StageType::kCommit,
+ Now());
+
+ AdvanceNowByUs(3);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kEndCommitToActivation, Now());
+
+ AdvanceNowByUs(3);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kActivation, Now());
+
+ AdvanceNowByUs(3);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame,
+ Now());
+
+ AdvanceNowByUs(3);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::
+ kSubmitCompositorFrameToPresentationCompositorFrame,
+ Now());
+ viz::FrameTimingDetails viz_breakdown = BuildVizBreakdown();
+ pipeline_reporter_->SetVizBreakdown(viz_breakdown);
+
+ pipeline_reporter_->TerminateFrame(
+ CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame,
+ viz_breakdown.presentation_feedback.timestamp);
+
+ // predictions when this is the very first prediction
+ CompositorFrameReporter::CompositorLatencyInfo expected_latency_predictions1;
+ expected_latency_predictions1.top_level_stages = {
+ base::Microseconds(3), base::Microseconds(55), base::Microseconds(3),
+ base::Microseconds(3), base::Microseconds(3), base::Microseconds(3),
+ base::Microseconds(15)};
+ expected_latency_predictions1.blink_breakdown_stages = {
+ base::Microseconds(10), base::Microseconds(9), base::Microseconds(8),
+ base::Microseconds(7), base::Microseconds(0), base::Microseconds(5),
+ base::Microseconds(6), base::Microseconds(3), base::Microseconds(2),
+ base::Microseconds(1), base::Microseconds(4)};
+ expected_latency_predictions1.viz_breakdown_stages = {
+ base::Microseconds(1), base::Microseconds(2), base::Microseconds(3),
+ base::Microseconds(4), base::Microseconds(5), base::Microseconds(0),
+ base::Microseconds(0), base::Microseconds(0), base::Microseconds(0)};
+ expected_latency_predictions1.total_latency = base::Microseconds(85);
+ expected_latency_predictions1.total_blink_latency = base::Microseconds(55);
+ expected_latency_predictions1.total_viz_latency = base::Microseconds(15);
+
+ // predictions when there exists a previous prediction
+ CompositorFrameReporter::CompositorLatencyInfo expected_latency_predictions2(
+ base::Microseconds(0));
+ expected_latency_predictions2.top_level_stages = {
+ base::Microseconds(1), base::Microseconds(13), base::Microseconds(3),
+ base::Microseconds(0), base::Microseconds(2), base::Microseconds(3),
+ base::Microseconds(3)};
+ expected_latency_predictions2.blink_breakdown_stages = {
+ base::Microseconds(10), base::Microseconds(9), base::Microseconds(8),
+ base::Microseconds(7), base::Microseconds(0), base::Microseconds(5),
+ base::Microseconds(6), base::Microseconds(3), base::Microseconds(2),
+ base::Microseconds(1), base::Microseconds(4)};
+ expected_latency_predictions2.viz_breakdown_stages = {
+ base::Microseconds(1), base::Microseconds(2), base::Microseconds(3),
+ base::Microseconds(4), base::Microseconds(5), base::Microseconds(0),
+ base::Microseconds(0), base::Microseconds(0), base::Microseconds(0)};
+ expected_latency_predictions2.total_latency = base::Microseconds(28);
+ expected_latency_predictions2.total_blink_latency = base::Microseconds(55);
+ expected_latency_predictions2.total_viz_latency = base::Microseconds(15);
+
+ // expected attribution for all 3 cases above
+ std::vector<std::string> expected_latency_attributions = {};
+
+ CompositorFrameReporter::CompositorLatencyInfo actual_latency_predictions1(
+ base::Microseconds(-1));
+ pipeline_reporter_->CalculateCompositorLatencyPrediction(
+ actual_latency_predictions1, kLatencyPredictionDeviationThreshold);
+ std::vector<std::string> actual_latency_attributions1 =
+ pipeline_reporter_->high_latency_substages_for_testing();
+ pipeline_reporter_->ClearHighLatencySubstagesForTesting();
+
+ CompositorFrameReporter::CompositorLatencyInfo actual_latency_predictions2(
+ base::Microseconds(0));
+ actual_latency_predictions2.top_level_stages = {
+ base::Microseconds(1), base::Microseconds(0), base::Microseconds(4),
+ base::Microseconds(0), base::Microseconds(2), base::Microseconds(3),
+ base::Microseconds(0)};
+ actual_latency_predictions2.total_latency = base::Microseconds(10);
+ pipeline_reporter_->CalculateCompositorLatencyPrediction(
+ actual_latency_predictions2, kLatencyPredictionDeviationThreshold);
+ std::vector<std::string> actual_latency_attributions2 =
+ pipeline_reporter_->high_latency_substages_for_testing();
+ pipeline_reporter_->ClearHighLatencySubstagesForTesting();
+
+ VerifyLatencyInfo(expected_latency_predictions1, actual_latency_predictions1);
+ VerifyLatencyInfo(expected_latency_predictions2, actual_latency_predictions2);
+
+ EXPECT_EQ(expected_latency_attributions, actual_latency_attributions1);
+ EXPECT_EQ(expected_latency_attributions, actual_latency_attributions2);
+
+ pipeline_reporter_ = nullptr;
+}
+
+TEST_F(CompositorFrameReporterTest, StageLatencyAllZeroPrediction) {
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame,
+ Now());
+
+ AdvanceNowByUs(0);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kSendBeginMainFrameToCommit, Now());
+
+ AdvanceNowByUs(0);
+ pipeline_reporter_->StartStage(CompositorFrameReporter::StageType::kCommit,
+ Now());
+
+ AdvanceNowByUs(0);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kEndCommitToActivation, Now());
+
+ AdvanceNowByUs(0);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kActivation, Now());
+
+ AdvanceNowByUs(0);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame,
+ Now());
+
+ AdvanceNowByUs(0);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::
+ kSubmitCompositorFrameToPresentationCompositorFrame,
+ Now());
+
+ AdvanceNowByUs(0);
+ pipeline_reporter_->TerminateFrame(
+ CompositorFrameReporter::FrameTerminationStatus::kDidNotProduceFrame,
+ Now());
+
+ // predictions when this is the very first prediction
+ CompositorFrameReporter::CompositorLatencyInfo expected_latency_predictions1(
+ base::Microseconds(-1));
+
+ // predictions when there exists a previous prediction
+ CompositorFrameReporter::CompositorLatencyInfo expected_latency_predictions2(
+ base::Microseconds(0));
+ expected_latency_predictions2.top_level_stages = {
+ base::Microseconds(1), base::Microseconds(0), base::Microseconds(4),
+ base::Microseconds(0), base::Microseconds(2), base::Microseconds(3),
+ base::Microseconds(0)};
+ expected_latency_predictions2.total_latency = base::Microseconds(10);
+
+ // expected attribution for all 3 cases above
+ std::vector<std::string> expected_latency_attributions = {};
+
+ CompositorFrameReporter::CompositorLatencyInfo actual_latency_predictions1(
+ base::Microseconds(-1));
+ pipeline_reporter_->CalculateCompositorLatencyPrediction(
+ actual_latency_predictions1, kLatencyPredictionDeviationThreshold);
+ std::vector<std::string> actual_latency_attributions1 =
+ pipeline_reporter_->high_latency_substages_for_testing();
+ pipeline_reporter_->ClearHighLatencySubstagesForTesting();
+
+ CompositorFrameReporter::CompositorLatencyInfo actual_latency_predictions2(
+ base::Microseconds(0));
+ actual_latency_predictions2.top_level_stages = {
+ base::Microseconds(1), base::Microseconds(0), base::Microseconds(4),
+ base::Microseconds(0), base::Microseconds(2), base::Microseconds(3),
+ base::Microseconds(0)};
+ actual_latency_predictions2.total_latency = base::Microseconds(10);
+
+ pipeline_reporter_->CalculateCompositorLatencyPrediction(
+ actual_latency_predictions2, kLatencyPredictionDeviationThreshold);
+ std::vector<std::string> actual_latency_attributions2 =
+ pipeline_reporter_->high_latency_substages_for_testing();
+ pipeline_reporter_->ClearHighLatencySubstagesForTesting();
+
+ VerifyLatencyInfo(expected_latency_predictions1, actual_latency_predictions1);
+ VerifyLatencyInfo(expected_latency_predictions2, actual_latency_predictions2);
+
+ EXPECT_EQ(expected_latency_attributions, actual_latency_attributions1);
+ EXPECT_EQ(expected_latency_attributions, actual_latency_attributions2);
+
+ pipeline_reporter_ = nullptr;
+}
+
+TEST_F(CompositorFrameReporterTest, StageLatencyLargeDurationPrediction) {
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame,
+ Now());
+
+ AdvanceNowByUs(10000000);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kSendBeginMainFrameToCommit, Now());
+ AdvanceNowByUs(400000);
+ base::TimeTicks begin_main_frame_start_time = Now();
+
+ auto blink_breakdown = std::make_unique<BeginMainFrameMetrics>();
+ blink_breakdown->handle_input_events = base::Microseconds(1000000);
+ blink_breakdown->animate = base::Microseconds(900000);
+ blink_breakdown->style_update = base::Microseconds(800000);
+ blink_breakdown->layout_update = base::Microseconds(300000);
+ blink_breakdown->accessibility = base::Microseconds(400000);
+ blink_breakdown->prepaint = base::Microseconds(500000);
+ blink_breakdown->compositing_inputs = base::Microseconds(600000);
+ blink_breakdown->paint = base::Microseconds(300000);
+ blink_breakdown->composite_commit = base::Microseconds(200000);
+ blink_breakdown->update_layers = base::Microseconds(100000);
+ AdvanceNowByUs(5100000);
+
+ pipeline_reporter_->SetBlinkBreakdown(std::move(blink_breakdown),
+ begin_main_frame_start_time);
+
+ pipeline_reporter_->StartStage(CompositorFrameReporter::StageType::kCommit,
+ Now());
+
+ AdvanceNowByUs(6000000);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kEndCommitToActivation, Now());
+
+ AdvanceNowByUs(10000000);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kActivation, Now());
+
+ AdvanceNowByUs(0);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame,
+ Now());
+
+ AdvanceNowByUs(2000000);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::
+ kSubmitCompositorFrameToPresentationCompositorFrame,
+ Now());
+
+ viz::FrameTimingDetails viz_breakdown;
+ viz_breakdown.received_compositor_frame_timestamp = AdvanceNowByUs(1000000);
+ viz_breakdown.draw_start_timestamp = AdvanceNowByUs(2000000);
+ viz_breakdown.swap_timings.swap_start = AdvanceNowByUs(3000000);
+ viz_breakdown.presentation_feedback.available_timestamp =
+ AdvanceNowByUs(15000000);
+ viz_breakdown.presentation_feedback.ready_timestamp = AdvanceNowByUs(700000);
+ viz_breakdown.presentation_feedback.latch_timestamp = AdvanceNowByUs(800000);
+ viz_breakdown.swap_timings.swap_end = AdvanceNowByUs(1000000);
+ viz_breakdown.presentation_feedback.timestamp = AdvanceNowByUs(5000000);
+
+ pipeline_reporter_->SetVizBreakdown(viz_breakdown);
+
+ pipeline_reporter_->TerminateFrame(
+ CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame, Now());
+
+ // predictions when this is the very first prediction
+ CompositorFrameReporter::CompositorLatencyInfo expected_latency_predictions1;
+ expected_latency_predictions1.top_level_stages = {
+ base::Microseconds(10000000), base::Microseconds(5500000),
+ base::Microseconds(6000000), base::Microseconds(10000000),
+ base::Microseconds(0), base::Microseconds(2000000),
+ base::Microseconds(28500000)};
+ expected_latency_predictions1.blink_breakdown_stages = {
+ base::Microseconds(1000000), base::Microseconds(900000),
+ base::Microseconds(800000), base::Microseconds(300000),
+ base::Microseconds(400000), base::Microseconds(500000),
+ base::Microseconds(600000), base::Microseconds(300000),
+ base::Microseconds(200000), base::Microseconds(100000),
+ base::Microseconds(400000)};
+ expected_latency_predictions1.viz_breakdown_stages = {
+ base::Microseconds(1000000), base::Microseconds(2000000),
+ base::Microseconds(3000000), base::Microseconds(0),
+ base::Microseconds(5000000), base::Microseconds(15000000),
+ base::Microseconds(700000), base::Microseconds(800000),
+ base::Microseconds(1000000)};
+ expected_latency_predictions1.total_latency = base::Microseconds(62000000);
+ expected_latency_predictions1.total_blink_latency =
+ base::Microseconds(5500000);
+ expected_latency_predictions1.total_viz_latency =
+ base::Microseconds(28500000);
+
+ // predictions when there exists a previous prediction
+ CompositorFrameReporter::CompositorLatencyInfo expected_latency_predictions2;
+ expected_latency_predictions2.top_level_stages = {
+ base::Microseconds(8500000), base::Microseconds(4375000),
+ base::Microseconds(4875000), base::Microseconds(5252650),
+ base::Microseconds(750000), base::Microseconds(1850000),
+ base::Microseconds(18375000)};
+ expected_latency_predictions2.blink_breakdown_stages = {
+ base::Microseconds(1000000), base::Microseconds(225000),
+ base::Microseconds(500000), base::Microseconds(75000),
+ base::Microseconds(250000), base::Microseconds(350000),
+ base::Microseconds(150000), base::Microseconds(750000),
+ base::Microseconds(650000), base::Microseconds(250000),
+ base::Microseconds(175000)};
+ expected_latency_predictions2.viz_breakdown_stages = {
+ base::Microseconds(625000), base::Microseconds(875000),
+ base::Microseconds(1500000), base::Microseconds(0),
+ base::Microseconds(1706075), base::Microseconds(9750000),
+ base::Microseconds(925000), base::Microseconds(1100000),
+ base::Microseconds(1893925)};
+ expected_latency_predictions2.total_latency = base::Microseconds(43977650);
+ expected_latency_predictions2.total_blink_latency =
+ base::Microseconds(4375000);
+ expected_latency_predictions2.total_viz_latency =
+ base::Microseconds(18375000);
+
+ // expected attribution for cases 1 above
+ std::vector<std::string> expected_latency_attributions1 = {};
+
+ // expected attribution for case 2 above
+ std::vector<std::string> expected_latency_attributions2 = {
+ "EndCommitToActivation",
+ "SubmitCompositorFrameToPresentationCompositorFrame."
+ "SwapEndToPresentationCompositorFrame"};
+
+ CompositorFrameReporter::CompositorLatencyInfo actual_latency_predictions1(
+ base::Microseconds(-1));
+ pipeline_reporter_->CalculateCompositorLatencyPrediction(
+ actual_latency_predictions1, kLatencyPredictionDeviationThreshold);
+ std::vector<std::string> actual_latency_attributions1 =
+ pipeline_reporter_->high_latency_substages_for_testing();
+ pipeline_reporter_->ClearHighLatencySubstagesForTesting();
+
+ CompositorFrameReporter::CompositorLatencyInfo actual_latency_predictions2;
+ actual_latency_predictions2.top_level_stages = {
+ base::Microseconds(8000000), base::Microseconds(4000000),
+ base::Microseconds(4500000), base::Microseconds(3670200),
+ base::Microseconds(1000000), base::Microseconds(1800000),
+ base::Microseconds(15000000)};
+ actual_latency_predictions2.blink_breakdown_stages = {
+ base::Microseconds(1000000), base::Microseconds(0),
+ base::Microseconds(400000), base::Microseconds(0),
+ base::Microseconds(200000), base::Microseconds(300000),
+ base::Microseconds(0), base::Microseconds(900000),
+ base::Microseconds(800000), base::Microseconds(300000),
+ base::Microseconds(100000)};
+ actual_latency_predictions2.viz_breakdown_stages = {
+ base::Microseconds(500000), base::Microseconds(500000),
+ base::Microseconds(1000000), base::Microseconds(0),
+ base::Microseconds(608100), base::Microseconds(8000000),
+ base::Microseconds(1000000), base::Microseconds(1200000),
+ base::Microseconds(2191900)};
+ actual_latency_predictions2.total_latency = base::Microseconds(37970200);
+ actual_latency_predictions2.total_blink_latency = base::Microseconds(4000000);
+ actual_latency_predictions2.total_viz_latency = base::Microseconds(15000000);
+
+ pipeline_reporter_->CalculateCompositorLatencyPrediction(
+ actual_latency_predictions2, kLatencyPredictionDeviationThreshold);
+ std::vector<std::string> actual_latency_attributions2 =
+ pipeline_reporter_->high_latency_substages_for_testing();
+ pipeline_reporter_->ClearHighLatencySubstagesForTesting();
+
+ VerifyLatencyInfo(expected_latency_predictions1, actual_latency_predictions1);
+ VerifyLatencyInfo(expected_latency_predictions2, actual_latency_predictions2);
+
+ EXPECT_EQ(expected_latency_attributions1, actual_latency_attributions1);
+ EXPECT_EQ(expected_latency_attributions2, actual_latency_attributions2);
+
+ pipeline_reporter_ = nullptr;
+}
+
+TEST_F(CompositorFrameReporterTest, StageLatencyMultiplePrediction) {
+ CompositorFrameReporter::CompositorLatencyInfo actual_latency_predictions(
+ base::Microseconds(-1));
+ CompositorFrameReporter::CompositorLatencyInfo expected_latency_predictions(
+ base::Microseconds(-1));
+
+ // First compositor reporter (general)
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame,
+ Now());
+
+ AdvanceNowByUs(16000);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame,
+ Now());
+
+ AdvanceNowByUs(1500);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::
+ kSubmitCompositorFrameToPresentationCompositorFrame,
+ Now());
+
+ viz::FrameTimingDetails viz_breakdown;
+ viz_breakdown.received_compositor_frame_timestamp = AdvanceNowByUs(330000);
+ viz_breakdown.draw_start_timestamp = AdvanceNowByUs(23000);
+ viz_breakdown.swap_timings.swap_start = AdvanceNowByUs(170000);
+ viz_breakdown.swap_timings.swap_end = AdvanceNowByUs(280000);
+ viz_breakdown.presentation_feedback.timestamp = AdvanceNowByUs(30000);
+
+ pipeline_reporter_->SetVizBreakdown(viz_breakdown);
+
+ pipeline_reporter_->TerminateFrame(
+ CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame, Now());
+
+ expected_latency_predictions.top_level_stages = {
+ base::Microseconds(16000), base::Microseconds(0),
+ base::Microseconds(0), base::Microseconds(0),
+ base::Microseconds(0), base::Microseconds(1500),
+ base::Microseconds(833000)};
+ expected_latency_predictions.blink_breakdown_stages = {
+ base::Microseconds(0), base::Microseconds(0), base::Microseconds(0),
+ base::Microseconds(0), base::Microseconds(0), base::Microseconds(0),
+ base::Microseconds(0), base::Microseconds(0), base::Microseconds(0),
+ base::Microseconds(0), base::Microseconds(0)};
+ expected_latency_predictions.viz_breakdown_stages = {
+ base::Microseconds(330000), base::Microseconds(23000),
+ base::Microseconds(170000), base::Microseconds(280000),
+ base::Microseconds(30000), base::Microseconds(0),
+ base::Microseconds(0), base::Microseconds(0),
+ base::Microseconds(0)};
+ expected_latency_predictions.total_latency = base::Microseconds(850500);
+ expected_latency_predictions.total_blink_latency = base::Microseconds(0);
+ expected_latency_predictions.total_viz_latency = base::Microseconds(833000);
+
+ pipeline_reporter_->CalculateCompositorLatencyPrediction(
+ actual_latency_predictions, kLatencyPredictionDeviationThreshold);
+
+ VerifyLatencyInfo(expected_latency_predictions, actual_latency_predictions);
+
+ // Second compositor reporter (without subtmit stage)
+ pipeline_reporter_ = CreatePipelineReporter();
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame,
+ Now());
+
+ AdvanceNowByUs(16000);
+ pipeline_reporter_->TerminateFrame(
+ CompositorFrameReporter::FrameTerminationStatus::kDidNotProduceFrame,
+ Now());
+
+ expected_latency_predictions.top_level_stages = {
+ base::Microseconds(16000), base::Microseconds(0),
+ base::Microseconds(0), base::Microseconds(0),
+ base::Microseconds(0), base::Microseconds(1500),
+ base::Microseconds(833000)};
+ expected_latency_predictions.blink_breakdown_stages = {
+ base::Microseconds(0), base::Microseconds(0), base::Microseconds(0),
+ base::Microseconds(0), base::Microseconds(0), base::Microseconds(0),
+ base::Microseconds(0), base::Microseconds(0), base::Microseconds(0),
+ base::Microseconds(0), base::Microseconds(0)};
+ expected_latency_predictions.viz_breakdown_stages = {
+ base::Microseconds(330000), base::Microseconds(23000),
+ base::Microseconds(170000), base::Microseconds(280000),
+ base::Microseconds(30000), base::Microseconds(0),
+ base::Microseconds(0), base::Microseconds(0),
+ base::Microseconds(0)};
+ expected_latency_predictions.total_latency = base::Microseconds(850500);
+ expected_latency_predictions.total_blink_latency = base::Microseconds(0);
+ expected_latency_predictions.total_viz_latency = base::Microseconds(833000);
+
+ pipeline_reporter_->CalculateCompositorLatencyPrediction(
+ actual_latency_predictions, kLatencyPredictionDeviationThreshold);
+
+ VerifyLatencyInfo(expected_latency_predictions, actual_latency_predictions);
+
+ // Third compositor reporter (prediction and actual latency does not differ
+ // by 8)
+ pipeline_reporter_ = CreatePipelineReporter();
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame,
+ Now());
+
+ AdvanceNowByUs(16500);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame,
+ Now());
+
+ AdvanceNowByUs(2000);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::
+ kSubmitCompositorFrameToPresentationCompositorFrame,
+ Now());
+
+ viz_breakdown.received_compositor_frame_timestamp = AdvanceNowByUs(330000);
+ viz_breakdown.draw_start_timestamp = AdvanceNowByUs(23000);
+ viz_breakdown.swap_timings.swap_start = AdvanceNowByUs(170000);
+ viz_breakdown.swap_timings.swap_end = AdvanceNowByUs(280000);
+ viz_breakdown.presentation_feedback.timestamp = AdvanceNowByUs(30000);
+
+ pipeline_reporter_->SetVizBreakdown(viz_breakdown);
+
+ pipeline_reporter_->TerminateFrame(
+ CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame, Now());
+
+ expected_latency_predictions.top_level_stages = {
+ base::Microseconds(16125), base::Microseconds(0),
+ base::Microseconds(0), base::Microseconds(0),
+ base::Microseconds(0), base::Microseconds(1625),
+ base::Microseconds(833000)};
+ expected_latency_predictions.blink_breakdown_stages = {
+ base::Microseconds(0), base::Microseconds(0), base::Microseconds(0),
+ base::Microseconds(0), base::Microseconds(0), base::Microseconds(0),
+ base::Microseconds(0), base::Microseconds(0), base::Microseconds(0),
+ base::Microseconds(0), base::Microseconds(0)};
+ expected_latency_predictions.viz_breakdown_stages = {
+ base::Microseconds(330000), base::Microseconds(23000),
+ base::Microseconds(170000), base::Microseconds(280000),
+ base::Microseconds(30000), base::Microseconds(0),
+ base::Microseconds(0), base::Microseconds(0),
+ base::Microseconds(0)};
+ expected_latency_predictions.total_latency = base::Microseconds(850750);
+ expected_latency_predictions.total_blink_latency = base::Microseconds(0);
+ expected_latency_predictions.total_viz_latency = base::Microseconds(833000);
+
+ pipeline_reporter_->CalculateCompositorLatencyPrediction(
+ actual_latency_predictions, kLatencyPredictionDeviationThreshold);
+
+ VerifyLatencyInfo(expected_latency_predictions, actual_latency_predictions);
+
+ // Fourth compositor reporter (total duration is 0)
+ pipeline_reporter_ = CreatePipelineReporter();
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame,
+ Now());
+
+ AdvanceNowByUs(0);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kSendBeginMainFrameToCommit, Now());
+
+ AdvanceNowByUs(0);
+ pipeline_reporter_->StartStage(CompositorFrameReporter::StageType::kCommit,
+ Now());
+
+ AdvanceNowByUs(0);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kEndCommitToActivation, Now());
+
+ AdvanceNowByUs(0);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::
+ kSubmitCompositorFrameToPresentationCompositorFrame,
+ Now());
+
+ AdvanceNowByUs(0);
+ pipeline_reporter_->TerminateFrame(
+ CompositorFrameReporter::FrameTerminationStatus::kDidNotProduceFrame,
+ Now());
+
+ expected_latency_predictions.top_level_stages = {
+ base::Microseconds(16125), base::Microseconds(0),
+ base::Microseconds(0), base::Microseconds(0),
+ base::Microseconds(0), base::Microseconds(1625),
+ base::Microseconds(833000)};
+ expected_latency_predictions.blink_breakdown_stages = {
+ base::Microseconds(0), base::Microseconds(0), base::Microseconds(0),
+ base::Microseconds(0), base::Microseconds(0), base::Microseconds(0),
+ base::Microseconds(0), base::Microseconds(0), base::Microseconds(0),
+ base::Microseconds(0), base::Microseconds(0)};
+ expected_latency_predictions.viz_breakdown_stages = {
+ base::Microseconds(330000), base::Microseconds(23000),
+ base::Microseconds(170000), base::Microseconds(280000),
+ base::Microseconds(30000), base::Microseconds(0),
+ base::Microseconds(0), base::Microseconds(0),
+ base::Microseconds(0)};
+ expected_latency_predictions.total_latency = base::Microseconds(850750);
+ expected_latency_predictions.total_blink_latency = base::Microseconds(0);
+ expected_latency_predictions.total_viz_latency = base::Microseconds(833000);
+
+ pipeline_reporter_->CalculateCompositorLatencyPrediction(
+ actual_latency_predictions, kLatencyPredictionDeviationThreshold);
+
+ VerifyLatencyInfo(expected_latency_predictions, actual_latency_predictions);
+
+ // Fifth compositor reporter (prediction and actual latency differ by a lot)
+ pipeline_reporter_ = CreatePipelineReporter();
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame,
+ Now());
+
+ AdvanceNowByUs(16000);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kSendBeginMainFrameToCommit, Now());
+
+ AdvanceNowByUs(4000);
+ base::TimeTicks begin_main_frame_start_time = Now();
+
+ auto blink_breakdown = std::make_unique<BeginMainFrameMetrics>();
+ blink_breakdown->handle_input_events = base::Microseconds(12000);
+ blink_breakdown->animate = base::Microseconds(3000);
+ blink_breakdown->style_update = base::Microseconds(7000);
+ blink_breakdown->layout_update = base::Microseconds(19000);
+ blink_breakdown->accessibility = base::Microseconds(800);
+ blink_breakdown->prepaint = base::Microseconds(4100);
+ blink_breakdown->compositing_inputs = base::Microseconds(5100);
+ blink_breakdown->paint = base::Microseconds(1500);
+ blink_breakdown->composite_commit = base::Microseconds(1500);
+ blink_breakdown->update_layers = base::Microseconds(2000);
+ AdvanceNowByUs(56000);
+
+ pipeline_reporter_->SetBlinkBreakdown(std::move(blink_breakdown),
+ begin_main_frame_start_time);
+
+ pipeline_reporter_->StartStage(CompositorFrameReporter::StageType::kCommit,
+ Now());
+
+ AdvanceNowByUs(6000);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kEndCommitToActivation, Now());
+
+ AdvanceNowByUs(3000);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kActivation, Now());
+
+ AdvanceNowByUs(300);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame,
+ Now());
+
+ AdvanceNowByUs(39000);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::
+ kSubmitCompositorFrameToPresentationCompositorFrame,
+ Now());
+
+ viz_breakdown.received_compositor_frame_timestamp = AdvanceNowByUs(340000);
+ viz_breakdown.draw_start_timestamp = AdvanceNowByUs(20000);
+ viz_breakdown.swap_timings.swap_start = AdvanceNowByUs(160000);
+ viz_breakdown.swap_timings.swap_end = AdvanceNowByUs(283000);
+ viz_breakdown.presentation_feedback.timestamp = AdvanceNowByUs(30000);
+
+ pipeline_reporter_->SetVizBreakdown(viz_breakdown);
+
+ pipeline_reporter_->TerminateFrame(
+ CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame, Now());
+
+ expected_latency_predictions.top_level_stages = {
+ base::Microseconds(16093), base::Microseconds(15000),
+ base::Microseconds(1500), base::Microseconds(750),
+ base::Microseconds(75), base::Microseconds(10968),
+ base::Microseconds(833000)};
+ expected_latency_predictions.blink_breakdown_stages = {
+ base::Microseconds(12000), base::Microseconds(3000),
+ base::Microseconds(7000), base::Microseconds(19000),
+ base::Microseconds(800), base::Microseconds(4100),
+ base::Microseconds(5100), base::Microseconds(1500),
+ base::Microseconds(1500), base::Microseconds(2000),
+ base::Microseconds(4000)};
+ expected_latency_predictions.viz_breakdown_stages = {
+ base::Microseconds(332500), base::Microseconds(22250),
+ base::Microseconds(167500), base::Microseconds(280750),
+ base::Microseconds(30000), base::Microseconds(0),
+ base::Microseconds(0), base::Microseconds(0),
+ base::Microseconds(0)};
+ expected_latency_predictions.total_latency = base::Microseconds(877387);
+ expected_latency_predictions.total_blink_latency = base::Microseconds(60000);
+ expected_latency_predictions.total_viz_latency = base::Microseconds(833000);
+
+ std::vector<std::string> expected_latency_attributions = {
+ "EndActivateToSubmitCompositorFrame"};
+
+ pipeline_reporter_->CalculateCompositorLatencyPrediction(
+ actual_latency_predictions, kLatencyPredictionDeviationThreshold);
+ std::vector<std::string> actual_latency_attributions =
+ pipeline_reporter_->high_latency_substages_for_testing();
+
+ VerifyLatencyInfo(expected_latency_predictions, actual_latency_predictions);
+ EXPECT_EQ(expected_latency_attributions, actual_latency_attributions);
+
+ pipeline_reporter_ = nullptr;
+}
+
+// Tests that when a frame is presented to the user, event latency predictions
+// are reported properly.
+TEST_F(CompositorFrameReporterTest, EventLatencyDispatchPredictions) {
+ std::vector<int> dispatch_times = {300, 300, 300, 300, 300};
+ std::unique_ptr<EventMetrics> event_metrics_ptrs[] = {
+ CreateScrollUpdateEventMetricsWithDispatchTimes(
+ false, ScrollUpdateEventMetrics::ScrollUpdateType::kContinued,
+ dispatch_times)};
+ EXPECT_THAT(event_metrics_ptrs, Each(NotNull()));
+ EventMetrics::List events_metrics = {
+ std::make_move_iterator(std::begin(event_metrics_ptrs)),
+ std::make_move_iterator(std::end(event_metrics_ptrs))};
+
+ AdvanceNowByUs(300); // Transition time
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame,
+ Now());
+
+ AdvanceNowByUs(300); // kEndActivateToSubmitCompositorFrame stage duration
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::
+ kSubmitCompositorFrameToPresentationCompositorFrame,
+ Now());
+
+ pipeline_reporter_->AddEventsMetrics(std::move(events_metrics));
+
+ // Test with no previous stage predictions.
+ std::vector<base::TimeDelta> expected_predictions1(kNumDispatchStages,
+ base::Microseconds(-1));
+ IntToTimeDeltaVector(expected_predictions1,
+ std::vector<int>{300, 300, 300, 300, 300});
+ base::TimeDelta expected_transition1 = base::Microseconds(300);
+ base::TimeDelta expected_total1 = base::Microseconds(2100);
+ CompositorFrameReporter::EventLatencyInfo actual_predictions1 =
+ CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages,
+ kNumOfCompositorStages);
+ pipeline_reporter_->CalculateEventLatencyPrediction(
+ actual_predictions1, kLatencyPredictionDeviationThreshold);
+
+ // Test with all previous stage predictions.
+ std::vector<base::TimeDelta> expected_predictions2(kNumDispatchStages,
+ base::Microseconds(-1));
+ IntToTimeDeltaVector(expected_predictions2,
+ std::vector<int>{262, 300, 412, 225, 450});
+ base::TimeDelta expected_transition2 = base::Microseconds(390);
+ base::TimeDelta expected_total2 = base::Microseconds(2339);
+ CompositorFrameReporter::EventLatencyInfo actual_predictions2 =
+ CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages,
+ kNumOfCompositorStages);
+ IntToTimeDeltaVector(actual_predictions2.dispatch_durations,
+ std::vector<int>{250, 300, 450, 200, 500});
+ actual_predictions2.transition_duration = base::Microseconds(420);
+ pipeline_reporter_->CalculateEventLatencyPrediction(
+ actual_predictions2, kLatencyPredictionDeviationThreshold);
+
+ // Test with some previous stage predictions.
+ std::vector<base::TimeDelta> expected_predictions3(kNumDispatchStages,
+ base::Microseconds(-1));
+ IntToTimeDeltaVector(expected_predictions3,
+ std::vector<int>{375, 450, 300, 300, 300});
+ base::TimeDelta expected_transition3 = base::Microseconds(270);
+ base::TimeDelta expected_total3 = base::Microseconds(2295);
+ CompositorFrameReporter::EventLatencyInfo actual_predictions3 =
+ CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages,
+ kNumOfCompositorStages);
+ IntToTimeDeltaVector(actual_predictions3.dispatch_durations,
+ std::vector<int>{400, 500, 300, -1, -1});
+ actual_predictions3.transition_duration = base::Microseconds(260);
+ pipeline_reporter_->CalculateEventLatencyPrediction(
+ actual_predictions3, kLatencyPredictionDeviationThreshold);
+
+ for (int i = 0; i < kNumDispatchStages; i++) {
+ EXPECT_EQ(expected_predictions1[i],
+ actual_predictions1.dispatch_durations[i]);
+ EXPECT_EQ(expected_predictions2[i],
+ actual_predictions2.dispatch_durations[i]);
+ EXPECT_EQ(expected_predictions3[i],
+ actual_predictions3.dispatch_durations[i]);
+ }
+ EXPECT_EQ(expected_transition1, actual_predictions1.transition_duration);
+ EXPECT_EQ(expected_total1, actual_predictions1.total_duration);
+ EXPECT_EQ(expected_transition2, actual_predictions2.transition_duration);
+ EXPECT_EQ(expected_total2, actual_predictions2.total_duration);
+ EXPECT_EQ(expected_transition3, actual_predictions3.transition_duration);
+ EXPECT_EQ(expected_total3, actual_predictions3.total_duration);
+
+ pipeline_reporter_ = nullptr;
+}
+
+// Tests that when a new frame with missing dispatch stages is presented to
+// the user, event latency predictions are reported properly.
+TEST_F(CompositorFrameReporterTest,
+ EventLatencyDispatchPredictionsWithMissingStages) {
+ // Invalid EventLatency stage durations will cause program to crash,
+ // validity checked in event_latency_tracing_recorder.cc.
+ std::vector<int> dispatch_times = {400, 600, 700, -1, -1};
+ std::unique_ptr<EventMetrics> event_metrics_ptrs[] = {
+ CreateScrollUpdateEventMetricsWithDispatchTimes(
+ false, ScrollUpdateEventMetrics::ScrollUpdateType::kContinued,
+ dispatch_times)};
+ EXPECT_THAT(event_metrics_ptrs, Each(NotNull()));
+ EventMetrics::List events_metrics = {
+ std::make_move_iterator(std::begin(event_metrics_ptrs)),
+ std::make_move_iterator(std::end(event_metrics_ptrs))};
+
+ AdvanceNowByUs(470); // Transition time
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame,
+ Now());
+
+ AdvanceNowByUs(300); // kEndActivateToSubmitCompositorFrame stage duration
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::
+ kSubmitCompositorFrameToPresentationCompositorFrame,
+ Now());
+
+ pipeline_reporter_->AddEventsMetrics(std::move(events_metrics));
+
+ // Test with no previous stage predictions.
+ std::vector<base::TimeDelta> expected_predictions1(kNumDispatchStages,
+ base::Microseconds(-1));
+ IntToTimeDeltaVector(expected_predictions1,
+ std::vector<int>{400, 600, 700, -1, -1});
+ base::TimeDelta expected_transition1 = base::Microseconds(470);
+ base::TimeDelta expected_total1 = base::Microseconds(2470);
+ CompositorFrameReporter::EventLatencyInfo actual_predictions1 =
+ CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages,
+ kNumOfCompositorStages);
+ pipeline_reporter_->CalculateEventLatencyPrediction(
+ actual_predictions1, kLatencyPredictionDeviationThreshold);
+
+ // Test with all previous stage predictions.
+ std::vector<base::TimeDelta> expected_predictions2(kNumDispatchStages,
+ base::Microseconds(-1));
+ IntToTimeDeltaVector(expected_predictions2,
+ std::vector<int>{250, 375, 475, 200, 500});
+ base::TimeDelta expected_transition2 = base::Microseconds(402);
+ base::TimeDelta expected_total2 = base::Microseconds(2502);
+ CompositorFrameReporter::EventLatencyInfo actual_predictions2 =
+ CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages,
+ kNumOfCompositorStages);
+ IntToTimeDeltaVector(actual_predictions2.dispatch_durations,
+ std::vector<int>{200, 300, 400, 200, 500});
+ actual_predictions2.transition_duration = base::Microseconds(380);
+ pipeline_reporter_->CalculateEventLatencyPrediction(
+ actual_predictions2, kLatencyPredictionDeviationThreshold);
+
+ // Test with some previous stage predictions.
+ std::vector<base::TimeDelta> expected_predictions3(kNumDispatchStages,
+ base::Microseconds(-1));
+ IntToTimeDeltaVector(expected_predictions3,
+ std::vector<int>{400, 525, 745, -1, -1});
+ base::TimeDelta expected_transition3 = base::Microseconds(492);
+ base::TimeDelta expected_total3 = base::Microseconds(2462);
+ CompositorFrameReporter::EventLatencyInfo actual_predictions3 =
+ CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages,
+ kNumOfCompositorStages);
+ IntToTimeDeltaVector(actual_predictions3.dispatch_durations,
+ std::vector<int>{400, 500, 760, -1, -1});
+ actual_predictions3.transition_duration = base::Microseconds(500);
+ pipeline_reporter_->CalculateEventLatencyPrediction(
+ actual_predictions3, kLatencyPredictionDeviationThreshold);
+
+ for (int i = 0; i < kNumDispatchStages; i++) {
+ EXPECT_EQ(expected_predictions1[i],
+ actual_predictions1.dispatch_durations[i]);
+ EXPECT_EQ(expected_predictions2[i],
+ actual_predictions2.dispatch_durations[i]);
+ EXPECT_EQ(expected_predictions3[i],
+ actual_predictions3.dispatch_durations[i]);
+ }
+ EXPECT_EQ(expected_transition1, actual_predictions1.transition_duration);
+ EXPECT_EQ(expected_total1, actual_predictions1.total_duration);
+ EXPECT_EQ(expected_transition2, actual_predictions2.transition_duration);
+ EXPECT_EQ(expected_total2, actual_predictions2.total_duration);
+ EXPECT_EQ(expected_transition3, actual_predictions3.transition_duration);
+ EXPECT_EQ(expected_total3, actual_predictions3.total_duration);
+
+ pipeline_reporter_ = nullptr;
+}
+
+// Tests that when a frame is presented to the user, event latency predictions
+// are reported properly.
+TEST_F(CompositorFrameReporterTest, EventLatencyCompositorPredictions) {
+ std::vector<int> dispatch_times = {300, 300, 300, 300, 300};
+ std::unique_ptr<EventMetrics> event_metrics_ptrs[] = {
+ CreateScrollUpdateEventMetricsWithDispatchTimes(
+ false, ScrollUpdateEventMetrics::ScrollUpdateType::kContinued,
+ dispatch_times)};
+ EXPECT_THAT(event_metrics_ptrs, Each(NotNull()));
+ EventMetrics::List events_metrics = {
+ std::make_move_iterator(std::begin(event_metrics_ptrs)),
+ std::make_move_iterator(std::end(event_metrics_ptrs))};
+
+ AdvanceNowByUs(300); // Transition time
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame,
+ Now());
+
+ // For this test there are only 3 compositor substages updated which reflects
+ // a more realistic scenario.
+
+ AdvanceNowByUs(300); // kBeginImplFrameToSendBeginMainFrame duration
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame,
+ Now());
+
+ AdvanceNowByUs(300); // kEndActivateToSubmitCompositorFrame duration
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::
+ kSubmitCompositorFrameToPresentationCompositorFrame,
+ Now());
+
+ // kSubmitCompositorFrameToPresentationCompositorFrame duration
+ AdvanceNowByUs(300);
+ pipeline_reporter_->TerminateFrame(
+ CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame, Now());
+
+ pipeline_reporter_->AddEventsMetrics(std::move(events_metrics));
+
+ // Test with no previous stage predictions.
+ std::vector<base::TimeDelta> expected_dispatch1(kNumDispatchStages,
+ base::Microseconds(-1));
+ IntToTimeDeltaVector(expected_dispatch1,
+ std::vector<int>{300, 300, 300, 300, 300});
+ base::TimeDelta expected_transition1 = base::Microseconds(300);
+ std::vector<base::TimeDelta> expected_compositor1(kNumOfCompositorStages,
+ base::Microseconds(-1));
+ IntToTimeDeltaVector(expected_compositor1,
+ std::vector<int>{300, -1, -1, -1, -1, 300, 300});
+ base::TimeDelta expected_total1 = base::Microseconds(2700);
+ CompositorFrameReporter::EventLatencyInfo actual_predictions1 =
+ CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages,
+ kNumOfCompositorStages);
+ pipeline_reporter_->CalculateEventLatencyPrediction(
+ actual_predictions1, kLatencyPredictionDeviationThreshold);
+
+ // Test with all previous stage predictions.
+ std::vector<base::TimeDelta> expected_dispatch2(kNumDispatchStages,
+ base::Microseconds(-1));
+ IntToTimeDeltaVector(expected_dispatch2,
+ std::vector<int>{262, 300, 412, 225, 450});
+ base::TimeDelta expected_transition2 = base::Microseconds(390);
+ std::vector<base::TimeDelta> expected_compositor2(kNumOfCompositorStages,
+ base::Microseconds(-1));
+ IntToTimeDeltaVector(expected_compositor2,
+ std::vector<int>{465, 500, 90, 720, 410, 742, 390});
+ base::TimeDelta expected_total2 = base::Microseconds(5356);
+ CompositorFrameReporter::EventLatencyInfo actual_predictions2 =
+ CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages,
+ kNumOfCompositorStages);
+ IntToTimeDeltaVector(actual_predictions2.dispatch_durations,
+ std::vector<int>{250, 300, 450, 200, 500});
+ actual_predictions2.transition_duration = base::Microseconds(420);
+ IntToTimeDeltaVector(actual_predictions2.compositor_durations,
+ std::vector<int>{520, 500, 90, 720, 410, 890, 420});
+ pipeline_reporter_->CalculateEventLatencyPrediction(
+ actual_predictions2, kLatencyPredictionDeviationThreshold);
+
+ // Test with some previous stage predictions.
+ std::vector<base::TimeDelta> expected_dispatch3(kNumDispatchStages,
+ base::Microseconds(-1));
+ IntToTimeDeltaVector(expected_dispatch3,
+ std::vector<int>{375, 450, 300, 300, 300});
+ base::TimeDelta expected_transition3 = base::Microseconds(270);
+ std::vector<base::TimeDelta> expected_compositor3(kNumOfCompositorStages,
+ base::Microseconds(-1));
+ IntToTimeDeltaVector(expected_compositor3,
+ std::vector<int>{300, 500, -1, -1, 410, 742, 390});
+ base::TimeDelta expected_total3 = base::Microseconds(4337);
+ CompositorFrameReporter::EventLatencyInfo actual_predictions3 =
+ CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages,
+ kNumOfCompositorStages);
+ IntToTimeDeltaVector(actual_predictions3.dispatch_durations,
+ std::vector<int>{400, 500, 300, -1, -1});
+ actual_predictions3.transition_duration = base::Microseconds(260);
+ IntToTimeDeltaVector(actual_predictions3.compositor_durations,
+ std::vector<int>{-1, 500, -1, -1, 410, 890, 420});
+ pipeline_reporter_->CalculateEventLatencyPrediction(
+ actual_predictions3, kLatencyPredictionDeviationThreshold);
+
+ for (int i = 0; i < kNumDispatchStages; i++) {
+ EXPECT_EQ(expected_dispatch1[i], actual_predictions1.dispatch_durations[i]);
+ EXPECT_EQ(expected_dispatch2[i], actual_predictions2.dispatch_durations[i]);
+ EXPECT_EQ(expected_dispatch3[i], actual_predictions3.dispatch_durations[i]);
+ }
+ for (int i = 0; i < kNumOfCompositorStages; i++) {
+ EXPECT_EQ(expected_compositor1[i],
+ actual_predictions1.compositor_durations[i]);
+ EXPECT_EQ(expected_compositor2[i],
+ actual_predictions2.compositor_durations[i]);
+ EXPECT_EQ(expected_compositor3[i],
+ actual_predictions3.compositor_durations[i]);
+ }
+ EXPECT_EQ(expected_transition1, actual_predictions1.transition_duration);
+ EXPECT_EQ(expected_total1, actual_predictions1.total_duration);
+ EXPECT_EQ(expected_transition2, actual_predictions2.transition_duration);
+ EXPECT_EQ(expected_total2, actual_predictions2.total_duration);
+ EXPECT_EQ(expected_transition3, actual_predictions3.transition_duration);
+ EXPECT_EQ(expected_total3, actual_predictions3.total_duration);
+
+ pipeline_reporter_ = nullptr;
+}
+
+// Tests that when a frame is presented to the user, event latency predictions
+// are reported properly for filtered EventTypes.
+TEST_F(CompositorFrameReporterTest, EventLatencyMultipleEventTypePredictions) {
+ std::vector<int> dispatch_times = {300, 300, 300, 300, 300};
+ // The prediction should only be updated with the ScrollUpdateType event,
+ // other EventType metrics should be ignored.
+ std::unique_ptr<EventMetrics> event_metrics_ptrs[] = {
+ CreateEventMetrics(ui::ET_TOUCH_PRESSED),
+ CreateEventMetrics(ui::ET_TOUCH_MOVED),
+ CreateScrollUpdateEventMetricsWithDispatchTimes(
+ false, ScrollUpdateEventMetrics::ScrollUpdateType::kContinued,
+ dispatch_times),
+ CreateEventMetrics(ui::ET_TOUCH_MOVED)};
+ // The last ET_TOUCH_MOVED event above adds 12 us to transition time.
+ const base::TimeDelta kTouchEventTransition = base::Microseconds(12);
+ EXPECT_THAT(event_metrics_ptrs, Each(NotNull()));
+ EventMetrics::List events_metrics = {
+ std::make_move_iterator(std::begin(event_metrics_ptrs)),
+ std::make_move_iterator(std::end(event_metrics_ptrs))};
+
+ AdvanceNowByUs(300);
+ // Total transition time is 312 us because of the extra 3 us from the
+ // ET_TOUCH_MOVED event.
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame,
+ Now());
+
+ // For this test there are only 3 compositor substages updated which reflects
+ // a more realistic scenario.
+
+ AdvanceNowByUs(300); // kBeginImplFrameToSendBeginMainFrame duration
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame,
+ Now());
+
+ AdvanceNowByUs(300); // kEndActivateToSubmitCompositorFrame duration
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::
+ kSubmitCompositorFrameToPresentationCompositorFrame,
+ Now());
+
+ // kSubmitCompositorFrameToPresentationCompositorFrame duration
+ AdvanceNowByUs(300);
+ pipeline_reporter_->TerminateFrame(
+ CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame, Now());
+
+ pipeline_reporter_->AddEventsMetrics(std::move(events_metrics));
+
+ // Test with no previous stage predictions.
+ std::vector<base::TimeDelta> expected_dispatch1(kNumDispatchStages,
+ base::Microseconds(-1));
+ IntToTimeDeltaVector(expected_dispatch1,
+ std::vector<int>{300, 300, 300, 300, 300});
+ base::TimeDelta expected_transition1 =
+ base::Microseconds(300) + kTouchEventTransition;
+ std::vector<base::TimeDelta> expected_compositor1(kNumOfCompositorStages,
+ base::Microseconds(-1));
+ IntToTimeDeltaVector(expected_compositor1,
+ std::vector<int>{300, -1, -1, -1, -1, 300, 300});
+ base::TimeDelta expected_total1 =
+ base::Microseconds(2700) + kTouchEventTransition;
+ CompositorFrameReporter::EventLatencyInfo actual_predictions1 =
+ CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages,
+ kNumOfCompositorStages);
+ pipeline_reporter_->CalculateEventLatencyPrediction(
+ actual_predictions1, kLatencyPredictionDeviationThreshold);
+
+ // Test with all previous stage predictions.
+ std::vector<base::TimeDelta> expected_dispatch2(kNumDispatchStages,
+ base::Microseconds(-1));
+ IntToTimeDeltaVector(expected_dispatch2,
+ std::vector<int>{262, 300, 412, 225, 450});
+ base::TimeDelta expected_transition2 = base::Microseconds(393);
+ std::vector<base::TimeDelta> expected_compositor2(kNumOfCompositorStages,
+ base::Microseconds(-1));
+ IntToTimeDeltaVector(expected_compositor2,
+ std::vector<int>{465, 500, 90, 720, 410, 742, 390});
+ base::TimeDelta expected_total2 = base::Microseconds(5359);
+ CompositorFrameReporter::EventLatencyInfo actual_predictions2 =
+ CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages,
+ kNumOfCompositorStages);
+ IntToTimeDeltaVector(actual_predictions2.dispatch_durations,
+ std::vector<int>{250, 300, 450, 200, 500});
+ actual_predictions2.transition_duration = base::Microseconds(420);
+ IntToTimeDeltaVector(actual_predictions2.compositor_durations,
+ std::vector<int>{520, 500, 90, 720, 410, 890, 420});
+ pipeline_reporter_->CalculateEventLatencyPrediction(
+ actual_predictions2, kLatencyPredictionDeviationThreshold);
+
+ for (int i = 0; i < kNumDispatchStages; i++) {
+ EXPECT_EQ(expected_dispatch1[i], actual_predictions1.dispatch_durations[i]);
+ EXPECT_EQ(expected_dispatch2[i], actual_predictions2.dispatch_durations[i]);
+ }
+ for (int i = 0; i < kNumOfCompositorStages; i++) {
+ EXPECT_EQ(expected_compositor1[i],
+ actual_predictions1.compositor_durations[i]);
+ EXPECT_EQ(expected_compositor2[i],
+ actual_predictions2.compositor_durations[i]);
+ }
+ EXPECT_EQ(expected_transition1, actual_predictions1.transition_duration);
+ EXPECT_EQ(expected_total1, actual_predictions1.total_duration);
+ EXPECT_EQ(expected_transition2, actual_predictions2.transition_duration);
+ EXPECT_EQ(expected_total2, actual_predictions2.total_duration);
+
+ pipeline_reporter_ = nullptr;
+}
+
+// Tests that when a frame is presented to the user, high latency attribution
+// for EventLatency is reported properly for filtered EventTypes.
+TEST_F(CompositorFrameReporterTest, EventLatencyAttributionPredictions) {
+ std::vector<int> dispatch_times = {300, 300, 300, 50000, 300};
+ // The prediction should only be updated with the ScrollUpdateType event,
+ // other EventType metrics should be ignored.
+ std::unique_ptr<EventMetrics> event_metrics_ptrs[] = {
+ CreateScrollUpdateEventMetricsWithDispatchTimes(
+ false, ScrollUpdateEventMetrics::ScrollUpdateType::kContinued,
+ dispatch_times)};
+ EXPECT_THAT(event_metrics_ptrs, Each(NotNull()));
+ EventMetrics::List events_metrics = {
+ std::make_move_iterator(std::begin(event_metrics_ptrs)),
+ std::make_move_iterator(std::end(event_metrics_ptrs))};
+
+ AdvanceNowByUs(300);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame,
+ Now());
+
+ // For this test there are only 3 compositor substages updated which reflects
+ // a more realistic scenario.
+
+ AdvanceNowByUs(300); // kBeginImplFrameToSendBeginMainFrame duration
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame,
+ Now());
+
+ AdvanceNowByUs(50000); // kEndActivateToSubmitCompositorFrame duration
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::
+ kSubmitCompositorFrameToPresentationCompositorFrame,
+ Now());
+
+ // kSubmitCompositorFrameToPresentationCompositorFrame duration
+ AdvanceNowByUs(300);
+ pipeline_reporter_->TerminateFrame(
+ CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame, Now());
+
+ pipeline_reporter_->AddEventsMetrics(std::move(events_metrics));
+
+ // Test with no high latency attribution.
+ CompositorFrameReporter::EventLatencyInfo expected_predictions1 =
+ CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages,
+ kNumOfCompositorStages);
+ IntToTimeDeltaVector(expected_predictions1.dispatch_durations,
+ std::vector<int>{300, 300, 300, 50000, 300});
+ expected_predictions1.transition_duration = base::Microseconds(300);
+ IntToTimeDeltaVector(expected_predictions1.compositor_durations,
+ std::vector<int>{300, -1, -1, -1, -1, 50000, 300});
+ expected_predictions1.total_duration = base::Microseconds(102100);
+
+ CompositorFrameReporter::EventLatencyInfo actual_predictions1 =
+ CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages,
+ kNumOfCompositorStages);
+ pipeline_reporter_->CalculateEventLatencyPrediction(
+ actual_predictions1, kLatencyPredictionDeviationThreshold);
+
+ std::unique_ptr<EventMetrics>& event_metrics =
+ pipeline_reporter_->events_metrics_for_testing()[0];
+ std::vector<std::string> attribution = event_metrics->GetHighLatencyStages();
+ EXPECT_EQ(0, (int)attribution.size());
+ event_metrics->ClearHighLatencyStagesForTesting();
+
+ // Test with 1 high latency stage attributed.
+ CompositorFrameReporter::EventLatencyInfo expected_predictions2 =
+ CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages,
+ kNumOfCompositorStages);
+ IntToTimeDeltaVector(expected_predictions2.dispatch_durations,
+ std::vector<int>{300, 300, 300, 12725, 300});
+ expected_predictions2.transition_duration = base::Microseconds(300);
+ IntToTimeDeltaVector(expected_predictions2.compositor_durations,
+ std::vector<int>{300, -1, -1, -1, -1, 50000, 300});
+ expected_predictions2.total_duration = base::Microseconds(64825);
+
+ CompositorFrameReporter::EventLatencyInfo actual_predictions2 =
+ CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages,
+ kNumOfCompositorStages);
+ IntToTimeDeltaVector(actual_predictions2.dispatch_durations,
+ std::vector<int>{300, 300, 300, 300, 300});
+ actual_predictions2.transition_duration = base::Microseconds(300);
+ IntToTimeDeltaVector(actual_predictions2.compositor_durations,
+ std::vector<int>{300, -1, -1, -1, -1, 50000, 300});
+ actual_predictions2.total_duration = base::Microseconds(52400);
+ pipeline_reporter_->CalculateEventLatencyPrediction(
+ actual_predictions2, kLatencyPredictionDeviationThreshold);
+
+ attribution = event_metrics->GetHighLatencyStages();
+ EXPECT_EQ(1, (int)attribution.size());
+ EXPECT_EQ("RendererCompositorToMain", attribution[0]);
+ event_metrics->ClearHighLatencyStagesForTesting();
+
+ // Test with more than 1 high latency stage attributed.
+ CompositorFrameReporter::EventLatencyInfo expected_predictions3 =
+ CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages,
+ kNumOfCompositorStages);
+ IntToTimeDeltaVector(expected_predictions3.dispatch_durations,
+ std::vector<int>{300, 300, 300, 12725, 300});
+ expected_predictions3.transition_duration = base::Microseconds(300);
+ IntToTimeDeltaVector(expected_predictions3.compositor_durations,
+ std::vector<int>{300, -1, -1, -1, -1, 12725, 300});
+ expected_predictions3.total_duration = base::Microseconds(27550);
+
+ CompositorFrameReporter::EventLatencyInfo actual_predictions3 =
+ CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages,
+ kNumOfCompositorStages);
+ IntToTimeDeltaVector(actual_predictions3.dispatch_durations,
+ std::vector<int>{300, 300, 300, 300, 300});
+ actual_predictions3.transition_duration = base::Microseconds(300);
+ IntToTimeDeltaVector(actual_predictions3.compositor_durations,
+ std::vector<int>{300, -1, -1, -1, -1, 300, 300});
+ actual_predictions3.total_duration = base::Microseconds(2700);
+ pipeline_reporter_->CalculateEventLatencyPrediction(
+ actual_predictions3, kLatencyPredictionDeviationThreshold);
+
+ attribution = event_metrics->GetHighLatencyStages();
+ EXPECT_EQ(2, (int)attribution.size());
+ EXPECT_EQ("RendererCompositorToMain", attribution[0]);
+ EXPECT_EQ("EndActivateToSubmitCompositorFrame", attribution[1]);
+
+ // Check that all prediction values are accurate.
+ for (int i = 0; i < kNumDispatchStages; i++) {
+ EXPECT_EQ(expected_predictions1.dispatch_durations[i],
+ actual_predictions1.dispatch_durations[i]);
+ EXPECT_EQ(expected_predictions2.dispatch_durations[i],
+ actual_predictions2.dispatch_durations[i]);
+ EXPECT_EQ(expected_predictions3.dispatch_durations[i],
+ actual_predictions3.dispatch_durations[i]);
+ }
+ for (int i = 0; i < kNumOfCompositorStages; i++) {
+ EXPECT_EQ(expected_predictions1.compositor_durations[i],
+ actual_predictions1.compositor_durations[i]);
+ EXPECT_EQ(expected_predictions2.compositor_durations[i],
+ actual_predictions2.compositor_durations[i]);
+ EXPECT_EQ(expected_predictions3.compositor_durations[i],
+ actual_predictions3.compositor_durations[i]);
+ }
+ EXPECT_EQ(expected_predictions1.transition_duration,
+ actual_predictions1.transition_duration);
+ EXPECT_EQ(expected_predictions1.total_duration,
+ actual_predictions1.total_duration);
+ EXPECT_EQ(expected_predictions2.transition_duration,
+ actual_predictions2.transition_duration);
+ EXPECT_EQ(expected_predictions2.total_duration,
+ actual_predictions2.total_duration);
+ EXPECT_EQ(expected_predictions3.transition_duration,
+ actual_predictions3.transition_duration);
+ EXPECT_EQ(expected_predictions3.total_duration,
+ actual_predictions3.total_duration);
+
+ pipeline_reporter_ = nullptr;
+}
+
+// Tests that when a frame is presented to the user, high latency attribution
+// for EventLatency is reported properly for filtered EventTypes.
+TEST_F(CompositorFrameReporterTest, EventLatencyAttributionChangePredictions) {
+ std::vector<int> dispatch_times = {40000, -1, -1, 300, 50000};
+ // The prediction should only be updated with the ScrollUpdateType event,
+ // other EventType metrics should be ignored.
+ std::unique_ptr<EventMetrics> event_metrics_ptrs[] = {
+ CreateScrollUpdateEventMetricsWithDispatchTimes(
+ false, ScrollUpdateEventMetrics::ScrollUpdateType::kContinued,
+ dispatch_times)};
+ EXPECT_THAT(event_metrics_ptrs, Each(NotNull()));
+ EventMetrics::List events_metrics = {
+ std::make_move_iterator(std::begin(event_metrics_ptrs)),
+ std::make_move_iterator(std::end(event_metrics_ptrs))};
+
+ AdvanceNowByUs(300);
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame,
+ Now());
+
+ // For this test there are only 3 compositor substages updated which reflects
+ // a more realistic scenario.
+
+ AdvanceNowByUs(300); // kBeginImplFrameToSendBeginMainFrame duration
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame,
+ Now());
+
+ AdvanceNowByUs(50000); // kEndActivateToSubmitCompositorFrame duration
+ pipeline_reporter_->StartStage(
+ CompositorFrameReporter::StageType::
+ kSubmitCompositorFrameToPresentationCompositorFrame,
+ Now());
+
+ // kSubmitCompositorFrameToPresentationCompositorFrame duration
+ AdvanceNowByUs(300);
+ pipeline_reporter_->TerminateFrame(
+ CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame, Now());
+
+ pipeline_reporter_->AddEventsMetrics(std::move(events_metrics));
+
+ // Test 1
+ CompositorFrameReporter::EventLatencyInfo expected_predictions1 =
+ CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages,
+ kNumOfCompositorStages);
+ IntToTimeDeltaVector(expected_predictions1.dispatch_durations,
+ std::vector<int>{10300, -1, -1, 300, 42500});
+ expected_predictions1.transition_duration = base::Microseconds(300);
+ IntToTimeDeltaVector(expected_predictions1.compositor_durations,
+ std::vector<int>{300, -1, -1, -1, -1, 15200, 300});
+ expected_predictions1.total_duration = base::Microseconds(69200);
+
+ CompositorFrameReporter::EventLatencyInfo actual_predictions1 =
+ CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages,
+ kNumOfCompositorStages);
+ IntToTimeDeltaVector(actual_predictions1.dispatch_durations,
+ std::vector<int>{400, -1, -1, 300, 40000});
+ actual_predictions1.transition_duration = base::Microseconds(300);
+ IntToTimeDeltaVector(actual_predictions1.compositor_durations,
+ std::vector<int>{300, -1, -1, -1, -1, 3600, 300});
+ actual_predictions1.total_duration = base::Microseconds(45200);
+ pipeline_reporter_->CalculateEventLatencyPrediction(
+ actual_predictions1, kLatencyPredictionDeviationThreshold);
+
+ std::unique_ptr<EventMetrics>& event_metrics =
+ pipeline_reporter_->events_metrics_for_testing()[0];
+ std::vector<std::string> attribution = event_metrics->GetHighLatencyStages();
+ EXPECT_EQ(2, (int)attribution.size());
+ EXPECT_EQ("GenerationToRendererCompositor", attribution[0]);
+ EXPECT_EQ("EndActivateToSubmitCompositorFrame", attribution[1]);
+ event_metrics->ClearHighLatencyStagesForTesting();
+
+ // Test 2
+ CompositorFrameReporter::EventLatencyInfo expected_predictions2 =
+ CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages,
+ kNumOfCompositorStages);
+ IntToTimeDeltaVector(expected_predictions2.dispatch_durations,
+ std::vector<int>{10225, -1, -1, 300, 12725});
+ expected_predictions2.transition_duration = base::Microseconds(300);
+
+ IntToTimeDeltaVector(expected_predictions2.compositor_durations,
+ std::vector<int>{300, -1, -1, -1, -1, 12725, 300});
+ expected_predictions2.total_duration = base::Microseconds(36875);
+
+ CompositorFrameReporter::EventLatencyInfo actual_predictions2 =
+ CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages,
+ kNumOfCompositorStages);
+ IntToTimeDeltaVector(actual_predictions2.dispatch_durations,
+ std::vector<int>{300, -1, -1, 300, 300});
+ actual_predictions2.transition_duration = base::Microseconds(300);
+ IntToTimeDeltaVector(actual_predictions2.compositor_durations,
+ std::vector<int>{300, -1, -1, -1, -1, 300, 300});
+ actual_predictions2.total_duration = base::Microseconds(2100);
+ pipeline_reporter_->CalculateEventLatencyPrediction(
+ actual_predictions2, kLatencyPredictionDeviationThreshold);
+
+ attribution = event_metrics->GetHighLatencyStages();
+ EXPECT_EQ(2, (int)attribution.size());
+ EXPECT_EQ("RendererMainProcessing", attribution[0]);
+ EXPECT_EQ("EndActivateToSubmitCompositorFrame", attribution[1]);
+
+ // Check that all prediction values are accurate.
+ for (int i = 0; i < kNumDispatchStages; i++) {
+ EXPECT_EQ(expected_predictions1.dispatch_durations[i],
+ actual_predictions1.dispatch_durations[i]);
+ EXPECT_EQ(expected_predictions2.dispatch_durations[i],
+ actual_predictions2.dispatch_durations[i]);
+ }
+ for (int i = 0; i < kNumOfCompositorStages; i++) {
+ EXPECT_EQ(expected_predictions1.compositor_durations[i],
+ actual_predictions1.compositor_durations[i]);
+ EXPECT_EQ(expected_predictions2.compositor_durations[i],
+ actual_predictions2.compositor_durations[i]);
+ }
+ EXPECT_EQ(expected_predictions1.transition_duration,
+ actual_predictions1.transition_duration);
+ EXPECT_EQ(expected_predictions1.total_duration,
+ actual_predictions1.total_duration);
+ EXPECT_EQ(expected_predictions2.transition_duration,
+ actual_predictions2.transition_duration);
+ EXPECT_EQ(expected_predictions2.total_duration,
+ actual_predictions2.total_duration);
+
+ pipeline_reporter_ = nullptr;
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/metrics/compositor_frame_reporting_controller.cc b/chromium/cc/metrics/compositor_frame_reporting_controller.cc
index c40ffcee3b5..b05992c7363 100644
--- a/chromium/cc/metrics/compositor_frame_reporting_controller.cc
+++ b/chromium/cc/metrics/compositor_frame_reporting_controller.cc
@@ -23,6 +23,12 @@ using StageType = CompositorFrameReporter::StageType;
using FrameTerminationStatus = CompositorFrameReporter::FrameTerminationStatus;
constexpr char kTraceCategory[] = "cc,benchmark";
+constexpr int kNumOfCompositorStages =
+ static_cast<int>(StageType::kStageTypeCount) - 1;
+constexpr int kNumDispatchStages =
+ static_cast<int>(EventMetrics::DispatchStage::kMaxValue);
+constexpr base::TimeDelta kDefaultLatencyPredictionDeviationThreshold =
+ viz::BeginFrameArgs::DefaultInterval() / 2;
} // namespace
CompositorFrameReportingController::CompositorFrameReportingController(
@@ -31,7 +37,12 @@ CompositorFrameReportingController::CompositorFrameReportingController(
int layer_tree_host_id)
: should_report_histograms_(should_report_histograms),
layer_tree_host_id_(layer_tree_host_id),
- latency_ukm_reporter_(std::make_unique<LatencyUkmReporter>()) {
+ latency_ukm_reporter_(std::make_unique<LatencyUkmReporter>()),
+ previous_latency_predictions_main_(base::Microseconds(-1)),
+ previous_latency_predictions_impl_(base::Microseconds(-1)),
+ event_latency_predictions_(
+ CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages,
+ kNumOfCompositorStages)) {
if (should_report_ukm) {
// UKM metrics should be reported if and only if `latency_ukm_reporter` is
// set on `global_trackers_`.
@@ -316,6 +327,7 @@ void CompositorFrameReportingController::DidSubmitCompositorFrame(
main_reporter->AddEventsMetrics(
std::move(events_metrics.main_event_metrics));
main_reporter->set_has_missing_content(has_missing_content);
+ main_reporter->set_reporter_type_to_main();
submitted_compositor_frames_.emplace_back(frame_token,
std::move(main_reporter));
}
@@ -330,6 +342,7 @@ void CompositorFrameReportingController::DidSubmitCompositorFrame(
impl_reporter->set_has_missing_content(has_missing_content);
impl_reporter->set_is_accompanied_by_main_thread_update(
is_activated_frame_new);
+ impl_reporter->set_reporter_type_to_impl();
submitted_compositor_frames_.emplace_back(frame_token,
std::move(impl_reporter));
}
@@ -471,6 +484,23 @@ void CompositorFrameReportingController::DidPresentCompositorFrame(
reporter->TerminateFrame(termination_status,
details.presentation_feedback.timestamp);
+ base::TimeDelta latency_prediction_deviation_threshold =
+ details.presentation_feedback.interval.is_zero()
+ ? kDefaultLatencyPredictionDeviationThreshold
+ : (details.presentation_feedback.interval) / 2;
+ switch (reporter->get_reporter_type()) {
+ case CompositorFrameReporter::ReporterType::kImpl:
+ reporter->CalculateCompositorLatencyPrediction(
+ previous_latency_predictions_impl_,
+ latency_prediction_deviation_threshold);
+ break;
+ case CompositorFrameReporter::ReporterType::kMain:
+ reporter->CalculateCompositorLatencyPrediction(
+ previous_latency_predictions_main_,
+ latency_prediction_deviation_threshold);
+ break;
+ }
+
if (termination_status == FrameTerminationStatus::kPresentedFrame) {
// If there are outstanding metrics from dropped frames older than this
// frame, this frame would be the first frame presented after those
@@ -487,6 +517,11 @@ void CompositorFrameReportingController::DidPresentCompositorFrame(
reporter->AddEventsMetrics(std::move(it->second));
}
+ // TODO(crbug.com/1334827): Consider using a separate container to
+ // differentiate event predictions with and without a main dispatch stage.
+ reporter->CalculateEventLatencyPrediction(
+ event_latency_predictions_, latency_prediction_deviation_threshold);
+
// For presented frames, if `reporter` was cloned from another reporter,
// and the original reporter is still alive, then check whether the cloned
// reporter has a 'partial update decider'. It is still possible for the
@@ -743,6 +778,7 @@ void CompositorFrameReportingController::CreateReportersForDroppedFrames(
timestamp);
reporter->TerminateFrame(FrameTerminationStatus::kDidNotPresentFrame,
args.deadline);
+ reporter->set_is_backfill(true);
}
}
diff --git a/chromium/cc/metrics/compositor_frame_reporting_controller.h b/chromium/cc/metrics/compositor_frame_reporting_controller.h
index 3d1640c395c..321e4922095 100644
--- a/chromium/cc/metrics/compositor_frame_reporting_controller.h
+++ b/chromium/cc/metrics/compositor_frame_reporting_controller.h
@@ -236,6 +236,15 @@ class CC_EXPORT CompositorFrameReportingController {
// interval of last begin frame args.
base::TimeDelta last_interval_;
+
+ CompositorFrameReporter::CompositorLatencyInfo
+ previous_latency_predictions_main_;
+ CompositorFrameReporter::CompositorLatencyInfo
+ previous_latency_predictions_impl_;
+
+ // Container that stores the EventLatency stage latency predictions based on
+ // previous event traces.
+ CompositorFrameReporter::EventLatencyInfo event_latency_predictions_;
};
} // namespace cc
diff --git a/chromium/cc/metrics/compositor_timing_history.cc b/chromium/cc/metrics/compositor_timing_history.cc
index a9c16c24319..b949c6937da 100644
--- a/chromium/cc/metrics/compositor_timing_history.cc
+++ b/chromium/cc/metrics/compositor_timing_history.cc
@@ -30,11 +30,6 @@ class CompositorTimingHistory::UMAReporter {
// Latency measurements
virtual void AddBeginImplFrameLatency(base::TimeDelta delta) = 0;
- virtual void AddCommitToReadyToActivateDuration(base::TimeDelta duration,
- TreePriority priority) = 0;
- virtual void AddInvalidationToReadyToActivateDuration(
- base::TimeDelta duration,
- TreePriority priority) = 0;
virtual void AddDrawDuration(base::TimeDelta duration) = 0;
// crbug.com/758439: the following functions are used to report timing in
@@ -346,21 +341,6 @@ class RendererUMAReporter : public CompositorTimingHistory::UMAReporter {
"Scheduling.Renderer.BeginImplFrameLatency", delta);
}
- void AddCommitToReadyToActivateDuration(base::TimeDelta duration,
- TreePriority priority) override {
- UMA_HISTOGRAM_READY_TO_ACTIVATE(
- "Scheduling.Renderer.CommitToReadyToActivateDuration", duration,
- priority);
- }
-
- void AddInvalidationToReadyToActivateDuration(
- base::TimeDelta duration,
- TreePriority priority) override {
- UMA_HISTOGRAM_READY_TO_ACTIVATE(
- "Scheduling.Renderer.InvalidationToReadyToActivateDuration", duration,
- priority);
- }
-
void AddDrawDuration(base::TimeDelta duration) override {
UMA_HISTOGRAM_CUSTOM_TIMES_DURATION("Scheduling.Renderer.DrawDuration",
duration);
@@ -389,21 +369,6 @@ class BrowserUMAReporter : public CompositorTimingHistory::UMAReporter {
"Scheduling.Browser.BeginImplFrameLatency", delta);
}
- void AddCommitToReadyToActivateDuration(base::TimeDelta duration,
- TreePriority priority) override {
- UMA_HISTOGRAM_READY_TO_ACTIVATE(
- "Scheduling.Browser.CommitToReadyToActivateDuration", duration,
- priority);
- }
-
- void AddInvalidationToReadyToActivateDuration(
- base::TimeDelta duration,
- TreePriority priority) override {
- UMA_HISTOGRAM_READY_TO_ACTIVATE(
- "Scheduling.Browser.InvalidationToReadyToActivateDuration", duration,
- priority);
- }
-
void AddDrawDuration(base::TimeDelta duration) override {
UMA_HISTOGRAM_CUSTOM_TIMES_DURATION("Scheduling.Browser.DrawDuration",
duration);
@@ -423,11 +388,6 @@ class NullUMAReporter : public CompositorTimingHistory::UMAReporter {
void AddDrawIntervalWithCustomPropertyAnimations(
base::TimeDelta inverval) override {}
void AddBeginImplFrameLatency(base::TimeDelta delta) override {}
- void AddCommitToReadyToActivateDuration(base::TimeDelta duration,
- TreePriority priority) override {}
- void AddInvalidationToReadyToActivateDuration(
- base::TimeDelta duration,
- TreePriority priority) override {}
void AddDrawDuration(base::TimeDelta duration) override {}
void AddImplFrameDeadlineType(
CompositorTimingHistory::DeadlineMode deadline_mode) override {}
@@ -740,12 +700,7 @@ void CompositorTimingHistory::ReadyToActivate() {
DCHECK_EQ(pending_tree_ready_to_activate_time_, base::TimeTicks());
pending_tree_ready_to_activate_time_ = Now();
- if (pending_tree_is_impl_side_) {
- base::TimeDelta time_since_invalidation =
- pending_tree_ready_to_activate_time_ - pending_tree_creation_time_;
- uma_reporter_->AddInvalidationToReadyToActivateDuration(
- time_since_invalidation, tree_priority_);
- } else {
+ if (!pending_tree_is_impl_side_) {
base::TimeDelta time_since_commit =
pending_tree_ready_to_activate_time_ - pending_tree_creation_time_;
@@ -755,8 +710,6 @@ void CompositorTimingHistory::ReadyToActivate() {
base::TimeDelta commit_to_ready_to_activate_estimate =
CommitToReadyToActivateDurationEstimate();
- uma_reporter_->AddCommitToReadyToActivateDuration(time_since_commit,
- tree_priority_);
rendering_stats_instrumentation_->AddCommitToActivateDuration(
time_since_commit, commit_to_ready_to_activate_estimate);
diff --git a/chromium/cc/metrics/dropped_frame_counter.cc b/chromium/cc/metrics/dropped_frame_counter.cc
index 3ad8364c7a0..980fe517478 100644
--- a/chromium/cc/metrics/dropped_frame_counter.cc
+++ b/chromium/cc/metrics/dropped_frame_counter.cc
@@ -391,7 +391,6 @@ void DroppedFrameCounter::ReportFrames() {
if (sliding_window_max_percent_dropped_After_5_sec_.has_value())
smoothness_data.worst_smoothness_after5sec =
sliding_window_max_percent_dropped_After_5_sec_.value();
- smoothness_data.time_max_delta = time_max_delta_;
ukm_smoothness_data_->Write(smoothness_data);
}
}
@@ -447,7 +446,6 @@ void DroppedFrameCounter::Reset() {
sliding_window_histogram_[SmoothnessStrategy::kCompositorFocusedStrategy]
.Clear();
ring_buffer_.Clear();
- time_max_delta_ = {};
last_reported_metrics_ = {};
}
@@ -569,10 +567,9 @@ void DroppedFrameCounter::PopSlidingWindow() {
sliding_window_histogram_[SmoothnessStrategy::kScrollFocusedStrategy]
.AddPercentDroppedFrame(percent_dropped_frame_scroll, count);
- if (percent_dropped_frame > sliding_window_max_percent_dropped_) {
- time_max_delta_ = newest_args.frame_time - time_fcp_received_;
+ if (percent_dropped_frame > sliding_window_max_percent_dropped_)
sliding_window_max_percent_dropped_ = percent_dropped_frame;
- }
+
sliding_window_current_percent_dropped_ = percent_dropped_frame;
latest_sliding_window_start_ = last_timestamp;
diff --git a/chromium/cc/metrics/dropped_frame_counter.h b/chromium/cc/metrics/dropped_frame_counter.h
index 430f5100b80..52251305302 100644
--- a/chromium/cc/metrics/dropped_frame_counter.h
+++ b/chromium/cc/metrics/dropped_frame_counter.h
@@ -161,6 +161,10 @@ class CC_EXPORT DroppedFrameCounter {
return &sliding_window_histogram_[strategy];
}
+ double sliding_window_current_percent_dropped() const {
+ return sliding_window_current_percent_dropped_;
+ }
+
private:
void NotifyFrameResult(const viz::BeginFrameArgs& args,
const FrameInfo& frame_info);
@@ -194,7 +198,6 @@ class CC_EXPORT DroppedFrameCounter {
absl::optional<double> sliding_window_max_percent_dropped_After_2_sec_;
absl::optional<double> sliding_window_max_percent_dropped_After_5_sec_;
base::TimeTicks time_fcp_received_;
- base::TimeDelta time_max_delta_;
raw_ptr<UkmSmoothnessDataShared> ukm_smoothness_data_ = nullptr;
FrameSorter frame_sorter_;
raw_ptr<TotalFrameCounter> total_counter_ = nullptr;
diff --git a/chromium/cc/metrics/event_latency_tracing_recorder.cc b/chromium/cc/metrics/event_latency_tracing_recorder.cc
index 57dce582e1f..138dac53796 100644
--- a/chromium/cc/metrics/event_latency_tracing_recorder.cc
+++ b/chromium/cc/metrics/event_latency_tracing_recorder.cc
@@ -16,10 +16,47 @@ namespace cc {
namespace {
constexpr char kTracingCategory[] = "cc,benchmark,input";
+constexpr base::TimeDelta high_latency_threshold = base::Milliseconds(90);
-// Returns the name of the event dispatch breakdown of EventLatency trace events
-// between `start_stage` and `end_stage`.
-constexpr const char* GetDispatchBreakdownName(
+constexpr perfetto::protos::pbzero::EventLatency::EventType ToProtoEnum(
+ EventMetrics::EventType event_type) {
+#define CASE(event_type, proto_event_type) \
+ case EventMetrics::EventType::event_type: \
+ return perfetto::protos::pbzero::EventLatency::proto_event_type
+ switch (event_type) {
+ CASE(kMousePressed, MOUSE_PRESSED);
+ CASE(kMouseReleased, MOUSE_RELEASED);
+ CASE(kMouseWheel, MOUSE_WHEEL);
+ CASE(kKeyPressed, KEY_PRESSED);
+ CASE(kKeyReleased, KEY_RELEASED);
+ CASE(kTouchPressed, TOUCH_PRESSED);
+ CASE(kTouchReleased, TOUCH_RELEASED);
+ CASE(kTouchMoved, TOUCH_MOVED);
+ CASE(kGestureScrollBegin, GESTURE_SCROLL_BEGIN);
+ CASE(kGestureScrollUpdate, GESTURE_SCROLL_UPDATE);
+ CASE(kGestureScrollEnd, GESTURE_SCROLL_END);
+ CASE(kGestureDoubleTap, GESTURE_DOUBLE_TAP);
+ CASE(kGestureLongPress, GESTURE_LONG_PRESS);
+ CASE(kGestureLongTap, GESTURE_LONG_TAP);
+ CASE(kGestureShowPress, GESTURE_SHOW_PRESS);
+ CASE(kGestureTap, GESTURE_TAP);
+ CASE(kGestureTapCancel, GESTURE_TAP_CANCEL);
+ CASE(kGestureTapDown, GESTURE_TAP_DOWN);
+ CASE(kGestureTapUnconfirmed, GESTURE_TAP_UNCONFIRMED);
+ CASE(kGestureTwoFingerTap, GESTURE_TWO_FINGER_TAP);
+ CASE(kFirstGestureScrollUpdate, FIRST_GESTURE_SCROLL_UPDATE);
+ CASE(kMouseDragged, MOUSE_DRAGGED);
+ CASE(kGesturePinchBegin, GESTURE_PINCH_BEGIN);
+ CASE(kGesturePinchEnd, GESTURE_PINCH_END);
+ CASE(kGesturePinchUpdate, GESTURE_PINCH_UPDATE);
+ CASE(kInertialGestureScrollUpdate, INERTIAL_GESTURE_SCROLL_UPDATE);
+ }
+}
+
+} // namespace
+
+// static
+const char* EventLatencyTracingRecorder::GetDispatchBreakdownName(
EventMetrics::DispatchStage start_stage,
EventMetrics::DispatchStage end_stage) {
switch (start_stage) {
@@ -53,9 +90,8 @@ constexpr const char* GetDispatchBreakdownName(
}
}
-// Returns the name of EventLatency breakdown between `dispatch_stage` and
-// `compositor_stage`.
-constexpr const char* GetDispatchToCompositorBreakdownName(
+// static
+const char* EventLatencyTracingRecorder::GetDispatchToCompositorBreakdownName(
EventMetrics::DispatchStage dispatch_stage,
CompositorFrameReporter::StageType compositor_stage) {
switch (dispatch_stage) {
@@ -111,9 +147,8 @@ constexpr const char* GetDispatchToCompositorBreakdownName(
}
}
-// Returns the name of EventLatency breakdown between `dispatch_stage` and
-// termination for events not associated with a frame update.
-constexpr const char* GetDispatchToTerminationBreakdownName(
+// static
+const char* EventLatencyTracingRecorder::GetDispatchToTerminationBreakdownName(
EventMetrics::DispatchStage dispatch_stage) {
switch (dispatch_stage) {
case EventMetrics::DispatchStage::kArrivedInRendererCompositor:
@@ -132,43 +167,6 @@ constexpr const char* GetDispatchToTerminationBreakdownName(
}
}
-constexpr perfetto::protos::pbzero::EventLatency::EventType ToProtoEnum(
- EventMetrics::EventType event_type) {
-#define CASE(event_type, proto_event_type) \
- case EventMetrics::EventType::event_type: \
- return perfetto::protos::pbzero::EventLatency::proto_event_type
- switch (event_type) {
- CASE(kMousePressed, MOUSE_PRESSED);
- CASE(kMouseReleased, MOUSE_RELEASED);
- CASE(kMouseWheel, MOUSE_WHEEL);
- CASE(kKeyPressed, KEY_PRESSED);
- CASE(kKeyReleased, KEY_RELEASED);
- CASE(kTouchPressed, TOUCH_PRESSED);
- CASE(kTouchReleased, TOUCH_RELEASED);
- CASE(kTouchMoved, TOUCH_MOVED);
- CASE(kGestureScrollBegin, GESTURE_SCROLL_BEGIN);
- CASE(kGestureScrollUpdate, GESTURE_SCROLL_UPDATE);
- CASE(kGestureScrollEnd, GESTURE_SCROLL_END);
- CASE(kGestureDoubleTap, GESTURE_DOUBLE_TAP);
- CASE(kGestureLongPress, GESTURE_LONG_PRESS);
- CASE(kGestureLongTap, GESTURE_LONG_TAP);
- CASE(kGestureShowPress, GESTURE_SHOW_PRESS);
- CASE(kGestureTap, GESTURE_TAP);
- CASE(kGestureTapCancel, GESTURE_TAP_CANCEL);
- CASE(kGestureTapDown, GESTURE_TAP_DOWN);
- CASE(kGestureTapUnconfirmed, GESTURE_TAP_UNCONFIRMED);
- CASE(kGestureTwoFingerTap, GESTURE_TWO_FINGER_TAP);
- CASE(kFirstGestureScrollUpdate, FIRST_GESTURE_SCROLL_UPDATE);
- CASE(kMouseDragged, MOUSE_DRAGGED);
- CASE(kGesturePinchBegin, GESTURE_PINCH_BEGIN);
- CASE(kGesturePinchEnd, GESTURE_PINCH_END);
- CASE(kGesturePinchUpdate, GESTURE_PINCH_UPDATE);
- CASE(kInertialGestureScrollUpdate, INERTIAL_GESTURE_SCROLL_UPDATE);
- }
-}
-
-} // namespace
-
// static
void EventLatencyTracingRecorder::RecordEventLatencyTraceEvent(
EventMetrics* event_metrics,
@@ -191,6 +189,15 @@ void EventLatencyTracingRecorder::RecordEventLatencyTraceEvent(
context.event<perfetto::protos::pbzero::ChromeTrackEvent>();
auto* event_latency = event->set_event_latency();
event_latency->set_event_type(ToProtoEnum(event_metrics->type()));
+ bool has_high_latency =
+ (termination_time - generated_timestamp) > high_latency_threshold;
+ event_latency->set_has_high_latency(has_high_latency);
+ for (auto stage : event_metrics->GetHighLatencyStages()) {
+ // TODO(crbug.com/1334827): Consider changing the high_latency_stage
+ // type from a string to enum type in chrome_track_event.proto,
+ // similar to event_type.
+ event_latency->add_high_latency_stage(stage);
+ }
});
// Event dispatch stages.
diff --git a/chromium/cc/metrics/event_latency_tracing_recorder.h b/chromium/cc/metrics/event_latency_tracing_recorder.h
index 67202ca3d4e..755037195df 100644
--- a/chromium/cc/metrics/event_latency_tracing_recorder.h
+++ b/chromium/cc/metrics/event_latency_tracing_recorder.h
@@ -15,6 +15,23 @@ class EventMetrics;
class EventLatencyTracingRecorder {
public:
+ // Returns the name of the event dispatch breakdown of EventLatency trace
+ // events between `start_stage` and `end_stage`.
+ static const char* GetDispatchBreakdownName(
+ EventMetrics::DispatchStage start_stage,
+ EventMetrics::DispatchStage end_stage);
+
+ // Returns the name of EventLatency breakdown between `dispatch_stage` and
+ // `compositor_stage`.
+ static const char* GetDispatchToCompositorBreakdownName(
+ EventMetrics::DispatchStage dispatch_stage,
+ CompositorFrameReporter::StageType compositor_stage);
+
+ // Returns the name of EventLatency breakdown between `dispatch_stage` and
+ // termination for events not associated with a frame update.
+ static const char* GetDispatchToTerminationBreakdownName(
+ EventMetrics::DispatchStage dispatch_stage);
+
static void RecordEventLatencyTraceEvent(
EventMetrics* event_metrics,
base::TimeTicks termination_time,
diff --git a/chromium/cc/metrics/event_metrics.cc b/chromium/cc/metrics/event_metrics.cc
index aff7043c15f..62306ee30a5 100644
--- a/chromium/cc/metrics/event_metrics.cc
+++ b/chromium/cc/metrics/event_metrics.cc
@@ -6,6 +6,7 @@
#include <algorithm>
#include <ostream>
+#include <string>
#include <utility>
#include "base/check.h"
@@ -272,6 +273,10 @@ const char* EventMetrics::GetTypeName() const {
return kInterestingEvents[static_cast<int>(type_)].name;
}
+void EventMetrics::SetHighLatencyStage(const std::string& stage) {
+ high_latency_stages_.push_back(stage);
+}
+
void EventMetrics::SetDispatchStageTimestamp(DispatchStage stage) {
DCHECK(dispatch_stage_timestamps_[static_cast<size_t>(stage)].is_null());
diff --git a/chromium/cc/metrics/event_metrics.h b/chromium/cc/metrics/event_metrics.h
index b8c43eab201..ce133874abf 100644
--- a/chromium/cc/metrics/event_metrics.h
+++ b/chromium/cc/metrics/event_metrics.h
@@ -6,6 +6,7 @@
#define CC_METRICS_EVENT_METRICS_H_
#include <memory>
+#include <string>
#include <vector>
#include "base/memory/raw_ptr.h"
@@ -106,6 +107,12 @@ class CC_EXPORT EventMetrics {
// Returns a string representing event type.
const char* GetTypeName() const;
+ void SetHighLatencyStage(const std::string& stage);
+ const std::vector<std::string>& GetHighLatencyStages() const {
+ return high_latency_stages_;
+ }
+ void ClearHighLatencyStagesForTesting() { high_latency_stages_.clear(); }
+
void SetDispatchStageTimestamp(DispatchStage stage);
base::TimeTicks GetDispatchStageTimestamp(DispatchStage stage) const;
@@ -167,6 +174,8 @@ class CC_EXPORT EventMetrics {
EventType type_;
+ std::vector<std::string> high_latency_stages_;
+
const raw_ptr<const base::TickClock> tick_clock_;
// Timestamps of different stages of event dispatch. Timestamps are set as the
diff --git a/chromium/cc/metrics/frame_info.cc b/chromium/cc/metrics/frame_info.cc
index 003cc67a9cb..383c7ed69e4 100644
--- a/chromium/cc/metrics/frame_info.cc
+++ b/chromium/cc/metrics/frame_info.cc
@@ -55,6 +55,10 @@ void FrameInfo::MergeWith(const FrameInfo& other) {
// the same BeginFrameArgs. This can trip the DCHECK()s in this function.
if (was_merged)
return;
+ if (main_thread_response == MainThreadResponse::kIncluded &&
+ other.main_thread_response == MainThreadResponse::kIncluded) {
+ return;
+ }
#endif
DCHECK(!was_merged);
DCHECK(!other.was_merged);
diff --git a/chromium/cc/metrics/frame_sequence_metrics.cc b/chromium/cc/metrics/frame_sequence_metrics.cc
index 5d3938153e7..ef19c68621a 100644
--- a/chromium/cc/metrics/frame_sequence_metrics.cc
+++ b/chromium/cc/metrics/frame_sequence_metrics.cc
@@ -451,6 +451,8 @@ void FrameSequenceMetrics::ReportMetrics() {
base::LinearHistogram::FactoryGet(
GetCheckerboardingHistogramName(type_), 1, 100, 101,
base::HistogramBase::kUmaTargetedHistogramFlag));
+ ThroughputData::ReportCheckerboardingHistogram(
+ this, SmoothEffectDrivingThread::kCompositor, checkerboarding_percent);
frames_checkerboarded_ = 0;
}
@@ -680,6 +682,34 @@ int FrameSequenceMetrics::ThroughputData::
return percent;
}
+void FrameSequenceMetrics::ThroughputData::ReportCheckerboardingHistogram(
+ FrameSequenceMetrics* metrics,
+ SmoothEffectDrivingThread thread_type,
+ int percent) {
+ const auto sequence_type = metrics->type();
+ DCHECK_LT(sequence_type, FrameSequenceTrackerType::kMaxType);
+
+ const bool is_animation =
+ ShouldReportForAnimation(sequence_type, thread_type);
+ const bool is_interaction = ShouldReportForInteraction(
+ metrics->type(), thread_type, metrics->GetEffectiveThread());
+
+ if (is_animation) {
+ UMA_HISTOGRAM_PERCENTAGE(
+ "Graphics.Smoothness.Checkerboarding.AllAnimations", percent);
+ }
+
+ if (is_interaction) {
+ UMA_HISTOGRAM_PERCENTAGE(
+ "Graphics.Smoothness.Checkerboarding.AllInteractions", percent);
+ }
+
+ if (is_animation || is_interaction) {
+ UMA_HISTOGRAM_PERCENTAGE("Graphics.Smoothness.Checkerboarding.AllSequences",
+ percent);
+ }
+}
+
std::unique_ptr<base::trace_event::TracedValue>
FrameSequenceMetrics::ThroughputData::ToTracedValue(
const ThroughputData& impl,
diff --git a/chromium/cc/metrics/frame_sequence_metrics.h b/chromium/cc/metrics/frame_sequence_metrics.h
index 33fa2b8ae30..31759277ec7 100644
--- a/chromium/cc/metrics/frame_sequence_metrics.h
+++ b/chromium/cc/metrics/frame_sequence_metrics.h
@@ -106,6 +106,11 @@ class CC_EXPORT FrameSequenceMetrics {
int metric_index,
const ThroughputData& data);
+ static void ReportCheckerboardingHistogram(
+ FrameSequenceMetrics* metrics,
+ FrameInfo::SmoothEffectDrivingThread thread_type,
+ int percent);
+
void Merge(const ThroughputData& data) {
frames_expected += data.frames_expected;
frames_produced += data.frames_produced;
diff --git a/chromium/cc/metrics/frame_sequence_tracker_unittest.cc b/chromium/cc/metrics/frame_sequence_tracker_unittest.cc
index e1f7b45cad7..106224668c7 100644
--- a/chromium/cc/metrics/frame_sequence_tracker_unittest.cc
+++ b/chromium/cc/metrics/frame_sequence_tracker_unittest.cc
@@ -433,6 +433,7 @@ TEST_F(FrameSequenceTrackerTest, TestJankWithZeroIntervalInFeedback) {
// followed by a non-checkerboard frame.
TEST_F(FrameSequenceTrackerTest, CheckerboardingSimple) {
CreateNewTracker();
+ base::HistogramTester histogram_tester;
const uint64_t source_1 = 1;
uint64_t sequence_1 = 0;
@@ -458,12 +459,21 @@ TEST_F(FrameSequenceTrackerTest, CheckerboardingSimple) {
collection_.NotifyFramePresented(frame_token, feedback);
EXPECT_EQ(1u, NumberOfFramesCheckerboarded());
+
+ // ImplThroughput().frames_expected is set to 100 since in ReportMetrics(),
+ // in order to report checkerboarding histogram, the minimum frames for
+ // ThroughputMetric is 100.
+ ImplThroughput().frames_expected = 100u;
+ ReportMetrics();
+ histogram_tester.ExpectTotalCount(
+ "Graphics.Smoothness.Checkerboarding.AllSequences", 1u);
}
// Present a single frame with checkerboarding, followed by a non-checkerboard
// frame after a few vsyncs.
TEST_F(FrameSequenceTrackerTest, CheckerboardingMultipleFrames) {
CreateNewTracker();
+ base::HistogramTester histogram_tester;
const uint64_t source_1 = 1;
uint64_t sequence_1 = 0;
@@ -489,12 +499,21 @@ TEST_F(FrameSequenceTrackerTest, CheckerboardingMultipleFrames) {
collection_.NotifyFramePresented(frame_token, feedback);
EXPECT_EQ(3u, NumberOfFramesCheckerboarded());
+
+ // ImplThroughput().frames_expected is set to 100 since in ReportMetrics(),
+ // in order to report checkerboarding histogram, the minimum frames for
+ // ThroughputMetric is 100.
+ ImplThroughput().frames_expected = 100u;
+ ReportMetrics();
+ histogram_tester.ExpectTotalCount(
+ "Graphics.Smoothness.Checkerboarding.AllSequences", 1u);
}
// Present multiple checkerboarded frames, followed by a non-checkerboard
// frame.
TEST_F(FrameSequenceTrackerTest, MultipleCheckerboardingFrames) {
CreateNewTracker();
+ base::HistogramTester histogram_tester;
const uint32_t kFrames = 3;
const uint64_t source_1 = 1;
@@ -527,6 +546,14 @@ TEST_F(FrameSequenceTrackerTest, MultipleCheckerboardingFrames) {
collection_.NotifyFramePresented(frame_token, feedback);
EXPECT_EQ(kFrames, NumberOfFramesCheckerboarded());
+
+ // ImplThroughput().frames_expected is set to 100 since in ReportMetrics(),
+ // in order to report checkerboarding histogram, the minimum frames for
+ // ThroughputMetric is 100.
+ ImplThroughput().frames_expected = 100u;
+ ReportMetrics();
+ histogram_tester.ExpectTotalCount(
+ "Graphics.Smoothness.Checkerboarding.AllSequences", 1u);
}
TEST_F(FrameSequenceTrackerTest, ReportMetrics) {
diff --git a/chromium/cc/metrics/ukm_smoothness_data.h b/chromium/cc/metrics/ukm_smoothness_data.h
index 8aaedcb22b1..7d43fa20421 100644
--- a/chromium/cc/metrics/ukm_smoothness_data.h
+++ b/chromium/cc/metrics/ukm_smoothness_data.h
@@ -31,7 +31,6 @@ struct CC_EXPORT UkmSmoothnessData {
double percentile_95 = 0.0;
double variance = 0.0;
double buckets[7] = {0};
- base::TimeDelta time_max_delta = base::Milliseconds(1);
double scroll_focused_median = 0.0;
double scroll_focused_percentile_95 = 0.0;
diff --git a/chromium/cc/metrics/video_playback_roughness_reporter.cc b/chromium/cc/metrics/video_playback_roughness_reporter.cc
index 07d3232d1e1..fe8f3d950e4 100644
--- a/chromium/cc/metrics/video_playback_roughness_reporter.cc
+++ b/chromium/cc/metrics/video_playback_roughness_reporter.cc
@@ -7,6 +7,7 @@
#include <algorithm>
#include "base/callback_helpers.h"
+#include "base/containers/adapters.h"
#include "base/cxx17_backports.h"
#include "base/metrics/histogram_macros.h"
#include "base/numerics/safe_conversions.h"
@@ -84,19 +85,18 @@ void VideoPlaybackRoughnessReporter::FrameSubmitted(
void VideoPlaybackRoughnessReporter::FramePresented(TokenType token,
base::TimeTicks timestamp,
bool reliable_timestamp) {
- for (auto it = frames_.rbegin(); it != frames_.rend(); it++) {
- FrameInfo& info = *it;
- if (token == it->token) {
- if (info.decode_time.has_value()) {
- auto time_since_decode = timestamp - info.decode_time.value();
+ for (auto& frame : base::Reversed(frames_)) {
+ if (token == frame.token) {
+ if (frame.decode_time.has_value()) {
+ auto time_since_decode = timestamp - frame.decode_time.value();
UMA_HISTOGRAM_TIMES("Media.VideoFrameSubmitter", time_since_decode);
}
if (reliable_timestamp)
- info.presentation_time = timestamp;
+ frame.presentation_time = timestamp;
break;
}
- if (viz::FrameTokenGT(token, it->token))
+ if (viz::FrameTokenGT(token, frame.token))
break;
}
}
diff --git a/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.cc b/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.cc
index 522c1a6f1b8..2fa65d484fb 100644
--- a/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.cc
+++ b/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.cc
@@ -117,9 +117,11 @@ void AsyncLayerTreeFrameSink::DetachFromClient() {
begin_frame_source_.reset();
synthetic_begin_frame_source_.reset();
client_receiver_.reset();
+ // `compositor_frame_sink_ptr_` points to either `compositor_frame_sink_` or
+ // `compositor_frame_sink_associated_`, so it must be set to nullptr first.
+ compositor_frame_sink_ptr_ = nullptr;
compositor_frame_sink_.reset();
compositor_frame_sink_associated_.reset();
- compositor_frame_sink_ptr_ = nullptr;
LayerTreeFrameSink::DetachFromClient();
}
diff --git a/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.h b/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.h
index 53a1e93c220..a2893a801ee 100644
--- a/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.h
+++ b/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.h
@@ -131,13 +131,14 @@ class CC_MOJO_EMBEDDER_EXPORT AsyncLayerTreeFrameSink
// Message pipes that will be bound when BindToClient() is called.
UnboundMessagePipes pipes_;
- // One of |compositor_frame_sink_| or |compositor_frame_sink_associated_| will
- // be bound after calling BindToClient(). |compositor_frame_sink_ptr_| will
- // point to message pipe we want to use.
- raw_ptr<viz::mojom::CompositorFrameSink> compositor_frame_sink_ptr_ = nullptr;
mojo::Remote<viz::mojom::CompositorFrameSink> compositor_frame_sink_;
mojo::AssociatedRemote<viz::mojom::CompositorFrameSink>
compositor_frame_sink_associated_;
+ // One of |compositor_frame_sink_| or |compositor_frame_sink_associated_| will
+ // be bound after calling BindToClient(). |compositor_frame_sink_ptr_| will
+ // point to message pipe we want to use. It must be declared last and cleared
+ // first.
+ raw_ptr<viz::mojom::CompositorFrameSink> compositor_frame_sink_ptr_ = nullptr;
mojo::Receiver<viz::mojom::CompositorFrameSinkClient> client_receiver_{this};
THREAD_CHECKER(thread_checker_);
diff --git a/chromium/cc/mojom/BUILD.gn b/chromium/cc/mojom/BUILD.gn
index fc4ab95cb54..d2a1783867f 100644
--- a/chromium/cc/mojom/BUILD.gn
+++ b/chromium/cc/mojom/BUILD.gn
@@ -32,6 +32,7 @@ mojom("mojom") {
public_deps = [
"//mojo/public/mojom/base",
"//services/viz/public/mojom",
+ "//skia/public/mojom",
"//ui/gfx/geometry/mojom",
]
diff --git a/chromium/cc/mojom/DEPS b/chromium/cc/mojom/DEPS
index 5f69639a07c..f3731eba10f 100644
--- a/chromium/cc/mojom/DEPS
+++ b/chromium/cc/mojom/DEPS
@@ -1,4 +1,5 @@
include_rules = [
"+mojo/public/cpp/base",
"+services/viz/public/cpp/compositing",
+ "+skia/public/mojom",
]
diff --git a/chromium/cc/mojom/render_frame_metadata.mojom b/chromium/cc/mojom/render_frame_metadata.mojom
index 3ee3462988e..07112e7ffe3 100644
--- a/chromium/cc/mojom/render_frame_metadata.mojom
+++ b/chromium/cc/mojom/render_frame_metadata.mojom
@@ -8,6 +8,7 @@ import "mojo/public/mojom/base/time.mojom";
import "services/viz/public/mojom/compositing/local_surface_id.mojom";
import "services/viz/public/mojom/compositing/selection.mojom";
import "services/viz/public/mojom/compositing/vertical_scroll_direction.mojom";
+import "skia/public/mojom/skcolor4f.mojom";
import "ui/gfx/geometry/mojom/geometry.mojom";
// Contains information to assist in making a decision about forwarding
@@ -27,7 +28,7 @@ struct RenderFrameMetadata {
// The background color of a CompositorFrame. It can be used for filling the
// content area if the primary surface is unavailable and fallback is not
// specified.
- uint32 root_background_color;
+ skia.mojom.SkColor4f root_background_color;
// Scroll offset of the root layer. This optional parameter is only sent
// during tests.
diff --git a/chromium/cc/mojom/render_frame_metadata_mojom_traits.cc b/chromium/cc/mojom/render_frame_metadata_mojom_traits.cc
index 3e4cdf17c6b..8aeffaa74d4 100644
--- a/chromium/cc/mojom/render_frame_metadata_mojom_traits.cc
+++ b/chromium/cc/mojom/render_frame_metadata_mojom_traits.cc
@@ -8,6 +8,7 @@
#include "mojo/public/cpp/base/time_mojom_traits.h"
#include "services/viz/public/cpp/compositing/selection_mojom_traits.h"
#include "services/viz/public/cpp/compositing/vertical_scroll_direction_mojom_traits.h"
+#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/geometry/mojom/geometry_mojom_traits.h"
#include "ui/gfx/mojom/selection_bound_mojom_traits.h"
@@ -27,7 +28,6 @@ bool StructTraits<
cc::mojom::RenderFrameMetadataDataView,
cc::RenderFrameMetadata>::Read(cc::mojom::RenderFrameMetadataDataView data,
cc::RenderFrameMetadata* out) {
- out->root_background_color = data.root_background_color();
out->is_scroll_offset_at_top = data.is_scroll_offset_at_top();
out->is_mobile_optimized = data.is_mobile_optimized();
out->device_scale_factor = data.device_scale_factor();
@@ -60,7 +60,8 @@ bool StructTraits<
data.ReadPreviousSurfacesVisualUpdateDuration(
&out->previous_surfaces_visual_update_duration) &&
data.ReadCurrentSurfaceVisualUpdateDuration(
- &out->current_surface_visual_update_duration);
+ &out->current_surface_visual_update_duration) &&
+ data.ReadRootBackgroundColor(&out->root_background_color);
}
} // namespace mojo
diff --git a/chromium/cc/mojom/render_frame_metadata_mojom_traits.h b/chromium/cc/mojom/render_frame_metadata_mojom_traits.h
index 8631acd1a6e..eec5bed32c9 100644
--- a/chromium/cc/mojom/render_frame_metadata_mojom_traits.h
+++ b/chromium/cc/mojom/render_frame_metadata_mojom_traits.h
@@ -10,7 +10,9 @@
#include "cc/mojom/render_frame_metadata.mojom-shared.h"
#include "cc/trees/render_frame_metadata.h"
#include "services/viz/public/cpp/compositing/local_surface_id_mojom_traits.h"
+#include "skia/public/mojom/skcolor4f_mojom_traits.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/skia/include/core/SkColor.h"
namespace mojo {
@@ -31,7 +33,7 @@ template <>
struct COMPONENT_EXPORT(CC_SHARED_MOJOM_TRAITS)
StructTraits<cc::mojom::RenderFrameMetadataDataView,
cc::RenderFrameMetadata> {
- static SkColor root_background_color(
+ static SkColor4f root_background_color(
const cc::RenderFrameMetadata& metadata) {
return metadata.root_background_color;
}
diff --git a/chromium/cc/paint/display_item_list.h b/chromium/cc/paint/display_item_list.h
index 0a52e86b7fe..6f7c59f9ec0 100644
--- a/chromium/cc/paint/display_item_list.h
+++ b/chromium/cc/paint/display_item_list.h
@@ -149,7 +149,9 @@ class CC_PAINT_EXPORT DisplayItemList
absl::optional<DirectlyCompositedImageResult>
GetDirectlyCompositedImageResult() const;
- int num_slow_paths() const { return paint_op_buffer_.num_slow_paths(); }
+ int num_slow_paths_up_to_min_for_MSAA() const {
+ return paint_op_buffer_.num_slow_paths_up_to_min_for_MSAA();
+ }
bool HasNonAAPaint() const { return paint_op_buffer_.HasNonAAPaint(); }
// This gives the total number of PaintOps.
@@ -173,7 +175,9 @@ class CC_PAINT_EXPORT DisplayItemList
void EmitTraceSnapshot() const;
void GenerateDiscardableImagesMetadata();
- gfx::Rect VisualRectForTesting(int index) { return visual_rects_[index]; }
+ gfx::Rect VisualRectForTesting(int index) {
+ return visual_rects_[static_cast<size_t>(index)];
+ }
// Generate a PaintRecord from this DisplayItemList, leaving |this| in
// an empty state.
diff --git a/chromium/cc/paint/display_item_list_unittest.cc b/chromium/cc/paint/display_item_list_unittest.cc
index 90608ac939f..894be54150d 100644
--- a/chromium/cc/paint/display_item_list_unittest.cc
+++ b/chromium/cc/paint/display_item_list_unittest.cc
@@ -75,13 +75,13 @@ class DisplayItemListTest : public testing::Test {
}
};
-#define EXPECT_TRACED_RECT(x, y, width, height, rect_list) \
- do { \
- ASSERT_EQ(4u, rect_list->GetListDeprecated().size()); \
- EXPECT_EQ(x, rect_list->GetListDeprecated()[0].GetIfDouble()); \
- EXPECT_EQ(y, rect_list->GetListDeprecated()[1].GetIfDouble()); \
- EXPECT_EQ(width, rect_list->GetListDeprecated()[2].GetIfDouble()); \
- EXPECT_EQ(height, rect_list->GetListDeprecated()[3].GetIfDouble()); \
+#define EXPECT_TRACED_RECT(x, y, width, height, rect_list) \
+ do { \
+ ASSERT_EQ(4u, rect_list->size()); \
+ EXPECT_EQ(x, (*rect_list)[0].GetIfDouble()); \
+ EXPECT_EQ(y, (*rect_list)[1].GetIfDouble()); \
+ EXPECT_EQ(width, (*rect_list)[2].GetIfDouble()); \
+ EXPECT_EQ(height, (*rect_list)[3].GetIfDouble()); \
} while (false)
// AddToValue should not crash if there are different numbers of visual_rect
@@ -106,34 +106,35 @@ TEST_F(DisplayItemListTest, TraceEmptyVisualRect) {
// Pass: we don't crash
std::unique_ptr<base::Value> root = ToBaseValue(list.get(), true);
- const base::DictionaryValue* root_dict;
- ASSERT_TRUE(root->GetAsDictionary(&root_dict));
- const base::DictionaryValue* params_dict;
- ASSERT_TRUE(root_dict->GetDictionary("params", &params_dict));
- const base::ListValue* items;
- ASSERT_TRUE(params_dict->GetList("items", &items));
- ASSERT_EQ(2u, items->GetListDeprecated().size());
-
- const base::Value* item_value;
- const base::DictionaryValue* item_dict;
- const base::ListValue* visual_rect;
- std::string name;
-
- item_value = &items->GetListDeprecated()[0];
- ASSERT_TRUE(item_value->is_dict());
- item_dict = &base::Value::AsDictionaryValue(*item_value);
- ASSERT_TRUE(item_dict->GetList("visual_rect", &visual_rect));
+ const base::Value::Dict* root_dict = root->GetIfDict();
+ ASSERT_NE(nullptr, root_dict);
+ const base::Value::Dict* params_dict = root_dict->FindDict("params");
+ ASSERT_NE(nullptr, params_dict);
+ const base::Value::List* items = params_dict->FindList("items");
+ ASSERT_NE(nullptr, items);
+ ASSERT_EQ(2u, items->size());
+
+ const base::Value::Dict* item_dict;
+ const base::Value::List* visual_rect;
+ const std::string* name;
+
+ item_dict = ((*items)[0]).GetIfDict();
+ ASSERT_NE(nullptr, item_dict);
+ visual_rect = item_dict->FindList("visual_rect");
+ ASSERT_NE(nullptr, visual_rect);
EXPECT_TRACED_RECT(0, 0, 0, 0, visual_rect);
- EXPECT_TRUE(item_dict->GetString("name", &name));
- EXPECT_EQ("DrawRect", name);
-
- item_value = &items->GetListDeprecated()[1];
- ASSERT_TRUE(item_value->is_dict());
- item_dict = &base::Value::AsDictionaryValue(*item_value);
- ASSERT_TRUE(item_dict->GetList("visual_rect", &visual_rect));
+ name = item_dict->FindString("name");
+ ASSERT_NE(nullptr, name);
+ EXPECT_EQ("DrawRect", *name);
+
+ item_dict = ((*items)[1]).GetIfDict();
+ ASSERT_NE(nullptr, item_dict);
+ visual_rect = item_dict->FindList("visual_rect");
+ ASSERT_NE(nullptr, visual_rect);
EXPECT_TRACED_RECT(8, 9, 10, 10, visual_rect);
- EXPECT_TRUE(item_dict->GetString("name", &name));
- EXPECT_EQ("DrawRect", name);
+ name = item_dict->FindString("name");
+ ASSERT_NE(nullptr, name);
+ EXPECT_EQ("DrawRect", *name);
}
TEST_F(DisplayItemListTest, SingleUnpairedRange) {
@@ -460,45 +461,50 @@ TEST_F(DisplayItemListTest, AsValueWithNoOps) {
// Pass |true| to ask for PaintOps even though there are none.
std::unique_ptr<base::Value> root = ToBaseValue(list.get(), true);
- const base::DictionaryValue* root_dict;
- ASSERT_TRUE(root->GetAsDictionary(&root_dict));
+ const base::Value::Dict* root_dict = root->GetIfDict();
+ ASSERT_NE(nullptr, root_dict);
// The traced value has a params dictionary as its root.
{
- const base::DictionaryValue* params_dict;
- ASSERT_TRUE(root_dict->GetDictionary("params", &params_dict));
+ const base::Value::Dict* params_dict = root_dict->FindDict("params");
+ ASSERT_NE(nullptr, params_dict);
// The real contents of the traced value is in here.
{
- const base::ListValue* params_list;
+ const base::Value::List* params_list;
// The layer_rect field is present by empty.
- ASSERT_TRUE(params_dict->GetList("layer_rect", &params_list));
+ params_list = params_dict->FindList("layer_rect");
+ ASSERT_NE(nullptr, params_list);
EXPECT_TRACED_RECT(0, 0, 0, 0, params_list);
// The items list is there but empty.
- ASSERT_TRUE(params_dict->GetList("items", &params_list));
- EXPECT_EQ(0u, params_list->GetListDeprecated().size());
+ params_list = params_dict->FindList("items");
+ ASSERT_NE(nullptr, params_list);
+ EXPECT_EQ(0u, params_list->size());
}
}
// Pass |false| to not include PaintOps.
root = ToBaseValue(list.get(), false);
- ASSERT_TRUE(root->GetAsDictionary(&root_dict));
+ root_dict = root->GetIfDict();
+ ASSERT_NE(nullptr, root_dict);
// The traced value has a params dictionary as its root.
{
- const base::DictionaryValue* params_dict;
- ASSERT_TRUE(root_dict->GetDictionary("params", &params_dict));
+ const base::Value::Dict* params_dict = root_dict->FindDict("params");
+ ASSERT_NE(nullptr, params_dict);
// The real contents of the traced value is in here.
{
- const base::ListValue* params_list;
+ const base::Value::List* params_list;
// The layer_rect field is present by empty.
- ASSERT_TRUE(params_dict->GetList("layer_rect", &params_list));
+ params_list = params_dict->FindList("layer_rect");
+ ASSERT_NE(nullptr, params_list);
EXPECT_TRACED_RECT(0, 0, 0, 0, params_list);
// The items list is not there since we asked for no ops.
- ASSERT_FALSE(params_dict->GetList("items", &params_list));
+ params_list = params_dict->FindList("items");
+ ASSERT_EQ(nullptr, params_list);
}
}
}
@@ -542,24 +548,25 @@ TEST_F(DisplayItemListTest, AsValueWithOps) {
// Pass |true| to ask for PaintOps to be included.
std::unique_ptr<base::Value> root = ToBaseValue(list.get(), true);
- const base::DictionaryValue* root_dict;
- ASSERT_TRUE(root->GetAsDictionary(&root_dict));
+ const base::Value::Dict* root_dict = root->GetIfDict();
+ ASSERT_NE(nullptr, root_dict);
// The traced value has a params dictionary as its root.
{
- const base::DictionaryValue* params_dict;
- ASSERT_TRUE(root_dict->GetDictionary("params", &params_dict));
+ const base::Value::Dict* params_dict = root_dict->FindDict("params");
+ ASSERT_NE(nullptr, params_dict);
// The real contents of the traced value is in here.
{
- const base::ListValue* layer_rect_list;
+ const base::Value::List* layer_rect_list =
+ params_dict->FindList("layer_rect");
// The layer_rect field is present and has the bounds of the rtree.
- ASSERT_TRUE(params_dict->GetList("layer_rect", &layer_rect_list));
+ ASSERT_NE(nullptr, layer_rect_list);
EXPECT_TRACED_RECT(2, 3, 8, 9, layer_rect_list);
// The items list has 3 things in it since we built 3 visual rects.
- const base::ListValue* items;
- ASSERT_TRUE(params_dict->GetList("items", &items));
- ASSERT_EQ(7u, items->GetListDeprecated().size());
+ const base::Value::List* items = params_dict->FindList("items");
+ ASSERT_NE(nullptr, items);
+ ASSERT_EQ(7u, items->size());
const char* expected_names[] = {"Save", "Concat", "SaveLayer",
"Translate", "DrawRect", "Restore",
@@ -567,43 +574,45 @@ TEST_F(DisplayItemListTest, AsValueWithOps) {
bool expected_has_skp[] = {false, true, true, true, true, false, false};
for (int i = 0; i < 7; ++i) {
- const base::Value& item_value = items->GetListDeprecated()[i];
+ const base::Value& item_value = (*items)[i];
ASSERT_TRUE(item_value.is_dict());
- const base::DictionaryValue& item_dict =
- base::Value::AsDictionaryValue(item_value);
+ const base::Value::Dict& item_dict = item_value.GetDict();
- const base::ListValue* visual_rect;
- ASSERT_TRUE(item_dict.GetList("visual_rect", &visual_rect));
+ const base::Value::List* visual_rect =
+ item_dict.FindList("visual_rect");
+ ASSERT_NE(nullptr, visual_rect);
EXPECT_TRACED_RECT(2, 3, 8, 9, visual_rect);
- std::string name;
- EXPECT_TRUE(item_dict.GetString("name", &name));
- EXPECT_EQ(expected_names[i], name);
+ const std::string* name = item_dict.FindString("name");
+ EXPECT_NE(nullptr, name);
+ EXPECT_EQ(expected_names[i], *name);
- EXPECT_EQ(
- expected_has_skp[i],
- item_dict.GetString("skp64", static_cast<std::string*>(nullptr)));
+ EXPECT_EQ(expected_has_skp[i],
+ item_dict.FindString("skp64") != nullptr);
}
}
}
// Pass |false| to not include PaintOps.
root = ToBaseValue(list.get(), false);
- ASSERT_TRUE(root->GetAsDictionary(&root_dict));
+ root_dict = root->GetIfDict();
+ ASSERT_NE(nullptr, root_dict);
// The traced value has a params dictionary as its root.
{
- const base::DictionaryValue* params_dict;
- ASSERT_TRUE(root_dict->GetDictionary("params", &params_dict));
+ const base::Value::Dict* params_dict = root_dict->FindDict("params");
+ ASSERT_NE(nullptr, params_dict);
// The real contents of the traced value is in here.
{
- const base::ListValue* params_list;
+ const base::Value::List* params_list;
// The layer_rect field is present and has the bounds of the rtree.
- ASSERT_TRUE(params_dict->GetList("layer_rect", &params_list));
+ params_list = params_dict->FindList("layer_rect");
+ ASSERT_NE(nullptr, params_list);
EXPECT_TRACED_RECT(2, 3, 8, 9, params_list);
// The items list is not present since we asked for no ops.
- ASSERT_FALSE(params_dict->GetList("items", &params_list));
+ params_list = params_dict->FindList("items");
+ ASSERT_EQ(nullptr, params_list);
}
}
}
diff --git a/chromium/cc/paint/filter_operation.cc b/chromium/cc/paint/filter_operation.cc
index db70fd2f612..b5a36c2335c 100644
--- a/chromium/cc/paint/filter_operation.cc
+++ b/chromium/cc/paint/filter_operation.cc
@@ -54,7 +54,7 @@ FilterOperation::FilterOperation(FilterType type, float amount)
amount_(amount),
outer_threshold_(0),
drop_shadow_offset_(0, 0),
- drop_shadow_color_(0),
+ drop_shadow_color_(SkColors::kTransparent),
zoom_inset_(0) {
DCHECK_NE(type_, DROP_SHADOW);
DCHECK_NE(type_, COLOR_MATRIX);
@@ -69,7 +69,7 @@ FilterOperation::FilterOperation(FilterType type,
amount_(amount),
outer_threshold_(0),
drop_shadow_offset_(0, 0),
- drop_shadow_color_(0),
+ drop_shadow_color_(SkColors::kTransparent),
zoom_inset_(0),
blur_tile_mode_(tile_mode) {
DCHECK_EQ(type_, BLUR);
@@ -79,7 +79,7 @@ FilterOperation::FilterOperation(FilterType type,
FilterOperation::FilterOperation(FilterType type,
const gfx::Point& offset,
float stdDeviation,
- SkColor color)
+ SkColor4f color)
: type_(type),
amount_(stdDeviation),
outer_threshold_(0),
@@ -95,7 +95,7 @@ FilterOperation::FilterOperation(FilterType type, const Matrix& matrix)
amount_(0),
outer_threshold_(0),
drop_shadow_offset_(0, 0),
- drop_shadow_color_(0),
+ drop_shadow_color_(SkColors::kTransparent),
zoom_inset_(0) {
DCHECK_EQ(type_, COLOR_MATRIX);
memcpy(matrix_, matrix, sizeof(matrix_));
@@ -106,7 +106,7 @@ FilterOperation::FilterOperation(FilterType type, float amount, int inset)
amount_(amount),
outer_threshold_(0),
drop_shadow_offset_(0, 0),
- drop_shadow_color_(0),
+ drop_shadow_color_(SkColors::kTransparent),
zoom_inset_(inset) {
DCHECK_EQ(type_, ZOOM);
memset(matrix_, 0, sizeof(matrix_));
@@ -119,7 +119,7 @@ FilterOperation::FilterOperation(FilterType type,
amount_(amount),
outer_threshold_(outer_threshold),
drop_shadow_offset_(0, 0),
- drop_shadow_color_(0),
+ drop_shadow_color_(SkColors::kTransparent),
zoom_inset_(0) {
DCHECK_EQ(type_, STRETCH);
memset(matrix_, 0, sizeof(matrix_));
@@ -131,7 +131,7 @@ FilterOperation::FilterOperation(FilterType type,
amount_(0),
outer_threshold_(0),
drop_shadow_offset_(0, 0),
- drop_shadow_color_(0),
+ drop_shadow_color_(SkColors::kTransparent),
image_filter_(std::move(image_filter)),
zoom_inset_(0) {
DCHECK_EQ(type_, REFERENCE);
@@ -146,7 +146,7 @@ FilterOperation::FilterOperation(FilterType type,
amount_(inner_threshold),
outer_threshold_(outer_threshold),
drop_shadow_offset_(0, 0),
- drop_shadow_color_(0),
+ drop_shadow_color_(SkColors::kTransparent),
zoom_inset_(0),
shape_(shape) {
DCHECK_EQ(type_, ALPHA_THRESHOLD);
@@ -190,7 +190,7 @@ static FilterOperation CreateNoOpFilter(FilterOperation::FilterType type) {
return FilterOperation::CreateBlurFilter(0.f);
case FilterOperation::DROP_SHADOW:
return FilterOperation::CreateDropShadowFilter(gfx::Point(0, 0), 0.f,
- SK_ColorTRANSPARENT);
+ SkColors::kTransparent);
case FilterOperation::COLOR_MATRIX: {
FilterOperation::Matrix matrix = {};
matrix[0] = matrix[6] = matrix[12] = matrix[18] = 1.f;
@@ -318,7 +318,8 @@ void FilterOperation::AsValueInto(base::trace_event::TracedValue* value) const {
case FilterOperation::DROP_SHADOW:
value->SetDouble("std_deviation", amount_);
MathUtil::AddToTracedValue("offset", drop_shadow_offset_, value);
- value->SetInteger("color", drop_shadow_color_);
+ // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
+ value->SetInteger("color", drop_shadow_color_.toSkColor());
break;
case FilterOperation::COLOR_MATRIX: {
value->BeginArray("matrix");
diff --git a/chromium/cc/paint/filter_operation.h b/chromium/cc/paint/filter_operation.h
index 02002920792..9fce89757bd 100644
--- a/chromium/cc/paint/filter_operation.h
+++ b/chromium/cc/paint/filter_operation.h
@@ -75,7 +75,7 @@ class CC_PAINT_EXPORT FilterOperation {
return drop_shadow_offset_;
}
- SkColor drop_shadow_color() const {
+ SkColor4f drop_shadow_color() const {
DCHECK_EQ(type_, DROP_SHADOW);
return drop_shadow_color_;
}
@@ -145,7 +145,7 @@ class CC_PAINT_EXPORT FilterOperation {
static FilterOperation CreateDropShadowFilter(const gfx::Point& offset,
float std_deviation,
- SkColor color) {
+ SkColor4f color) {
return FilterOperation(DROP_SHADOW, offset, std_deviation, color);
}
@@ -206,7 +206,7 @@ class CC_PAINT_EXPORT FilterOperation {
drop_shadow_offset_ = offset;
}
- void set_drop_shadow_color(SkColor color) {
+ void set_drop_shadow_color(SkColor4f color) {
DCHECK_EQ(type_, DROP_SHADOW);
drop_shadow_color_ = color;
}
@@ -265,7 +265,7 @@ class CC_PAINT_EXPORT FilterOperation {
FilterOperation(FilterType type,
const gfx::Point& offset,
float stdDeviation,
- SkColor color);
+ SkColor4f color);
FilterOperation(FilterType, const Matrix& matrix);
@@ -284,7 +284,7 @@ class CC_PAINT_EXPORT FilterOperation {
float amount_;
float outer_threshold_;
gfx::Point drop_shadow_offset_;
- SkColor drop_shadow_color_;
+ SkColor4f drop_shadow_color_;
sk_sp<PaintFilter> image_filter_;
Matrix matrix_;
int zoom_inset_;
diff --git a/chromium/cc/paint/filter_operations_unittest.cc b/chromium/cc/paint/filter_operations_unittest.cc
index 54fe83569ae..4684ef60780 100644
--- a/chromium/cc/paint/filter_operations_unittest.cc
+++ b/chromium/cc/paint/filter_operations_unittest.cc
@@ -54,7 +54,7 @@ TEST(FilterOperationsTest, MapRectDropShadowReferenceFilter) {
ops.Append(
FilterOperation::CreateReferenceFilter(sk_make_sp<DropShadowPaintFilter>(
SkIntToScalar(3), SkIntToScalar(8), SkIntToScalar(4),
- SkIntToScalar(9), SK_ColorBLACK,
+ SkIntToScalar(9), SkColors::kBlack,
DropShadowPaintFilter::ShadowMode::kDrawShadowAndForeground,
nullptr)));
EXPECT_EQ(gfx::Rect(-9, -19, 34, 64),
@@ -70,7 +70,7 @@ TEST(FilterOperationsTest, MapRectReverseDropShadowReferenceFilter) {
ops.Append(
FilterOperation::CreateReferenceFilter(sk_make_sp<DropShadowPaintFilter>(
SkIntToScalar(3), SkIntToScalar(8), SkIntToScalar(4),
- SkIntToScalar(9), SK_ColorBLACK,
+ SkIntToScalar(9), SkColors::kBlack,
DropShadowPaintFilter::ShadowMode::kDrawShadowAndForeground,
nullptr)));
EXPECT_EQ(gfx::Rect(-15, -35, 34, 64),
@@ -171,7 +171,8 @@ TEST(FilterOperationsTest, MapRectReverseNullReferenceFilter) {
TEST(FilterOperationsTest, MapRectDropShadow) {
FilterOperations ops;
- ops.Append(FilterOperation::CreateDropShadowFilter(gfx::Point(3, 8), 20, 0));
+ ops.Append(FilterOperation::CreateDropShadowFilter(gfx::Point(3, 8), 20,
+ SkColors::kTransparent));
EXPECT_EQ(gfx::Rect(-57, -52, 130, 130),
ops.MapRect(gfx::Rect(0, 0, 10, 10), SkMatrix::I()));
EXPECT_EQ(gfx::Rect(-114, -104, 260, 260),
@@ -182,7 +183,8 @@ TEST(FilterOperationsTest, MapRectDropShadow) {
TEST(FilterOperationsTest, MapRectReverseDropShadow) {
FilterOperations ops;
- ops.Append(FilterOperation::CreateDropShadowFilter(gfx::Point(3, 8), 20, 0));
+ ops.Append(FilterOperation::CreateDropShadowFilter(gfx::Point(3, 8), 20,
+ SkColors::kTransparent));
EXPECT_EQ(gfx::Rect(-63, -68, 130, 130),
ops.MapRectReverse(gfx::Rect(0, 0, 10, 10), SkMatrix::I()));
EXPECT_EQ(gfx::Rect(-126, -136, 260, 260),
@@ -196,7 +198,8 @@ TEST(FilterOperationsTest, MapRectDropShadowDoesNotContract) {
// Even with a drop-shadow, the original content is still drawn. Thus the
// content bounds are never contracted due to a drop-shadow.
FilterOperations ops;
- ops.Append(FilterOperation::CreateDropShadowFilter(gfx::Point(3, 8), 0, 0));
+ ops.Append(FilterOperation::CreateDropShadowFilter(gfx::Point(3, 8), 0,
+ SkColors::kTransparent));
EXPECT_EQ(gfx::Rect(0, 0, 13, 18),
ops.MapRect(gfx::Rect(0, 0, 10, 10), SkMatrix::I()));
}
@@ -205,7 +208,8 @@ TEST(FilterOperationsTest, MapRectReverseDropShadowDoesNotContract) {
// Even with a drop-shadow, the original content is still drawn. Thus the
// content bounds are never contracted due to a drop-shadow.
FilterOperations ops;
- ops.Append(FilterOperation::CreateDropShadowFilter(gfx::Point(3, 8), 0, 0));
+ ops.Append(FilterOperation::CreateDropShadowFilter(gfx::Point(3, 8), 0,
+ SkColors::kTransparent));
EXPECT_EQ(gfx::Rect(-3, -8, 13, 18),
ops.MapRectReverse(gfx::Rect(0, 0, 10, 10), SkMatrix::I()));
}
@@ -324,7 +328,7 @@ TEST(FilterOperationsTest, SaveAndRestore) {
SAVE_RESTORE_AMOUNT(Blur, BLUR, 0.6f);
SAVE_RESTORE_AMOUNT(SaturatingBrightness, SATURATING_BRIGHTNESS, 0.6f);
SAVE_RESTORE_OFFSET_AMOUNT_COLOR(DropShadow, DROP_SHADOW, gfx::Point(3, 4),
- 0.4f, 0xffffff00);
+ 0.4f, SkColors::kYellow);
SkScalar matrix[20] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
@@ -596,43 +600,74 @@ TEST(FilterOperationsTest, BlendBlurWithNull) {
TEST(FilterOperationsTest, BlendDropShadowFilters) {
FilterOperation from = FilterOperation::CreateDropShadowFilter(
- gfx::Point(0, 0), 2.f, SkColorSetARGB(15, 34, 68, 136));
+ gfx::Point(0, 0), 2.f, SkColor4f{0.13f, 0.27f, 0.53f, 0.06f});
FilterOperation to = FilterOperation::CreateDropShadowFilter(
- gfx::Point(3, 5), 6.f, SkColorSetARGB(51, 30, 60, 120));
+ gfx::Point(3, 5), 6.f, SkColor4f{0.12f, 0.24f, 0.47f, 0.2f});
+ // In the test below we have to use EXPECT_NEAR as the color contain float for
+ // the components. In order to properly test the filterOperation we are
+ // equalizing the color aftewards.
FilterOperation blended = FilterOperation::Blend(&from, &to, -0.75);
FilterOperation expected = FilterOperation::CreateDropShadowFilter(
- gfx::Point(-2, -4), 0.f, SkColorSetARGB(0, 0, 0, 0));
+ gfx::Point(-2, -4), 0.f, SkColor4f{0.0f, 0.0f, 0.0f, 0.0f});
+ SkColor4f blended_color = blended.drop_shadow_color();
+ SkColor4f expected_color = expected.drop_shadow_color();
+ EXPECT_NEAR(blended_color.fR, expected_color.fR, 0.0001f);
+ EXPECT_NEAR(blended_color.fG, expected_color.fG, 0.0001f);
+ EXPECT_NEAR(blended_color.fB, expected_color.fB, 0.0001f);
+ EXPECT_NEAR(blended_color.fA, expected_color.fA, 0.0001f);
+ expected.set_drop_shadow_color(blended_color);
EXPECT_EQ(expected, blended);
blended = FilterOperation::Blend(&from, &to, 0.25);
expected = FilterOperation::CreateDropShadowFilter(
- gfx::Point(1, 1), 3.f, SkColorSetARGB(24, 32, 64, 128));
+ gfx::Point(1, 1), 3.f, SkColor4f{0.1247f, 0.2542f, 0.4984f, 0.095f});
+ blended_color = blended.drop_shadow_color();
+ expected_color = expected.drop_shadow_color();
+ EXPECT_NEAR(blended_color.fR, expected_color.fR, 0.0001f);
+ EXPECT_NEAR(blended_color.fG, expected_color.fG, 0.0001f);
+ EXPECT_NEAR(blended_color.fB, expected_color.fB, 0.0001f);
+ EXPECT_NEAR(blended_color.fA, expected_color.fA, 0.0001f);
+ expected.set_drop_shadow_color(blended_color);
EXPECT_EQ(expected, blended);
blended = FilterOperation::Blend(&from, &to, 0.75);
expected = FilterOperation::CreateDropShadowFilter(
- gfx::Point(2, 4), 5.f, SkColorSetARGB(42, 30, 61, 121));
+ gfx::Point(2, 4), 5.f, SkColor4f{0.1209f, 0.2427f, 0.4755f, 0.1649f});
+ blended_color = blended.drop_shadow_color();
+ expected_color = expected.drop_shadow_color();
+ EXPECT_NEAR(blended_color.fR, expected_color.fR, 0.0001f);
+ EXPECT_NEAR(blended_color.fG, expected_color.fG, 0.0001f);
+ EXPECT_NEAR(blended_color.fB, expected_color.fB, 0.0001f);
+ EXPECT_NEAR(blended_color.fA, expected_color.fA, 0.0001f);
+ expected.set_drop_shadow_color(blended_color);
EXPECT_EQ(expected, blended);
blended = FilterOperation::Blend(&from, &to, 1.5);
expected = FilterOperation::CreateDropShadowFilter(
- gfx::Point(5, 8), 8.f, SkColorSetARGB(69, 30, 59, 118));
+ gfx::Point(5, 8), 8.f, SkColor4f{0.1188f, 0.2366f, 0.4633f, 0.27});
+ blended_color = blended.drop_shadow_color();
+ expected_color = expected.drop_shadow_color();
+ EXPECT_NEAR(blended_color.fR, expected_color.fR, 0.0001f);
+ EXPECT_NEAR(blended_color.fG, expected_color.fG, 0.0001f);
+ EXPECT_NEAR(blended_color.fB, expected_color.fB, 0.0001f);
+ EXPECT_NEAR(blended_color.fA, expected_color.fA, 0.0001f);
+ expected.set_drop_shadow_color(blended_color);
EXPECT_EQ(expected, blended);
}
TEST(FilterOperationsTest, BlendDropShadowWithNull) {
FilterOperation filter = FilterOperation::CreateDropShadowFilter(
- gfx::Point(4, 4), 4.f, SkColorSetARGB(255, 40, 0, 0));
+ gfx::Point(4, 4), 4.f, SkColor4f{0.16f, 0.0f, 0.0f, 1.0f});
FilterOperation blended = FilterOperation::Blend(&filter, nullptr, 0.25);
FilterOperation expected = FilterOperation::CreateDropShadowFilter(
- gfx::Point(3, 3), 3.f, SkColorSetARGB(191, 40, 0, 0));
+ gfx::Point(3, 3), 3.f, SkColor4f{0.16f, 0.0f, 0.0f, 0.75f});
EXPECT_EQ(expected, blended);
blended = FilterOperation::Blend(nullptr, &filter, 0.25);
expected = FilterOperation::CreateDropShadowFilter(
- gfx::Point(1, 1), 1.f, SkColorSetARGB(64, 40, 0, 0));
+ gfx::Point(1, 1), 1.f, SkColor4f{0.16f, 0.0f, 0.0f, 0.25f});
EXPECT_EQ(expected, blended);
}
@@ -934,8 +969,8 @@ TEST(FilterOperationsTest, MaximumPixelMovement) {
EXPECT_FLOAT_EQ(20.f * 3, filters.MaximumPixelMovement());
filters.Clear();
- filters.Append(
- FilterOperation::CreateDropShadowFilter(gfx::Point(3, -8), 20, 0));
+ filters.Append(FilterOperation::CreateDropShadowFilter(
+ gfx::Point(3, -8), 20, SkColors::kTransparent));
float max_movement = fmax(std::abs(3), std::abs(-8)) + 20.f * 3;
EXPECT_FLOAT_EQ(max_movement, filters.MaximumPixelMovement());
diff --git a/chromium/cc/paint/image_transfer_cache_entry.cc b/chromium/cc/paint/image_transfer_cache_entry.cc
index 7fdce720233..6c32b6c2981 100644
--- a/chromium/cc/paint/image_transfer_cache_entry.cc
+++ b/chromium/cc/paint/image_transfer_cache_entry.cc
@@ -209,6 +209,8 @@ size_t TargetColorParamsSize(
// Floats for the SDR and HDR maximum luminance.
target_color_params_size += sizeof(float);
target_color_params_size += sizeof(float);
+ // uint32_t for tone mapping enabled or disabled.
+ target_color_params_size += sizeof(uint32_t);
}
return target_color_params_size;
}
@@ -222,6 +224,7 @@ void WriteTargetColorParams(
writer.Write(target_color_params->color_space.ToSkColorSpace().get());
writer.Write(target_color_params->sdr_max_luminance_nits);
writer.Write(target_color_params->hdr_max_luminance_relative);
+ writer.Write(target_color_params->enable_tone_mapping);
}
}
@@ -244,6 +247,7 @@ bool ReadTargetColorParams(
target_color_params->color_space = gfx::ColorSpace(*target_color_space);
reader.Read(&target_color_params->sdr_max_luminance_nits);
reader.Read(&target_color_params->hdr_max_luminance_relative);
+ reader.Read(&target_color_params->enable_tone_mapping);
return true;
}
@@ -296,7 +300,7 @@ ClientImageTransferCacheEntry::ClientImageTransferCacheEntry(
// 4-byte boundary.
safe_size += 4;
safe_size += pixmap_->computeByteSize();
- size_ = base::bits::AlignUp(safe_size.ValueOrDefault(0),
+ size_ = base::bits::AlignUp(size_t{safe_size.ValueOrDefault(0)},
PaintOpWriter::Alignment());
}
@@ -346,7 +350,7 @@ ClientImageTransferCacheEntry::ClientImageTransferCacheEntry(
safe_size += decoded_color_space_size + align; // SkColorSpace for YUVA image
for (size_t i = 0; i < num_yuva_pixmaps; ++i)
safe_size += SafeSizeForPixmap(*yuv_pixmaps_->at(i));
- size_ = base::bits::AlignUp(safe_size.ValueOrDefault(0),
+ size_ = base::bits::AlignUp(size_t{safe_size.ValueOrDefault(0)},
PaintOpWriter::Alignment());
}
@@ -586,6 +590,7 @@ bool ServiceImageTransferCacheEntry::Deserialize(
image_, target_color_params->color_space.ToSkColorSpace(),
target_color_params->sdr_max_luminance_nits,
target_color_params->hdr_max_luminance_relative,
+ target_color_params->enable_tone_mapping,
fits_on_gpu_ ? context_ : nullptr);
if (!image_) {
DLOG(ERROR) << "Failed image color conversion";
diff --git a/chromium/cc/paint/image_transfer_cache_entry_unittest.cc b/chromium/cc/paint/image_transfer_cache_entry_unittest.cc
index 817d3115deb..b18eb557135 100644
--- a/chromium/cc/paint/image_transfer_cache_entry_unittest.cc
+++ b/chromium/cc/paint/image_transfer_cache_entry_unittest.cc
@@ -36,6 +36,7 @@
#include "ui/gl/gl_context_egl.h"
#include "ui/gl/gl_share_group.h"
#include "ui/gl/gl_surface.h"
+#include "ui/gl/gl_utils.h"
#include "ui/gl/init/create_gr_gl_interface.h"
#include "ui/gl/init/gl_factory.h"
@@ -86,7 +87,8 @@ class ImageTransferCacheEntryTest
public:
void SetUp() override {
// Initialize a GL GrContext for Skia.
- surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size());
+ surface_ = gl::init::CreateOffscreenGLSurface(gl::GetDefaultDisplay(),
+ gfx::Size());
ASSERT_TRUE(surface_);
share_group_ = base::MakeRefCounted<gl::GLShareGroup>();
gl_context_ = base::MakeRefCounted<gl::GLContextEGL>(share_group_.get());
@@ -94,9 +96,9 @@ class ImageTransferCacheEntryTest
ASSERT_TRUE(
gl_context_->Initialize(surface_.get(), gl::GLContextAttribs()));
ASSERT_TRUE(gl_context_->MakeCurrent(surface_.get()));
- sk_sp<GrGLInterface> interface(gl::init::CreateGrGLInterface(
+ sk_sp<GrGLInterface> gl_interface(gl::init::CreateGrGLInterface(
*gl_context_->GetVersionInfo(), false /* use_version_es2 */));
- gr_context_ = GrDirectContext::MakeGL(std::move(interface));
+ gr_context_ = GrDirectContext::MakeGL(std::move(gl_interface));
ASSERT_TRUE(gr_context_);
}
diff --git a/chromium/cc/paint/oop_pixeltest.cc b/chromium/cc/paint/oop_pixeltest.cc
index 57c8bf8ff07..d438d117ac5 100644
--- a/chromium/cc/paint/oop_pixeltest.cc
+++ b/chromium/cc/paint/oop_pixeltest.cc
@@ -11,54 +11,41 @@
#include "base/files/file_path.h"
#include "base/memory/raw_ptr.h"
#include "base/path_service.h"
-#include "base/strings/stringprintf.h"
#include "base/test/test_switches.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "cc/base/completion_event.h"
-#include "cc/base/region.h"
-#include "cc/layers/recording_source.h"
#include "cc/paint/display_item_list.h"
#include "cc/paint/paint_filter.h"
#include "cc/paint/paint_flags.h"
#include "cc/paint/paint_image_builder.h"
#include "cc/raster/playback_image_provider.h"
-#include "cc/raster/raster_source.h"
#include "cc/test/pixel_comparator.h"
#include "cc/test/pixel_test_utils.h"
#include "cc/tiles/gpu_image_decode_cache.h"
#include "components/viz/service/gl/gpu_service_impl.h"
+#include "components/viz/test/buildflags.h"
#include "components/viz/test/paths.h"
#include "components/viz/test/test_gpu_service_holder.h"
#include "components/viz/test/test_in_process_context_provider.h"
-#include "gpu/GLES2/gl2extchromium.h"
-#include "gpu/command_buffer/client/gles2_implementation.h"
-#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/client/raster_implementation.h"
-#include "gpu/command_buffer/client/raster_implementation_gles.h"
#include "gpu/command_buffer/client/shared_image_interface.h"
-#include "gpu/command_buffer/client/shared_memory_limits.h"
-#include "gpu/command_buffer/common/context_creation_attribs.h"
#include "gpu/command_buffer/common/shared_image_usage.h"
#include "gpu/command_buffer/service/gr_shader_cache.h"
-#include "gpu/config/gpu_switches.h"
-#include "gpu/ipc/gl_in_process_context.h"
-#include "gpu/skia_bindings/grcontext_for_gles2_interface.h"
#include "ipc/common/gpu_client_ids.h"
#include "skia/ext/legacy_display_globals.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/khronos/GLES2/gl2ext.h"
+#include "third_party/skia/include/core/SkAlphaType.h"
#include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/core/SkColorSpace.h"
+#include "third_party/skia/include/core/SkColorType.h"
#include "third_party/skia/include/core/SkGraphics.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
#include "third_party/skia/include/core/SkRect.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/core/SkTextBlob.h"
#include "third_party/skia/include/core/SkYUVAInfo.h"
-#include "third_party/skia/include/gpu/GrBackendSurface.h"
#include "third_party/skia/include/gpu/GrDirectContext.h"
-#include "third_party/skia/include/gpu/GrYUVABackendTextures.h"
-#include "ui/gfx/geometry/axis_transform2d.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/skia_conversions.h"
#include "ui/gl/gl_implementation.h"
@@ -113,14 +100,7 @@ class OopPixelTest : public testing::Test,
public:
OopPixelTest() : gr_shader_cache_(kCacheLimitBytes, this) {}
- void SetUp() override {
- InitializeOOPContext();
- gles2_context_provider_ =
- base::MakeRefCounted<viz::TestInProcessContextProvider>(
- viz::TestContextType::kGLES2, /*support_locking=*/true);
- gpu::ContextResult result = gles2_context_provider_->BindToCurrentThread();
- DCHECK_EQ(result, gpu::ContextResult::kSuccess);
- }
+ void SetUp() override { InitializeOOPContext(); }
// gpu::raster::GrShaderCache::Client implementation.
void StoreShader(const std::string& key, const std::string& shader) override {
@@ -140,8 +120,7 @@ class OopPixelTest : public testing::Test,
raster_context_provider_->ContextCapabilities().max_texture_size;
oop_image_cache_ = std::make_unique<GpuImageDecodeCache>(
raster_context_provider_.get(), true, kRGBA_8888_SkColorType,
- kWorkingSetSize, raster_max_texture_size,
- PaintImage::GetNextGeneratorClientId(), nullptr);
+ kWorkingSetSize, raster_max_texture_size, nullptr);
}
class RasterOptions {
@@ -197,7 +176,7 @@ class OopPixelTest : public testing::Test,
int height = options.resource_size.height();
// Create and allocate a shared image on the raster interface.
- auto* raster_implementation = raster_context_provider_->RasterInterface();
+ auto* ri = raster_context_provider_->RasterInterface();
auto* sii = raster_context_provider_->SharedImageInterface();
uint32_t flags = gpu::SHARED_IMAGE_USAGE_RASTER |
gpu::SHARED_IMAGE_USAGE_OOP_RASTERIZATION;
@@ -206,8 +185,7 @@ class OopPixelTest : public testing::Test,
options.target_color_params.color_space, kTopLeft_GrSurfaceOrigin,
kPremul_SkAlphaType, flags, gpu::kNullSurfaceHandle);
EXPECT_TRUE(mailbox.Verify());
- raster_implementation->WaitSyncTokenCHROMIUM(
- sii->GenUnverifiedSyncToken().GetConstData());
+ ri->WaitSyncTokenCHROMIUM(sii->GenUnverifiedSyncToken().GetConstData());
// Assume legacy MSAA if sample count is positive.
gpu::raster::MsaaMode msaa_mode = options.msaa_sample_count > 0
@@ -215,20 +193,20 @@ class OopPixelTest : public testing::Test,
: gpu::raster::kNoMSAA;
if (options.preclear) {
- raster_implementation->BeginRasterCHROMIUM(
+ ri->BeginRasterCHROMIUM(
options.preclear_color,
/*needs_clear=*/options.preclear, options.msaa_sample_count,
msaa_mode, options.use_lcd_text,
/*visible=*/true, options.target_color_params.color_space,
mailbox.name);
- raster_implementation->EndRasterCHROMIUM();
+ ri->EndRasterCHROMIUM();
}
// "Out of process" raster! \o/
// If |options.preclear| is true, the mailbox has already been cleared by
// the BeginRasterCHROMIUM call above, and we want to test that it is indeed
// cleared, so set |needs_clear| to false here.
- raster_implementation->BeginRasterCHROMIUM(
+ ri->BeginRasterCHROMIUM(
options.background_color,
/*needs_clear=*/!options.preclear, options.msaa_sample_count, msaa_mode,
options.use_lcd_text,
@@ -236,106 +214,70 @@ class OopPixelTest : public testing::Test,
mailbox.name);
size_t max_op_size_limit =
gpu::raster::RasterInterface::kDefaultMaxOpSizeHint;
- raster_implementation->RasterCHROMIUM(
- display_item_list.get(), &image_provider, options.content_size,
- options.full_raster_rect, options.playback_rect, options.post_translate,
- gfx::Vector2dF(options.post_scale, options.post_scale),
- options.requires_clear, &max_op_size_limit);
+ ri->RasterCHROMIUM(display_item_list.get(), &image_provider,
+ options.content_size, options.full_raster_rect,
+ options.playback_rect, options.post_translate,
+ gfx::Vector2dF(options.post_scale, options.post_scale),
+ options.requires_clear, &max_op_size_limit);
for (const auto& list : options.additional_lists) {
- raster_implementation->RasterCHROMIUM(
- list.get(), &image_provider, options.content_size,
- options.full_raster_rect, options.playback_rect,
- options.post_translate,
- gfx::Vector2dF(options.post_scale, options.post_scale),
- options.requires_clear, &max_op_size_limit);
+ ri->RasterCHROMIUM(list.get(), &image_provider, options.content_size,
+ options.full_raster_rect, options.playback_rect,
+ options.post_translate,
+ gfx::Vector2dF(options.post_scale, options.post_scale),
+ options.requires_clear, &max_op_size_limit);
}
- raster_implementation->EndRasterCHROMIUM();
- raster_implementation->OrderingBarrierCHROMIUM();
+ ri->EndRasterCHROMIUM();
+ ri->OrderingBarrierCHROMIUM();
- EXPECT_EQ(raster_implementation->GetError(),
- static_cast<unsigned>(GL_NO_ERROR));
+ EXPECT_EQ(ri->GetError(), static_cast<unsigned>(GL_NO_ERROR));
- gpu::gles2::GLES2Interface* gl = gles2_context_provider_->ContextGL();
- SkBitmap result = ReadbackMailbox(gl, mailbox, options);
+ SkBitmap result = ReadbackMailbox(ri, mailbox, options.resource_size);
gpu::SyncToken sync_token;
- gl->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
+ ri->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
sii->DestroySharedImage(sync_token, mailbox);
return result;
}
- SkBitmap ReadbackMailbox(gpu::gles2::GLES2Interface* gl,
+ SkBitmap ReadbackMailbox(gpu::raster::RasterInterface* ri,
const gpu::Mailbox& mailbox,
- const RasterOptions& options) {
- // Import the texture in gl, create an fbo and bind the texture to it.
- GLuint gl_texture_id =
- gl->CreateAndTexStorage2DSharedImageCHROMIUM(mailbox.name);
- gl->BeginSharedImageAccessDirectCHROMIUM(
- gl_texture_id, GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM);
- GLuint fbo_id;
- gl->GenFramebuffers(1, &fbo_id);
- gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_id);
- gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- GL_TEXTURE_2D, gl_texture_id, 0);
-
- // Read the data back.
- int width = options.resource_size.width();
- int height = options.resource_size.height();
- std::unique_ptr<unsigned char[]> data(
- new unsigned char[width * height * 4]);
- gl->ReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data.get());
-
- gl->DeleteFramebuffers(1, &fbo_id);
-
- gl->EndSharedImageAccessDirectCHROMIUM(gl_texture_id);
- gl->DeleteTextures(1, &gl_texture_id);
-
- // Swizzle rgba->bgra
- std::vector<SkPMColor> colors;
- colors.reserve(width * height);
- for (int h = 0; h < height; ++h) {
- for (int w = 0; w < width; ++w) {
- int i = (h * width + w) * 4;
- colors.push_back(SkPreMultiplyARGB(data[i + 3], data[i + 0],
- data[i + 1], data[i + 2]));
- }
- }
-
- SkBitmap bitmap;
- bitmap.allocN32Pixels(width, height);
- SkPixmap pixmap(SkImageInfo::MakeN32Premul(width, height), colors.data(),
- width * sizeof(SkColor));
- bitmap.writePixels(pixmap);
- return bitmap;
+ const gfx::Size& image_size,
+ sk_sp<SkColorSpace> color_space = nullptr) {
+ SkImageInfo image_info = SkImageInfo::MakeN32Premul(
+ image_size.width(), image_size.height(), color_space);
+ SkBitmap result;
+ result.allocPixels(image_info);
+ ri->ReadbackImagePixels(mailbox, image_info, image_info.minRowBytes(), 0, 0,
+ result.getPixels());
+ return result;
}
- gpu::Mailbox CreateMailboxSharedImage(gpu::raster::RasterInterface* ri,
- gpu::SharedImageInterface* sii,
- const RasterOptions& options,
- viz::ResourceFormat image_format) {
+ gpu::Mailbox CreateMailboxSharedImage(
+ gpu::raster::RasterInterface* ri,
+ gpu::SharedImageInterface* sii,
+ const RasterOptions& options,
+ viz::ResourceFormat image_format,
+ absl::optional<gfx::ColorSpace> color_space = absl::nullopt) {
uint32_t flags = gpu::SHARED_IMAGE_USAGE_RASTER |
gpu::SHARED_IMAGE_USAGE_OOP_RASTERIZATION;
gpu::Mailbox mailbox = sii->CreateSharedImage(
image_format, options.resource_size,
- options.target_color_params.color_space, kTopLeft_GrSurfaceOrigin,
- kPremul_SkAlphaType, flags, gpu::kNullSurfaceHandle);
+ color_space.value_or(options.target_color_params.color_space),
+ kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, flags,
+ gpu::kNullSurfaceHandle);
EXPECT_TRUE(mailbox.Verify());
ri->WaitSyncTokenCHROMIUM(sii->GenUnverifiedSyncToken().GetConstData());
return mailbox;
}
- void UploadPixels(gpu::gles2::GLES2Interface* gl,
+ void UploadPixels(gpu::raster::RasterInterface* ri,
const gpu::Mailbox& mailbox,
- const gfx::Size& size,
- GLenum format,
- GLenum type,
- const void* data) {
- GLuint texture = gl->CreateAndTexStorage2DSharedImageCHROMIUM(mailbox.name);
- gl->BindTexture(GL_TEXTURE_2D, texture);
- gl->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size.width(), size.height(),
- format, type, data);
- gl->BindTexture(GL_TEXTURE_2D, 0);
- gl->DeleteTextures(1, &texture);
+ const SkImageInfo& info,
+ const SkBitmap& bitmap) {
+ ri->WritePixels(mailbox, 0, 0, 0, info.minRowBytes(), info,
+ bitmap.getPixels());
+ ri->OrderingBarrierCHROMIUM();
+ EXPECT_EQ(ri->GetError(), static_cast<unsigned>(GL_NO_ERROR));
}
// Verifies |actual| matches the expected PNG image.
@@ -367,7 +309,6 @@ class OopPixelTest : public testing::Test,
protected:
static constexpr size_t kWorkingSetSize = 64 * 1024 * 1024;
scoped_refptr<viz::TestInProcessContextProvider> raster_context_provider_;
- scoped_refptr<viz::TestInProcessContextProvider> gles2_context_provider_;
std::unique_ptr<GpuImageDecodeCache> oop_image_cache_;
gl::DisableNullDrawGLBindings enable_pixel_output_;
std::unique_ptr<ImageProvider> image_provider_;
@@ -836,10 +777,7 @@ TEST_F(OopPixelTest, DrawMailboxBackedImage) {
ri, sii, options, viz::ResourceFormat::RGBA_8888);
ri->OrderingBarrierCHROMIUM();
- auto* gl = gles2_context_provider_->ContextGL();
- UploadPixels(gl, src_mailbox, options.resource_size, GL_RGBA,
- GL_UNSIGNED_BYTE, expected_bitmap.getPixels());
- gl->OrderingBarrierCHROMIUM();
+ UploadPixels(ri, src_mailbox, expected_bitmap.info(), expected_bitmap);
auto src_paint_image =
PaintImageBuilder::WithDefault()
@@ -1498,7 +1436,8 @@ TEST_F(OopPixelTest, DrawRectQueryMiddleOfDisplayList) {
options.post_scale = 2.f;
auto actual = Raster(display_item_list, options);
- ExpectEquals(actual, FILE_PATH_LITERAL("oop_draw_rect_query.png"));
+ ExpectEquals(actual, FILE_PATH_LITERAL("oop_draw_rect_query.png"),
+ FuzzyPixelOffByOneComparator(/*discard_alpha=*/false));
}
TEST_F(OopPixelTest, DrawRectColorSpace) {
@@ -2140,159 +2079,193 @@ TEST_F(OopPixelTest, WritePixels) {
SkImageInfo::MakeN32Premul(dest_size.width(), dest_size.height()),
expected_pixels.data(), dest_size.width() * sizeof(SkColor));
- ri->WritePixels(dest_mailbox, 0, 0, 0, expected.info().minRowBytes(),
- expected.info(), expected.getPixels());
- ri->OrderingBarrierCHROMIUM();
- EXPECT_EQ(ri->GetError(), static_cast<unsigned>(GL_NO_ERROR));
+ UploadPixels(ri, dest_mailbox, expected.info(), expected);
- gpu::gles2::GLES2Interface* gl = gles2_context_provider_->ContextGL();
- SkBitmap actual = ReadbackMailbox(gl, dest_mailbox, options);
+ SkBitmap actual = ReadbackMailbox(ri, dest_mailbox, options.resource_size);
gpu::SyncToken sync_token;
- gl->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
+ ri->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
sii->DestroySharedImage(sync_token, dest_mailbox);
ExpectEquals(actual, expected);
}
-namespace {
-GrBackendTexture MakeBackendTexture(gpu::gles2::GLES2Interface* gl,
- const gpu::Mailbox& mailbox,
- gfx::Size size,
- GLenum type) {
- GrGLTextureInfo tex_info = {
- GL_TEXTURE_2D, gl->CreateAndTexStorage2DSharedImageCHROMIUM(mailbox.name),
- type};
- return GrBackendTexture(size.width(), size.height(), GrMipMapped::kNo,
- tex_info);
+TEST_F(OopPixelTest, CopySubTexture) {
+ const gfx::Size size(16, 16);
+ auto* ri = raster_context_provider_->RasterInterface();
+ auto* sii = raster_context_provider_->SharedImageInterface();
+ const gfx::ColorSpace source_color_space = gfx::ColorSpace::CreateSRGB();
+ const gfx::ColorSpace dest_color_space =
+ gfx::ColorSpace::CreateDisplayP3D65();
+
+ // Create data to upload in sRGB (solid green).
+ SkBitmap upload_bitmap;
+ {
+ upload_bitmap.allocPixels(SkImageInfo::MakeN32Premul(
+ size.width(), size.height(), source_color_space.ToSkColorSpace()));
+ SkCanvas canvas(upload_bitmap, SkSurfaceProps{});
+ SkPaint paint;
+ paint.setColor(SkColors::kGreen);
+ canvas.drawRect(SkRect::MakeWH(size.width(), size.height()), paint);
+ }
+
+ // Create an sRGB SharedImage and upload to it.
+ gpu::Mailbox source_mailbox;
+ {
+ RasterOptions options(size);
+ options.target_color_params.color_space = source_color_space;
+ source_mailbox = CreateMailboxSharedImage(ri, sii, options,
+ viz::ResourceFormat::RGBA_8888);
+ ri->WaitSyncTokenCHROMIUM(sii->GenUnverifiedSyncToken().GetConstData());
+
+ ri->WritePixels(source_mailbox, 0, 0, GL_TEXTURE_2D,
+ upload_bitmap.rowBytes(), upload_bitmap.info(),
+ upload_bitmap.getPixels());
+ }
+
+ // Create a DisplayP3 SharedImage and copy to it.
+ gpu::Mailbox dest_mailbox;
+ {
+ RasterOptions options(size);
+ options.target_color_params.color_space = dest_color_space;
+ dest_mailbox = CreateMailboxSharedImage(ri, sii, options,
+ viz::ResourceFormat::RGBA_8888);
+ ri->WaitSyncTokenCHROMIUM(sii->GenUnverifiedSyncToken().GetConstData());
+
+ ri->CopySubTexture(source_mailbox, dest_mailbox, GL_TEXTURE_2D, 0, 0, 0, 0,
+ size.width(), size.height(),
+ /*unpack_flip_y=*/GL_FALSE,
+ /*unpack_premultiply_alpha=*/GL_FALSE);
+ }
+
+ // Read the data back as DisplayP3, from the Display P3 SharedImage.
+ SkBitmap readback_bitmap;
+ {
+ readback_bitmap.allocPixels(SkImageInfo::MakeN32Premul(
+ size.width(), size.height(), dest_color_space.ToSkColorSpace()));
+
+ ri->ReadbackImagePixels(dest_mailbox, readback_bitmap.info(),
+ readback_bitmap.rowBytes(), 0, 0,
+ readback_bitmap.getPixels());
+ }
+
+ // The pixel value should be unchanged, even though the source and dest are
+ // in different color spaces. No color conversion (which would change the
+ // pixel value) should have happened.
+ EXPECT_EQ(*upload_bitmap.getAddr32(0, 0), *readback_bitmap.getAddr32(0, 0));
}
-} // namespace
-TEST_F(OopPixelTest, ConvertYUVToRGB) {
+// The Android emulator does not support RED_8 or RG_88 texture formats.
+#if !BUILDFLAG(IS_ANDROID_EMULATOR)
+using OopYUVToRGBConfig = ::testing::tuple<gfx::ColorSpace, bool>;
+
+class OopYUVToRGBPixelTest
+ : public OopPixelTest,
+ public ::testing::WithParamInterface<OopYUVToRGBConfig> {
+ public:
+ bool TestColorSpaceConversion() const {
+ return ::testing::get<1>(GetParam());
+ }
+
+ gfx::ColorSpace DestinationColorSpace() const {
+ return ::testing::get<0>(GetParam());
+ }
+};
+
+TEST_P(OopYUVToRGBPixelTest, ConvertYUVToRGB) {
+ // The source color space for the YUV image. If color space conversion is
+ // disabled, or if `dest_color_space` is invalid, then this will be ignored.
+ const gfx::ColorSpace source_color_space(gfx::ColorSpace::PrimaryID::P3,
+ gfx::ColorSpace::TransferID::SRGB);
+
+ // The output SharedImage color space.
+ const gfx::ColorSpace dest_color_space = DestinationColorSpace();
+
RasterOptions options(gfx::Size(16, 16));
RasterOptions uv_options(gfx::Size(options.resource_size.width() / 2,
options.resource_size.height() / 2));
auto* ri = raster_context_provider_->RasterInterface();
auto* sii = raster_context_provider_->SharedImageInterface();
+
gpu::Mailbox dest_mailbox = CreateMailboxSharedImage(
- ri, sii, options, viz::ResourceFormat::RGBA_8888);
+ ri, sii, options, viz::ResourceFormat::RGBA_8888, dest_color_space);
+
+ constexpr viz::ResourceFormat format = viz::ResourceFormat::RED_8;
gpu::Mailbox yuv_mailboxes[3]{
- CreateMailboxSharedImage(ri, sii, options,
- viz::ResourceFormat::LUMINANCE_8),
- CreateMailboxSharedImage(ri, sii, uv_options,
- viz::ResourceFormat::LUMINANCE_8),
- CreateMailboxSharedImage(ri, sii, uv_options,
- viz::ResourceFormat::LUMINANCE_8)};
-
- size_t y_pixels_size = options.resource_size.GetArea();
- size_t uv_pixels_size = uv_options.resource_size.GetArea();
- auto y_pix = std::make_unique<uint8_t[]>(y_pixels_size);
- auto u_pix = std::make_unique<uint8_t[]>(uv_pixels_size);
- auto v_pix = std::make_unique<uint8_t[]>(uv_pixels_size);
-
- // Create a blue image
- memset(y_pix.get(), 0x1d, y_pixels_size);
- memset(u_pix.get(), 0xff, uv_pixels_size);
- memset(v_pix.get(), 0x6b, uv_pixels_size);
-
- // Upload initial yuv image data
- gpu::gles2::GLES2Interface* gl = gles2_context_provider_->ContextGL();
- UploadPixels(gl, yuv_mailboxes[0], options.resource_size, GL_LUMINANCE,
- GL_UNSIGNED_BYTE, y_pix.get());
- UploadPixels(gl, yuv_mailboxes[1], uv_options.resource_size, GL_LUMINANCE,
- GL_UNSIGNED_BYTE, u_pix.get());
- UploadPixels(gl, yuv_mailboxes[2], uv_options.resource_size, GL_LUMINANCE,
- GL_UNSIGNED_BYTE, v_pix.get());
- gl->OrderingBarrierCHROMIUM();
+ CreateMailboxSharedImage(ri, sii, options, format),
+ CreateMailboxSharedImage(ri, sii, uv_options, format),
+ CreateMailboxSharedImage(ri, sii, uv_options, format)};
+
+ SkImageInfo y_info = SkImageInfo::Make(
+ options.resource_size.width(), options.resource_size.height(),
+ kGray_8_SkColorType, kPremul_SkAlphaType,
+ options.target_color_params.color_space.ToSkColorSpace());
+
+ SkImageInfo uv_info = SkImageInfo::Make(
+ uv_options.resource_size.width(), uv_options.resource_size.height(),
+ kGray_8_SkColorType, kPremul_SkAlphaType,
+ uv_options.target_color_params.color_space.ToSkColorSpace());
+
+ // Create Y+U+V image planes for a solid blue image.
+ SkBitmap y_bitmap;
+ y_bitmap.allocPixels(y_info);
+ memset(y_bitmap.getPixels(), 0x1d, y_bitmap.computeByteSize());
+
+ SkBitmap u_bitmap;
+ u_bitmap.allocPixels(uv_info);
+ memset(u_bitmap.getPixels(), 0xff, u_bitmap.computeByteSize());
+
+ SkBitmap v_bitmap;
+ v_bitmap.allocPixels(uv_info);
+ memset(v_bitmap.getPixels(), 0x6b, v_bitmap.computeByteSize());
+
+ // Upload initial Y+U+V planes and convert to RGB.
+ UploadPixels(ri, yuv_mailboxes[0], y_info, y_bitmap);
+ UploadPixels(ri, yuv_mailboxes[1], uv_info, u_bitmap);
+ UploadPixels(ri, yuv_mailboxes[2], uv_info, v_bitmap);
ri->ConvertYUVAMailboxesToRGB(dest_mailbox, kJPEG_SkYUVColorSpace,
+ TestColorSpaceConversion()
+ ? source_color_space.ToSkColorSpace().get()
+ : nullptr,
SkYUVAInfo::PlaneConfig::kY_U_V,
SkYUVAInfo::Subsampling::k420, yuv_mailboxes);
ri->OrderingBarrierCHROMIUM();
- SkBitmap actual_bitmap = ReadbackMailbox(gl, dest_mailbox, options);
-
- // Create the expected result using SkImage::MakeFromYUVTextures
- GrBackendTexture backend_textures[3];
- backend_textures[0] = MakeBackendTexture(
- gl, yuv_mailboxes[0], options.resource_size, GL_LUMINANCE8_EXT);
- backend_textures[1] = MakeBackendTexture(
- gl, yuv_mailboxes[1], uv_options.resource_size, GL_LUMINANCE8_EXT);
- backend_textures[2] = MakeBackendTexture(
- gl, yuv_mailboxes[2], uv_options.resource_size, GL_LUMINANCE8_EXT);
-
- SkYUVAInfo yuva_info(
- {options.resource_size.width(), options.resource_size.height()},
- SkYUVAInfo::PlaneConfig::kY_U_V, SkYUVAInfo::Subsampling::k420,
- kJPEG_Full_SkYUVColorSpace);
- GrYUVABackendTextures yuva_textures(yuva_info, backend_textures,
- kTopLeft_GrSurfaceOrigin);
-
- auto expected_image = SkImage::MakeFromYUVATextures(
- gles2_context_provider_->GrContext(), yuva_textures);
-
- SkBitmap expected_bitmap;
- expected_bitmap.allocN32Pixels(options.resource_size.width(),
- options.resource_size.height());
- expected_image->readPixels(expected_bitmap.pixmap(), 0, 0);
- ExpectEquals(actual_bitmap, expected_bitmap);
-
- for (auto& backend : backend_textures) {
- GrGLTextureInfo info;
- if (backend.getGLTextureInfo(&info))
- gl->DeleteTextures(1, &info.fID);
- }
+ SkBitmap actual_bitmap =
+ ReadbackMailbox(ri, dest_mailbox, options.resource_size,
+ dest_color_space.ToSkColorSpace());
+
+ SkColor expected_color =
+ (TestColorSpaceConversion() && dest_color_space.IsValid())
+ ? SkColorSetARGB(255, 61, 29, 252)
+ : SkColorSetARGB(255, 0, 0, 254);
+ SkBitmap expected_bitmap = MakeSolidColorBitmap(
+ options.resource_size, SkColor4f::FromColor(expected_color));
+
+ // Allow slight rounding error on all pixels.
+ FuzzyPixelComparator comparator(
+ /*discard_alpha=*/false,
+ /*error_pixels_percentage_limit=*/100.0f,
+ /*small_error_pixels_percentage_limit=*/0.0f,
+ /*avg_abs_error_limit=*/2.f,
+ /*max_abs_error_limit=*/2.f,
+ /*small_error_threshold=*/0);
+ ExpectEquals(actual_bitmap, expected_bitmap, comparator);
gpu::SyncToken sync_token;
- gl->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
sii->DestroySharedImage(sync_token, dest_mailbox);
sii->DestroySharedImage(sync_token, yuv_mailboxes[0]);
sii->DestroySharedImage(sync_token, yuv_mailboxes[1]);
sii->DestroySharedImage(sync_token, yuv_mailboxes[2]);
}
-TEST_F(OopPixelTest, ReadbackImagePixels) {
- RasterOptions options(gfx::Size(16, 16));
- SkImageInfo dest_info = SkImageInfo::MakeN32Premul(
- options.resource_size.width(), options.resource_size.height(),
- gfx::ColorSpace::CreateSRGB().ToSkColorSpace());
-
- SkBitmap expected_bitmap;
- expected_bitmap.allocPixels(dest_info);
-
- SkCanvas canvas(expected_bitmap, SkSurfaceProps{});
- canvas.drawColor(SkColors::kMagenta);
- SkPaint green;
- green.setColor(SkColors::kGreen);
- canvas.drawRect(SkRect::MakeXYWH(1, 2, 3, 4), green);
-
- auto* ri = raster_context_provider_->RasterInterface();
- auto* sii = raster_context_provider_->SharedImageInterface();
- gpu::Mailbox mailbox = CreateMailboxSharedImage(
- ri, sii, options, viz::ResourceFormat::RGBA_8888);
- ri->OrderingBarrierCHROMIUM();
-
- gpu::gles2::GLES2Interface* gl = gles2_context_provider_->ContextGL();
- UploadPixels(gl, mailbox, options.resource_size, GL_RGBA, GL_UNSIGNED_BYTE,
- expected_bitmap.getPixels());
- gl->OrderingBarrierCHROMIUM();
-
- SkBitmap actual_bitmap;
- actual_bitmap.allocPixels(dest_info);
-
- ri->ReadbackImagePixels(mailbox, dest_info, dest_info.minRowBytes(), 0, 0,
- actual_bitmap.getPixels());
- EXPECT_EQ(ri->GetError(), static_cast<unsigned>(GL_NO_ERROR));
- ri->OrderingBarrierCHROMIUM();
-
- ExpectEquals(actual_bitmap, expected_bitmap);
-
- gpu::SyncToken sync_token;
- gl->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
- sii->DestroySharedImage(sync_token, mailbox);
-}
+INSTANTIATE_TEST_SUITE_P(
+ P,
+ OopYUVToRGBPixelTest,
+ ::testing::Combine(
+ ::testing::Values(gfx::ColorSpace(gfx::ColorSpace::PrimaryID::BT2020,
+ gfx::ColorSpace::TransferID::SRGB),
+ gfx::ColorSpace()),
+ ::testing::Bool()));
-// A workaround on Android that forces the use of GLES 2.0 instead of 3.0
-// prevents the use of the GL_RG textures required for NV12 format. This
-// test will be reactiviated on Android once the workaround is removed.
-#if !BUILDFLAG(IS_ANDROID)
TEST_F(OopPixelTest, ConvertNV12ToRGB) {
RasterOptions options(gfx::Size(16, 16));
RasterOptions uv_options(gfx::Size(options.resource_size.width() / 2,
@@ -2303,70 +2276,57 @@ TEST_F(OopPixelTest, ConvertNV12ToRGB) {
gpu::Mailbox dest_mailbox = CreateMailboxSharedImage(
ri, sii, options, viz::ResourceFormat::RGBA_8888);
gpu::Mailbox y_uv_mailboxes[2]{
- CreateMailboxSharedImage(ri, sii, options,
- viz::ResourceFormat::LUMINANCE_8),
+ CreateMailboxSharedImage(ri, sii, options, viz::ResourceFormat::RED_8),
CreateMailboxSharedImage(ri, sii, uv_options, viz::ResourceFormat::RG_88),
};
- size_t y_pixels_size = options.resource_size.GetArea();
- size_t uv_pixels_size = uv_options.resource_size.GetArea() * 2;
- auto y_pix = std::make_unique<uint8_t[]>(y_pixels_size);
- auto uv_pix = std::make_unique<uint8_t[]>(uv_pixels_size);
-
- memset(y_pix.get(), 0x1d, y_pixels_size);
- for (size_t i = 0; i < uv_pixels_size; i += 2) {
+ SkImageInfo y_info = SkImageInfo::Make(
+ options.resource_size.width(), options.resource_size.height(),
+ kGray_8_SkColorType, kPremul_SkAlphaType,
+ options.target_color_params.color_space.ToSkColorSpace());
+
+ SkImageInfo uv_info = SkImageInfo::Make(
+ uv_options.resource_size.width(), uv_options.resource_size.height(),
+ kR8G8_unorm_SkColorType, kPremul_SkAlphaType,
+ uv_options.target_color_params.color_space.ToSkColorSpace());
+
+ // Create Y+UV image planes for a solid blue image.
+ SkBitmap y_bitmap;
+ y_bitmap.allocPixels(y_info);
+ memset(y_bitmap.getPixels(), 0x1d, y_bitmap.computeByteSize());
+
+ SkBitmap uv_bitmap;
+ uv_bitmap.allocPixels(uv_info);
+ uint8_t* uv_pix = static_cast<uint8_t*>(uv_bitmap.getPixels());
+ for (size_t i = 0; i < uv_bitmap.computeByteSize(); i += 2) {
uv_pix[i] = 0xff;
uv_pix[i + 1] = 0x6d;
}
- gpu::gles2::GLES2Interface* gl = gles2_context_provider_->ContextGL();
- UploadPixels(gl, y_uv_mailboxes[0], options.resource_size, GL_LUMINANCE,
- GL_UNSIGNED_BYTE, y_pix.get());
- UploadPixels(gl, y_uv_mailboxes[1], uv_options.resource_size, GL_RG,
- GL_UNSIGNED_BYTE, uv_pix.get());
- gl->OrderingBarrierCHROMIUM();
+ // Upload initial Y+UV planes and convert to RGB.
+ UploadPixels(ri, y_uv_mailboxes[0], y_info, y_bitmap);
+ UploadPixels(ri, y_uv_mailboxes[1], uv_info, uv_bitmap);
ri->ConvertYUVAMailboxesToRGB(dest_mailbox, kJPEG_SkYUVColorSpace,
+ SkColorSpace::MakeSRGB().get(),
SkYUVAInfo::PlaneConfig::kY_UV,
SkYUVAInfo::Subsampling::k420, y_uv_mailboxes);
ri->OrderingBarrierCHROMIUM();
- SkBitmap actual_bitmap = ReadbackMailbox(gl, dest_mailbox, options);
-
- // Create the expected result using SkImage::MakeFromYUVTextures
- GrBackendTexture backend_textures[2];
- backend_textures[0] = MakeBackendTexture(
- gl, y_uv_mailboxes[0], options.resource_size, GL_LUMINANCE8_EXT);
- backend_textures[1] = MakeBackendTexture(gl, y_uv_mailboxes[1],
- uv_options.resource_size, GL_RG8);
-
- SkYUVAInfo yuva_info(
- {options.resource_size.width(), options.resource_size.height()},
- SkYUVAInfo::PlaneConfig::kY_UV, SkYUVAInfo::Subsampling::k420,
- kJPEG_Full_SkYUVColorSpace);
- GrYUVABackendTextures yuva_textures(yuva_info, backend_textures,
- kTopLeft_GrSurfaceOrigin);
- auto expected_image = SkImage::MakeFromYUVATextures(
- gles2_context_provider_->GrContext(), yuva_textures);
+ SkBitmap actual_bitmap =
+ ReadbackMailbox(ri, dest_mailbox, options.resource_size);
- SkBitmap expected_bitmap;
- expected_bitmap.allocN32Pixels(options.resource_size.width(),
- options.resource_size.height());
- expected_image->readPixels(expected_bitmap.pixmap(), 0, 0);
- ExpectEquals(actual_bitmap, expected_bitmap);
+ SkBitmap expected_bitmap = MakeSolidColorBitmap(
+ options.resource_size,
+ SkColor4f::FromColor(SkColorSetARGB(255, 2, 0, 254)));
- for (auto& backend : backend_textures) {
- GrGLTextureInfo info;
- if (backend.getGLTextureInfo(&info))
- gl->DeleteTextures(1, &info.fID);
- }
+ ExpectEquals(actual_bitmap, expected_bitmap);
gpu::SyncToken sync_token;
- gl->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
sii->DestroySharedImage(sync_token, dest_mailbox);
sii->DestroySharedImage(sync_token, y_uv_mailboxes[0]);
sii->DestroySharedImage(sync_token, y_uv_mailboxes[1]);
}
-#endif // !BUILDFLAG(IS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID_EMULATOR)
class OopPathPixelTest : public OopPixelTest,
public ::testing::WithParamInterface<bool> {
diff --git a/chromium/cc/paint/paint_cache.cc b/chromium/cc/paint/paint_cache.cc
index 8da1afa8452..90a32da1328 100644
--- a/chromium/cc/paint/paint_cache.cc
+++ b/chromium/cc/paint/paint_cache.cc
@@ -90,15 +90,6 @@ bool ClientPaintCache::PurgeAll() {
ServicePaintCache::ServicePaintCache() = default;
ServicePaintCache::~ServicePaintCache() = default;
-void ServicePaintCache::PutTextBlob(PaintCacheId id, sk_sp<SkTextBlob> blob) {
- cached_blobs_.emplace(id, std::move(blob));
-}
-
-sk_sp<SkTextBlob> ServicePaintCache::GetTextBlob(PaintCacheId id) const {
- auto it = cached_blobs_.find(id);
- return it == cached_blobs_.end() ? nullptr : it->second;
-}
-
void ServicePaintCache::PutPath(PaintCacheId id, SkPath path) {
cached_paths_.emplace(id, std::move(path));
}
@@ -115,9 +106,6 @@ void ServicePaintCache::Purge(PaintCacheDataType type,
size_t n,
const volatile PaintCacheId* ids) {
switch (type) {
- case PaintCacheDataType::kTextBlob:
- EraseFromMap(&cached_blobs_, n, ids);
- return;
case PaintCacheDataType::kPath:
EraseFromMap(&cached_paths_, n, ids);
return;
@@ -127,7 +115,6 @@ void ServicePaintCache::Purge(PaintCacheDataType type,
}
void ServicePaintCache::PurgeAll() {
- cached_blobs_.clear();
cached_paths_.clear();
}
diff --git a/chromium/cc/paint/paint_cache.h b/chromium/cc/paint/paint_cache.h
index e0cd5384ebf..3a0a889fc9a 100644
--- a/chromium/cc/paint/paint_cache.h
+++ b/chromium/cc/paint/paint_cache.h
@@ -38,7 +38,7 @@ namespace cc {
using PaintCacheId = uint32_t;
using PaintCacheIds = std::vector<PaintCacheId>;
-enum class PaintCacheDataType : uint32_t { kTextBlob, kPath, kLast = kPath };
+enum class PaintCacheDataType : uint32_t { kPath, kLast = kPath };
enum class PaintCacheEntryState : uint32_t {
kEmpty,
kCached,
@@ -107,13 +107,6 @@ class CC_PAINT_EXPORT ServicePaintCache {
ServicePaintCache();
~ServicePaintCache();
- // Stores the |blob| received from the client in the cache.
- void PutTextBlob(PaintCacheId id, sk_sp<SkTextBlob> blob);
-
- // Retrieves an entry for |id| stored in the cache. Or nullptr if the entry
- // is not found.
- sk_sp<SkTextBlob> GetTextBlob(PaintCacheId id) const;
-
// Stores |path| received from the client in the cache.
void PutPath(PaintCacheId, SkPath path);
@@ -125,11 +118,9 @@ class CC_PAINT_EXPORT ServicePaintCache {
size_t n,
const volatile PaintCacheId* ids);
void PurgeAll();
- bool empty() const { return cached_blobs_.empty() && cached_paths_.empty(); }
+ bool empty() const { return cached_paths_.empty(); }
private:
- using BlobMap = std::map<PaintCacheId, sk_sp<SkTextBlob>>;
- BlobMap cached_blobs_;
using PathMap = std::map<PaintCacheId, SkPath>;
PathMap cached_paths_;
};
diff --git a/chromium/cc/paint/paint_cache_unittest.cc b/chromium/cc/paint/paint_cache_unittest.cc
index 60ab43062ec..eca018ca823 100644
--- a/chromium/cc/paint/paint_cache_unittest.cc
+++ b/chromium/cc/paint/paint_cache_unittest.cc
@@ -11,18 +11,6 @@ namespace {
constexpr size_t kDefaultBudget = 1024u;
-sk_sp<SkTextBlob> CreateBlob() {
- SkFont font;
- font.setTypeface(SkTypeface::MakeDefault());
-
- SkTextBlobBuilder builder;
- int glyph_count = 5;
- const auto& run = builder.allocRun(font, glyph_count, 1.2f, 2.3f);
- // allocRun() allocates only the glyph buffer.
- std::fill(run.glyphs, run.glyphs + glyph_count, 0);
- return builder.make();
-}
-
SkPath CreatePath() {
SkPath path;
path.addCircle(2, 2, 5);
@@ -91,17 +79,6 @@ TEST_P(PaintCacheTest, CommitPendingEntries) {
TEST_P(PaintCacheTest, ServiceBasic) {
ServicePaintCache service_cache;
switch (GetType()) {
- case PaintCacheDataType::kTextBlob: {
- auto blob = CreateBlob();
- auto id = blob->uniqueID();
- EXPECT_EQ(nullptr, service_cache.GetTextBlob(id));
- service_cache.PutTextBlob(id, blob);
- EXPECT_EQ(blob, service_cache.GetTextBlob(id));
- service_cache.Purge(GetType(), 1, &id);
- EXPECT_EQ(nullptr, service_cache.GetTextBlob(id));
-
- service_cache.PutTextBlob(id, blob);
- } break;
case PaintCacheDataType::kPath: {
auto path = CreatePath();
auto id = path.getGenerationID();
@@ -125,8 +102,7 @@ TEST_P(PaintCacheTest, ServiceBasic) {
INSTANTIATE_TEST_SUITE_P(
P,
PaintCacheTest,
- ::testing::Range(static_cast<uint32_t>(0),
- static_cast<uint32_t>(PaintCacheDataType::kLast)));
+ ::testing::Values(static_cast<uint32_t>(PaintCacheDataType::kPath)));
} // namespace
} // namespace cc
diff --git a/chromium/cc/paint/paint_canvas.h b/chromium/cc/paint/paint_canvas.h
index bd32f3d968b..3815f678501 100644
--- a/chromium/cc/paint/paint_canvas.h
+++ b/chromium/cc/paint/paint_canvas.h
@@ -134,11 +134,11 @@ class CC_PAINT_EXPORT PaintCanvas {
virtual bool getLocalClipBounds(SkRect* bounds) const = 0;
virtual SkIRect getDeviceClipBounds() const = 0;
virtual bool getDeviceClipBounds(SkIRect* bounds) const = 0;
- virtual void drawColor(SkColor color, SkBlendMode mode) = 0;
- void drawColor(SkColor color) { drawColor(color, SkBlendMode::kSrcOver); }
+ virtual void drawColor(SkColor4f color, SkBlendMode mode) = 0;
+ void drawColor(SkColor4f color) { drawColor(color, SkBlendMode::kSrcOver); }
// TODO(enne): This is a synonym for drawColor with kSrc. Remove it.
- virtual void clear(SkColor color) = 0;
+ virtual void clear(SkColor4f color) = 0;
virtual void drawLine(SkScalar x0,
SkScalar y0,
diff --git a/chromium/cc/paint/paint_filter.cc b/chromium/cc/paint/paint_filter.cc
index 705aa95dabe..8f8c217bf64 100644
--- a/chromium/cc/paint/paint_filter.cc
+++ b/chromium/cc/paint/paint_filter.cc
@@ -538,7 +538,7 @@ DropShadowPaintFilter::DropShadowPaintFilter(SkScalar dx,
SkScalar dy,
SkScalar sigma_x,
SkScalar sigma_y,
- SkColor color,
+ SkColor4f color,
ShadowMode shadow_mode,
sk_sp<PaintFilter> input,
const CropRect* crop_rect)
@@ -551,13 +551,15 @@ DropShadowPaintFilter::DropShadowPaintFilter(SkScalar dx,
shadow_mode_(shadow_mode),
input_(std::move(input)) {
if (shadow_mode == ShadowMode::kDrawShadowOnly) {
- cached_sk_filter_ =
- SkImageFilters::DropShadowOnly(dx_, dy_, sigma_x_, sigma_y_, color_,
- GetSkFilter(input_.get()), crop_rect);
+ // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
+ cached_sk_filter_ = SkImageFilters::DropShadowOnly(
+ dx_, dy_, sigma_x_, sigma_y_, color_.toSkColor(),
+ GetSkFilter(input_.get()), crop_rect);
} else {
- cached_sk_filter_ =
- SkImageFilters::DropShadow(dx_, dy_, sigma_x_, sigma_y_, color_,
- GetSkFilter(input_.get()), crop_rect);
+ // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
+ cached_sk_filter_ = SkImageFilters::DropShadow(
+ dx_, dy_, sigma_x_, sigma_y_, color_.toSkColor(),
+ GetSkFilter(input_.get()), crop_rect);
}
}
@@ -1022,12 +1024,11 @@ sk_sp<RecordPaintFilter> RecordPaintFilter::CreateScaledPaintRecord(
// after PaintShader::CreateScaledPaintRecord.
SkRect scaled_record_bounds =
PaintRecord::GetFixedScaleBounds(ctm, record_bounds_, max_texture_size);
- if (scaled_record_bounds.isEmpty())
- return nullptr;
-
gfx::SizeF raster_scale = {
scaled_record_bounds.width() / record_bounds_.width(),
scaled_record_bounds.height() / record_bounds_.height()};
+ if (raster_scale.IsEmpty())
+ return nullptr;
return sk_make_sp<RecordPaintFilter>(record_, scaled_record_bounds,
raster_scale,
@@ -1291,9 +1292,10 @@ ShaderPaintFilter::ShaderPaintFilter(sk_sp<PaintShader> shader,
if (alpha < 255) {
// The blend effectively produces (shader * alpha), the rgb of the secondary
// color are ignored.
- SkColor color = SkColorSetARGB(alpha, 255, 255, 255);
+ SkColor4f color{1.0f, 1.0f, 1.0f, alpha / 255.0f};
+ // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
sk_shader = SkShaders::Blend(SkBlendMode::kDstIn, std::move(sk_shader),
- SkShaders::Color(color));
+ SkShaders::Color(color.toSkColor()));
}
cached_sk_filter_ =
@@ -1320,7 +1322,7 @@ sk_sp<PaintFilter> ShaderPaintFilter::SnapshotWithImagesInternal(
orig_flags.setDither(dither_ == SkImageFilters::Dither::kYes);
ScopedRasterFlags raster_flags(&orig_flags, image_provider, SkMatrix::I(), 0,
- 255u);
+ 1.0f);
const PaintFlags* snapshot = raster_flags.flags();
if (snapshot) {
// Ref the updated paint shader so that it can outlive ScopedRasterFlags
@@ -1377,7 +1379,7 @@ bool MatrixPaintFilter::operator==(const MatrixPaintFilter& other) const {
LightingDistantPaintFilter::LightingDistantPaintFilter(
LightingType lighting_type,
const SkPoint3& direction,
- SkColor light_color,
+ SkColor4f light_color,
SkScalar surface_scale,
SkScalar kconstant,
SkScalar shininess,
@@ -1393,14 +1395,16 @@ LightingDistantPaintFilter::LightingDistantPaintFilter(
input_(std::move(input)) {
switch (lighting_type_) {
case LightingType::kDiffuse:
+ // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
cached_sk_filter_ = SkImageFilters::DistantLitDiffuse(
- direction_, light_color_, surface_scale_, kconstant_,
+ direction_, light_color_.toSkColor(), surface_scale_, kconstant_,
GetSkFilter(input_.get()), crop_rect);
break;
case LightingType::kSpecular:
+ // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
cached_sk_filter_ = SkImageFilters::DistantLitSpecular(
- direction_, light_color_, surface_scale_, kconstant_, shininess_,
- GetSkFilter(input_.get()), crop_rect);
+ direction_, light_color_.toSkColor(), surface_scale_, kconstant_,
+ shininess_, GetSkFilter(input_.get()), crop_rect);
break;
}
}
@@ -1436,7 +1440,7 @@ bool LightingDistantPaintFilter::operator==(
LightingPointPaintFilter::LightingPointPaintFilter(LightingType lighting_type,
const SkPoint3& location,
- SkColor light_color,
+ SkColor4f light_color,
SkScalar surface_scale,
SkScalar kconstant,
SkScalar shininess,
@@ -1452,14 +1456,16 @@ LightingPointPaintFilter::LightingPointPaintFilter(LightingType lighting_type,
input_(std::move(input)) {
switch (lighting_type_) {
case LightingType::kDiffuse:
+ // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
cached_sk_filter_ = SkImageFilters::PointLitDiffuse(
- location_, light_color_, surface_scale_, kconstant_,
+ location_, light_color_.toSkColor(), surface_scale_, kconstant_,
GetSkFilter(input_.get()), crop_rect);
break;
case LightingType::kSpecular:
+ // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
cached_sk_filter_ = SkImageFilters::PointLitSpecular(
- location_, light_color_, surface_scale_, kconstant_, shininess_,
- GetSkFilter(input_.get()), crop_rect);
+ location_, light_color_.toSkColor(), surface_scale_, kconstant_,
+ shininess_, GetSkFilter(input_.get()), crop_rect);
break;
}
}
@@ -1498,7 +1504,7 @@ LightingSpotPaintFilter::LightingSpotPaintFilter(LightingType lighting_type,
const SkPoint3& target,
SkScalar specular_exponent,
SkScalar cutoff_angle,
- SkColor light_color,
+ SkColor4f light_color,
SkScalar surface_scale,
SkScalar kconstant,
SkScalar shininess,
@@ -1517,15 +1523,18 @@ LightingSpotPaintFilter::LightingSpotPaintFilter(LightingType lighting_type,
input_(std::move(input)) {
switch (lighting_type_) {
case LightingType::kDiffuse:
+ // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
cached_sk_filter_ = SkImageFilters::SpotLitDiffuse(
- location_, target_, specular_exponent_, cutoff_angle_, light_color_,
- surface_scale_, kconstant_, GetSkFilter(input_.get()), crop_rect);
+ location_, target_, specular_exponent_, cutoff_angle_,
+ light_color_.toSkColor(), surface_scale_, kconstant_,
+ GetSkFilter(input_.get()), crop_rect);
break;
case LightingType::kSpecular:
+ // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
cached_sk_filter_ = SkImageFilters::SpotLitSpecular(
- location_, target_, specular_exponent_, cutoff_angle_, light_color_,
- surface_scale_, kconstant_, shininess_, GetSkFilter(input_.get()),
- crop_rect);
+ location_, target_, specular_exponent_, cutoff_angle_,
+ light_color_.toSkColor(), surface_scale_, kconstant_, shininess_,
+ GetSkFilter(input_.get()), crop_rect);
break;
}
}
diff --git a/chromium/cc/paint/paint_filter.h b/chromium/cc/paint/paint_filter.h
index 93a456dff66..7cd1a3d5c23 100644
--- a/chromium/cc/paint/paint_filter.h
+++ b/chromium/cc/paint/paint_filter.h
@@ -20,7 +20,6 @@
#include "third_party/skia/include/effects/SkImageFilters.h"
namespace viz {
-class GLRenderer;
class SkiaRenderer;
class SoftwareRenderer;
} // namespace viz
@@ -146,7 +145,6 @@ class CC_PAINT_EXPORT PaintFilter : public SkRefCnt {
// For cached skia filter access in SkPaint conversions. Mostly used during
// raster.
friend class PaintFlags;
- friend class viz::GLRenderer;
friend class viz::SkiaRenderer;
friend class viz::SoftwareRenderer;
@@ -222,7 +220,7 @@ class CC_PAINT_EXPORT DropShadowPaintFilter final : public PaintFilter {
SkScalar dy,
SkScalar sigma_x,
SkScalar sigma_y,
- SkColor color,
+ SkColor4f color,
ShadowMode shadow_mode,
sk_sp<PaintFilter> input,
const CropRect* crop_rect = nullptr);
@@ -232,7 +230,7 @@ class CC_PAINT_EXPORT DropShadowPaintFilter final : public PaintFilter {
SkScalar dy() const { return dy_; }
SkScalar sigma_x() const { return sigma_x_; }
SkScalar sigma_y() const { return sigma_y_; }
- SkColor color() const { return color_; }
+ SkColor4f color() const { return color_; }
ShadowMode shadow_mode() const { return shadow_mode_; }
const sk_sp<PaintFilter>& input() const { return input_; }
@@ -248,7 +246,7 @@ class CC_PAINT_EXPORT DropShadowPaintFilter final : public PaintFilter {
SkScalar dy_;
SkScalar sigma_x_;
SkScalar sigma_y_;
- SkColor color_;
+ SkColor4f color_;
ShadowMode shadow_mode_;
sk_sp<PaintFilter> input_;
};
@@ -756,7 +754,7 @@ class CC_PAINT_EXPORT LightingDistantPaintFilter final : public PaintFilter {
// For specular lighting type only, shininess denotes the specular exponent.
LightingDistantPaintFilter(LightingType lighting_type,
const SkPoint3& direction,
- SkColor light_color,
+ SkColor4f light_color,
SkScalar surface_scale,
SkScalar kconstant,
SkScalar shininess,
@@ -766,7 +764,7 @@ class CC_PAINT_EXPORT LightingDistantPaintFilter final : public PaintFilter {
LightingType lighting_type() const { return lighting_type_; }
const SkPoint3& direction() const { return direction_; }
- SkColor light_color() const { return light_color_; }
+ SkColor4f light_color() const { return light_color_; }
SkScalar surface_scale() const { return surface_scale_; }
SkScalar kconstant() const { return kconstant_; }
SkScalar shininess() const { return shininess_; }
@@ -782,7 +780,7 @@ class CC_PAINT_EXPORT LightingDistantPaintFilter final : public PaintFilter {
private:
LightingType lighting_type_;
SkPoint3 direction_;
- SkColor light_color_;
+ SkColor4f light_color_;
SkScalar surface_scale_;
SkScalar kconstant_;
SkScalar shininess_;
@@ -797,7 +795,7 @@ class CC_PAINT_EXPORT LightingPointPaintFilter final : public PaintFilter {
// For specular lighting type only, shininess denotes the specular exponent.
LightingPointPaintFilter(LightingType lighting_type,
const SkPoint3& location,
- SkColor light_color,
+ SkColor4f light_color,
SkScalar surface_scale,
SkScalar kconstant,
SkScalar shininess,
@@ -807,7 +805,7 @@ class CC_PAINT_EXPORT LightingPointPaintFilter final : public PaintFilter {
LightingType lighting_type() const { return lighting_type_; }
const SkPoint3& location() const { return location_; }
- SkColor light_color() const { return light_color_; }
+ SkColor4f light_color() const { return light_color_; }
SkScalar surface_scale() const { return surface_scale_; }
SkScalar kconstant() const { return kconstant_; }
SkScalar shininess() const { return shininess_; }
@@ -823,7 +821,7 @@ class CC_PAINT_EXPORT LightingPointPaintFilter final : public PaintFilter {
private:
LightingType lighting_type_;
SkPoint3 location_;
- SkColor light_color_;
+ SkColor4f light_color_;
SkScalar surface_scale_;
SkScalar kconstant_;
SkScalar shininess_;
@@ -841,7 +839,7 @@ class CC_PAINT_EXPORT LightingSpotPaintFilter final : public PaintFilter {
const SkPoint3& target,
SkScalar specular_exponent,
SkScalar cutoff_angle,
- SkColor light_color,
+ SkColor4f light_color,
SkScalar surface_scale,
SkScalar kconstant,
SkScalar shininess,
@@ -854,7 +852,7 @@ class CC_PAINT_EXPORT LightingSpotPaintFilter final : public PaintFilter {
const SkPoint3& target() const { return target_; }
SkScalar specular_exponent() const { return specular_exponent_; }
SkScalar cutoff_angle() const { return cutoff_angle_; }
- SkColor light_color() const { return light_color_; }
+ SkColor4f light_color() const { return light_color_; }
SkScalar surface_scale() const { return surface_scale_; }
SkScalar kconstant() const { return kconstant_; }
SkScalar shininess() const { return shininess_; }
@@ -873,7 +871,7 @@ class CC_PAINT_EXPORT LightingSpotPaintFilter final : public PaintFilter {
SkPoint3 target_;
SkScalar specular_exponent_;
SkScalar cutoff_angle_;
- SkColor light_color_;
+ SkColor4f light_color_;
SkScalar surface_scale_;
SkScalar kconstant_;
SkScalar shininess_;
diff --git a/chromium/cc/paint/paint_filter_unittest.cc b/chromium/cc/paint/paint_filter_unittest.cc
index a25d3fd9ba5..a075980d2d8 100644
--- a/chromium/cc/paint/paint_filter_unittest.cc
+++ b/chromium/cc/paint/paint_filter_unittest.cc
@@ -59,7 +59,7 @@ sk_sp<PaintFilter> CreateTestFilter(PaintFilter::Type filter_type,
record_filter, &crop_rect);
case PaintFilter::Type::kDropShadow:
return sk_make_sp<DropShadowPaintFilter>(
- 0.1, 0.2f, 0.3f, 0.4f, SK_ColorWHITE,
+ 0.1, 0.2f, 0.3f, 0.4f, SkColors::kWhite,
DropShadowPaintFilter::ShadowMode::kDrawShadowOnly, image_filter,
&crop_rect);
case PaintFilter::Type::kMagnifier:
@@ -124,15 +124,15 @@ sk_sp<PaintFilter> CreateTestFilter(PaintFilter::Type filter_type,
case PaintFilter::Type::kLightingDistant:
return sk_make_sp<LightingDistantPaintFilter>(
PaintFilter::LightingType::kDiffuse, SkPoint3::Make(0.1f, 0.2f, 0.3f),
- SK_ColorWHITE, 0.1f, 0.2f, 0.3f, image_filter, &crop_rect);
+ SkColors::kWhite, 0.1f, 0.2f, 0.3f, image_filter, &crop_rect);
case PaintFilter::Type::kLightingPoint:
return sk_make_sp<LightingPointPaintFilter>(
PaintFilter::LightingType::kDiffuse, SkPoint3::Make(0.1f, 0.2f, 0.3f),
- SK_ColorWHITE, 0.1f, 0.2f, 0.3f, record_filter, &crop_rect);
+ SkColors::kWhite, 0.1f, 0.2f, 0.3f, record_filter, &crop_rect);
case PaintFilter::Type::kLightingSpot:
return sk_make_sp<LightingSpotPaintFilter>(
PaintFilter::LightingType::kDiffuse, SkPoint3::Make(0.1f, 0.2f, 0.3f),
- SkPoint3::Make(0.4f, 0.5f, 0.6f), 0.1f, 0.2f, SK_ColorWHITE, 0.4f,
+ SkPoint3::Make(0.4f, 0.5f, 0.6f), 0.1f, 0.2f, SkColors::kWhite, 0.4f,
0.5f, 0.6f, image_filter, &crop_rect);
case PaintFilter::Type::kStretch:
return sk_make_sp<StretchPaintFilter>(0.1f, 0.2f, 100.f, 200.f,
diff --git a/chromium/cc/paint/paint_flags.h b/chromium/cc/paint/paint_flags.h
index 537c13f9b2c..ba137d0fac8 100644
--- a/chromium/cc/paint/paint_flags.h
+++ b/chromium/cc/paint/paint_flags.h
@@ -51,9 +51,14 @@ class CC_PAINT_EXPORT PaintFlags {
ALWAYS_INLINE uint8_t getAlpha() const {
return SkColorGetA(color_.toSkColor());
}
+ ALWAYS_INLINE float getAlphaf() const { return color_.fA; }
ALWAYS_INLINE void setAlpha(uint8_t a) {
color_ = SkColor4f::FromColor(SkColorSetA(color_.toSkColor(), a));
}
+ template <class F, class = std::enable_if_t<std::is_same_v<F, float>>>
+ ALWAYS_INLINE void setAlphaf(F a) {
+ color_.fA = a;
+ }
ALWAYS_INLINE void setBlendMode(SkBlendMode mode) {
blend_mode_ = static_cast<uint32_t>(mode);
}
@@ -73,7 +78,7 @@ class CC_PAINT_EXPORT PaintFlags {
kLast = kHigh,
};
ALWAYS_INLINE void setFilterQuality(FilterQuality quality) {
- bitfields_.filter_quality_ = static_cast<int>(quality);
+ bitfields_.filter_quality_ = static_cast<uint32_t>(quality);
}
ALWAYS_INLINE FilterQuality getFilterQuality() const {
return static_cast<FilterQuality>(bitfields_.filter_quality_);
diff --git a/chromium/cc/paint/paint_image.cc b/chromium/cc/paint/paint_image.cc
index ed3a8f51214..ed04d6b6c24 100644
--- a/chromium/cc/paint/paint_image.cc
+++ b/chromium/cc/paint/paint_image.cc
@@ -71,6 +71,8 @@ bool PaintImage::operator==(const PaintImage& other) const {
return false;
if (paint_worklet_input_ != other.paint_worklet_input_)
return false;
+ // Do not check may_be_lcp_candidate_ as it should not affect any rendering
+ // operation, only metrics collection.
return true;
}
@@ -230,7 +232,7 @@ bool PaintImage::DecodeYuv(const SkYUVAPixmaps& pixmaps,
DCHECK(paint_image_generator_);
const uint32_t lazy_pixel_ref = stable_id();
return paint_image_generator_->GetYUVAPlanes(pixmaps, frame_index,
- lazy_pixel_ref);
+ lazy_pixel_ref, client_id);
}
bool PaintImage::DecodeFromGenerator(void* memory,
@@ -397,6 +399,7 @@ std::string PaintImage::ToString() const {
<< " animation_type_: " << static_cast<int>(animation_type_)
<< " completion_state_: " << static_cast<int>(completion_state_)
<< " is_multipart_: " << is_multipart_
+ << " may_be_lcp_candidate_: " << may_be_lcp_candidate_
<< " is YUV: " << IsYuv(SkYUVAPixmapInfo::SupportedDataTypes::All());
return str.str();
}
diff --git a/chromium/cc/paint/paint_image.h b/chromium/cc/paint/paint_image.h
index 32cbb7fdaeb..859f4487dc8 100644
--- a/chromium/cc/paint/paint_image.h
+++ b/chromium/cc/paint/paint_image.h
@@ -264,6 +264,7 @@ class CC_PAINT_EXPORT PaintImage {
CompletionState completion_state() const { return completion_state_; }
bool is_multipart() const { return is_multipart_; }
bool is_high_bit_depth() const { return is_high_bit_depth_; }
+ bool may_be_lcp_candidate() const { return may_be_lcp_candidate_; }
int repetition_count() const { return repetition_count_; }
bool ShouldAnimate() const;
AnimationSequenceId reset_animation_sequence_id() const {
@@ -389,6 +390,12 @@ class CC_PAINT_EXPORT PaintImage {
// Whether this image has more than 8 bits per color channel.
bool is_high_bit_depth_ = false;
+ // Whether this image may untimately be a candidate for Largest Contentful
+ // Paint. The final LCP contribution of an image is unknown until we present
+ // it, but this flag is intended for metrics on when we do not present the
+ // image when the system claims.
+ bool may_be_lcp_candidate_ = false;
+
// An incrementing sequence number maintained by the painter to indicate if
// this animation should be reset in the compositor. Incrementing this number
// will reset this animation in the compositor for the first frame which has a
diff --git a/chromium/cc/paint/paint_image_builder.h b/chromium/cc/paint/paint_image_builder.h
index 008d0fa5dc0..f75c3ffc06e 100644
--- a/chromium/cc/paint/paint_image_builder.h
+++ b/chromium/cc/paint/paint_image_builder.h
@@ -87,6 +87,10 @@ class CC_PAINT_EXPORT PaintImageBuilder {
paint_image_.is_high_bit_depth_ = is_high_bit_depth;
return std::move(*this);
}
+ PaintImageBuilder&& set_may_be_lcp_candidate(bool may_be_lcp_candidate) {
+ paint_image_.may_be_lcp_candidate_ = may_be_lcp_candidate;
+ return std::move(*this);
+ }
PaintImageBuilder&& set_repetition_count(int count) {
paint_image_.repetition_count_ = count;
return std::move(*this);
diff --git a/chromium/cc/paint/paint_image_generator.h b/chromium/cc/paint/paint_image_generator.h
index 7c52f61681f..8941b1feb5b 100644
--- a/chromium/cc/paint/paint_image_generator.h
+++ b/chromium/cc/paint/paint_image_generator.h
@@ -61,7 +61,8 @@ class CC_PAINT_EXPORT PaintImageGenerator : public SkRefCnt {
// DecodingImageGenerator tracing needs. Remove it.
virtual bool GetYUVAPlanes(const SkYUVAPixmaps& pixmaps,
size_t frame_index,
- uint32_t lazy_pixel_ref) = 0;
+ uint32_t lazy_pixel_ref,
+ PaintImage::GeneratorClientId client_id) = 0;
// Returns the smallest size that is at least as big as the requested size,
// such that we can decode to exactly that scale.
diff --git a/chromium/cc/paint/paint_op_buffer.cc b/chromium/cc/paint/paint_op_buffer.cc
index 1081d238920..475cf1c02ea 100644
--- a/chromium/cc/paint/paint_op_buffer.cc
+++ b/chromium/cc/paint/paint_op_buffer.cc
@@ -1910,9 +1910,9 @@ void SaveLayerAlphaOp::Raster(const SaveLayerAlphaOp* op,
// See PaintOp::kUnsetRect
bool unset = op->bounds.left() == SK_ScalarInfinity;
absl::optional<SkPaint> paint;
- if (op->alpha != 0xFF) {
+ if (op->alpha != 1.0f) {
paint.emplace();
- paint->setAlpha(op->alpha);
+ paint->setAlpha(op->alpha * 255.0f);
}
SkCanvas::SaveLayerRec rec(unset ? nullptr : &op->bounds,
base::OptionalOrNullptr(paint));
@@ -2737,7 +2737,7 @@ int DrawPathOp::CountSlowPaths() const {
}
int DrawRecordOp::CountSlowPaths() const {
- return record->num_slow_paths();
+ return record->num_slow_paths_up_to_min_for_MSAA();
}
bool DrawRecordOp::HasNonAAPaint() const {
@@ -2929,7 +2929,7 @@ PaintOpBuffer& PaintOpBuffer::operator=(PaintOpBuffer&& other) {
used_ = other.used_;
reserved_ = other.reserved_;
op_count_ = other.op_count_;
- num_slow_paths_ = other.num_slow_paths_;
+ num_slow_paths_up_to_min_for_MSAA_ = other.num_slow_paths_up_to_min_for_MSAA_;
subrecord_bytes_used_ = other.subrecord_bytes_used_;
subrecord_op_count_ = other.subrecord_op_count_;
has_non_aa_paint_ = other.has_non_aa_paint_;
@@ -2960,7 +2960,7 @@ void PaintOpBuffer::Reset() {
// that if called.
used_ = 0;
op_count_ = 0;
- num_slow_paths_ = 0;
+ num_slow_paths_up_to_min_for_MSAA_ = 0;
has_non_aa_paint_ = false;
subrecord_bytes_used_ = 0;
subrecord_op_count_ = 0;
@@ -3019,7 +3019,7 @@ PaintOpBuffer::PlaybackFoldingIterator::PlaybackFoldingIterator(
PaintOpBuffer::PlaybackFoldingIterator::~PlaybackFoldingIterator() = default;
void PaintOpBuffer::PlaybackFoldingIterator::FindNextOp() {
- current_alpha_ = 255u;
+ current_alpha_ = 1.0f;
for (current_op_ = NextUnfoldedOp(); current_op_;
current_op_ = NextUnfoldedOp()) {
if (current_op_->GetType() != PaintOpType::SaveLayerAlpha)
@@ -3060,7 +3060,7 @@ void PaintOpBuffer::PlaybackFoldingIterator::FindNextOp() {
auto* draw_color_op = static_cast<const DrawColorOp*>(draw_op);
SkColor4f color = draw_color_op->color;
folded_draw_color_.color = {color.fR, color.fG, color.fB,
- save_op->alpha / 255 * color.fA};
+ save_op->alpha * color.fA};
current_op_ = &folded_draw_color_;
break;
}
@@ -3143,7 +3143,7 @@ void PaintOpBuffer::Playback(SkCanvas* canvas,
auto* context = canvas->recordingContext();
const ScopedRasterFlags scoped_flags(
&flags_op->flags, new_params.image_provider, canvas->getTotalMatrix(),
- context ? context->maxTextureSize() : 0, iter.alpha());
+ context ? context->maxTextureSize() : 0, iter.alpha() / 255.0f);
if (const auto* raster_flags = scoped_flags.flags())
flags_op->RasterWithFlags(canvas, raster_flags, new_params);
} else {
@@ -3285,7 +3285,8 @@ void PaintOpBuffer::ShrinkToFit() {
bool PaintOpBuffer::operator==(const PaintOpBuffer& other) const {
if (op_count_ != other.op_count_)
return false;
- if (num_slow_paths_ != other.num_slow_paths_)
+ if (num_slow_paths_up_to_min_for_MSAA_ !=
+ other.num_slow_paths_up_to_min_for_MSAA_)
return false;
if (subrecord_bytes_used_ != other.subrecord_bytes_used_)
return false;
diff --git a/chromium/cc/paint/paint_op_buffer.h b/chromium/cc/paint/paint_op_buffer.h
index 37f9aaad81c..fbb5b964f03 100644
--- a/chromium/cc/paint/paint_op_buffer.h
+++ b/chromium/cc/paint/paint_op_buffer.h
@@ -976,7 +976,8 @@ class CC_PAINT_EXPORT SaveLayerOp final : public PaintOpWithFlags {
class CC_PAINT_EXPORT SaveLayerAlphaOp final : public PaintOp {
public:
static constexpr PaintOpType kType = PaintOpType::SaveLayerAlpha;
- SaveLayerAlphaOp(const SkRect* bounds, uint8_t alpha)
+ template <class F, class = std::enable_if_t<std::is_same_v<F, float>>>
+ SaveLayerAlphaOp(const SkRect* bounds, F alpha)
: PaintOp(kType), bounds(bounds ? *bounds : kUnsetRect), alpha(alpha) {}
static void Raster(const SaveLayerAlphaOp* op,
SkCanvas* canvas,
@@ -988,7 +989,7 @@ class CC_PAINT_EXPORT SaveLayerAlphaOp final : public PaintOp {
HAS_SERIALIZATION_FUNCTIONS();
SkRect bounds;
- uint8_t alpha;
+ float alpha;
private:
SaveLayerAlphaOp() : PaintOp(kType) {}
@@ -1078,6 +1079,9 @@ using LargestPaintOp =
DrawImageRectOp,
DrawDRRectOp>::type;
+// Defined outside of the class as this const is used in multiple files.
+static constexpr int kMinNumberOfSlowPathsForMSAA = 6;
+
class CC_PAINT_EXPORT PaintOpBuffer : public SkRefCnt {
public:
enum { kInitialBufferSize = 4096 };
@@ -1133,7 +1137,9 @@ class CC_PAINT_EXPORT PaintOpBuffer : public SkRefCnt {
size_t total_op_count() const { return op_count_ + subrecord_op_count_; }
size_t next_op_offset() const { return used_; }
- int num_slow_paths() const { return num_slow_paths_; }
+ int num_slow_paths_up_to_min_for_MSAA() const {
+ return num_slow_paths_up_to_min_for_MSAA_;
+ }
bool HasNonAAPaint() const { return has_non_aa_paint_; }
bool HasDiscardableImages() const { return has_discardable_images_; }
@@ -1202,8 +1208,10 @@ class CC_PAINT_EXPORT PaintOpBuffer : public SkRefCnt {
static_assert(!std::is_same<T, PaintOp>::value,
"AnalyzeAddedOp needs a subtype of PaintOp");
- num_slow_paths_ += op->CountSlowPathsFromFlags();
- num_slow_paths_ += op->CountSlowPaths();
+ if (num_slow_paths_up_to_min_for_MSAA_ < kMinNumberOfSlowPathsForMSAA) {
+ num_slow_paths_up_to_min_for_MSAA_ += op->CountSlowPathsFromFlags();
+ num_slow_paths_up_to_min_for_MSAA_ += op->CountSlowPaths();
+ }
has_non_aa_paint_ |= op->HasNonAAPaint();
@@ -1233,7 +1241,8 @@ class CC_PAINT_EXPORT PaintOpBuffer : public SkRefCnt {
size_t GetOpOffsetForTracing(const PaintOp* op) const {
DCHECK_GE(reinterpret_cast<const char*>(op), data_.get());
- size_t result = reinterpret_cast<const char*>(op) - data_.get();
+ size_t result =
+ static_cast<size_t>(reinterpret_cast<const char*>(op) - data_.get());
DCHECK_LT(result, used_);
return result;
}
@@ -1408,7 +1417,9 @@ class CC_PAINT_EXPORT PaintOpBuffer : public SkRefCnt {
operator bool() const { return !!current_op_; }
// Guaranteed to be 255 for all ops without flags.
- uint8_t alpha() const { return current_alpha_; }
+ uint8_t alpha() const {
+ return static_cast<uint8_t>(current_alpha_ * 255.0f);
+ }
private:
void FindNextOp();
@@ -1424,7 +1435,7 @@ class CC_PAINT_EXPORT PaintOpBuffer : public SkRefCnt {
// analysis of sampling profiler data and tab_search:top100:2020).
RAW_PTR_EXCLUSION const PaintOp* current_op_ = nullptr;
- uint8_t current_alpha_ = 255;
+ float current_alpha_ = 1.0f;
};
private:
@@ -1452,8 +1463,10 @@ class CC_PAINT_EXPORT PaintOpBuffer : public SkRefCnt {
size_t subrecord_bytes_used_ = 0;
// Record total op count of referenced sub-record and display lists.
size_t subrecord_op_count_ = 0;
- // Record paths for veto-to-msaa for gpu raster.
- int num_slow_paths_ = 0;
+ // Record paths for veto-to-msaa for gpu raster. Counting slow paths can be
+ // very expensive, we stop counting them once reaching the minimum number
+ // required for an MSAA sample count for raster.
+ int num_slow_paths_up_to_min_for_MSAA_ = 0;
bool has_non_aa_paint_ : 1;
bool has_discardable_images_ : 1;
diff --git a/chromium/cc/paint/paint_op_buffer_fuzzer.cc b/chromium/cc/paint/paint_op_buffer_fuzzer.cc
index 3324ae0afaf..a20a5050d25 100644
--- a/chromium/cc/paint/paint_op_buffer_fuzzer.cc
+++ b/chromium/cc/paint/paint_op_buffer_fuzzer.cc
@@ -130,8 +130,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
if (bytes_for_fonts > size)
bytes_for_fonts = size / 2;
// PaintOpBuffer only accepts 4 bytes aligned buffer.
- bytes_for_fonts =
- base::bits::AlignDown(bytes_for_fonts, cc::PaintOpWriter::Alignment());
+ bytes_for_fonts = base::bits::AlignDown(
+ bytes_for_fonts,
+ base::checked_cast<uint32_t>(cc::PaintOpWriter::Alignment()));
FontSupport font_support;
scoped_refptr<gpu::ServiceFontManager> font_manager(
diff --git a/chromium/cc/paint/paint_op_buffer_serializer.cc b/chromium/cc/paint/paint_op_buffer_serializer.cc
index b57a7309556..8d0411722b1 100644
--- a/chromium/cc/paint/paint_op_buffer_serializer.cc
+++ b/chromium/cc/paint/paint_op_buffer_serializer.cc
@@ -142,8 +142,7 @@ void PaintOpBufferSerializer::ClearForOpaqueRaster(
SkClipOp::kDifference, false);
SerializeOp(canvas, &inner_clip_op, nullptr, params);
}
- DrawColorOp clear_op(SkColor4f::FromColor(preamble.background_color),
- SkBlendMode::kSrc);
+ DrawColorOp clear_op(preamble.background_color, SkBlendMode::kSrc);
SerializeOp(canvas, &clear_op, nullptr, params);
RestoreToCount(canvas, 1, params);
}
@@ -321,9 +320,9 @@ bool PaintOpBufferSerializer::SerializeOpWithFlags(
uint8_t alpha) {
// We use a null |image_provider| here because images are decoded during
// serialization.
- const ScopedRasterFlags scoped_flags(&flags_op->flags, nullptr,
- canvas->getTotalMatrix(),
- options_.max_texture_size, alpha);
+ const ScopedRasterFlags scoped_flags(
+ &flags_op->flags, nullptr, canvas->getTotalMatrix(),
+ options_.max_texture_size, alpha / 255.0f);
const PaintFlags* flags_to_serialize = scoped_flags.flags();
if (!flags_to_serialize)
return true;
diff --git a/chromium/cc/paint/paint_op_buffer_serializer.h b/chromium/cc/paint/paint_op_buffer_serializer.h
index c1f2ac7c06a..b44825b10b2 100644
--- a/chromium/cc/paint/paint_op_buffer_serializer.h
+++ b/chromium/cc/paint/paint_op_buffer_serializer.h
@@ -49,7 +49,7 @@ class CC_PAINT_EXPORT PaintOpBufferSerializer {
// potentially being partially transparent, if post scaled).
bool requires_clear = true;
// If clearing is needed, the color to clear to.
- SkColor background_color = SK_ColorTRANSPARENT;
+ SkColor4f background_color = SkColors::kTransparent;
};
// Serialize the buffer with a preamble. This function wraps the buffer in a
// save/restore and includes any translations, scales, and clearing as
diff --git a/chromium/cc/paint/paint_op_buffer_unittest.cc b/chromium/cc/paint/paint_op_buffer_unittest.cc
index 802675a4d1c..9c54c44c373 100644
--- a/chromium/cc/paint/paint_op_buffer_unittest.cc
+++ b/chromium/cc/paint/paint_op_buffer_unittest.cc
@@ -74,7 +74,7 @@ class PaintOpSerializationTestUtils {
shader->start_radius_ = 13.4f;
shader->tx_ = SkTileMode::kRepeat;
shader->ty_ = SkTileMode::kMirror;
- shader->fallback_color_ = SkColorSetARGB(254, 252, 250, 248);
+ shader->fallback_color_ = {0.99f, 0.98f, 0.97f, 0.99f};
shader->scaling_behavior_ = PaintShader::ScalingBehavior::kRasterAtScale;
if (use_matrix) {
shader->local_matrix_.emplace(SkMatrix::I());
@@ -88,8 +88,9 @@ class PaintOpSerializationTestUtils {
shader->start_degrees_ = 123;
shader->end_degrees_ = 456;
// TODO(vmpstr): Add PaintImage/PaintRecord.
- shader->colors_ = {SkColorSetARGB(1, 2, 3, 4), SkColorSetARGB(5, 6, 7, 8),
- SkColorSetARGB(9, 0, 1, 2)};
+ shader->colors_ = {{0.1f, 0.2f, 0.3f, 0.4f},
+ {0.05f, 0.15f, 0.25f, 0.35f},
+ {0.0f, 0.5f, 0.9f, 0.1f}};
shader->positions_ = {0.f, 0.4f, 1.f};
}
};
@@ -230,12 +231,13 @@ TEST_F(PaintOpAppendTest, MoveThenReappendOperatorEq) {
TEST(PaintOpBufferTest, SaveDrawRestore) {
PaintOpBuffer buffer;
- uint8_t alpha = 100;
+ float alpha = 0.4f;
buffer.push<SaveLayerAlphaOp>(nullptr, alpha);
+ int paint_flags_alpha = 50;
PaintFlags draw_flags;
- draw_flags.setColor(SK_ColorMAGENTA);
- draw_flags.setAlpha(50);
+ draw_flags.setColor(SkColors::kMagenta);
+ draw_flags.setAlpha(paint_flags_alpha);
EXPECT_TRUE(draw_flags.SupportsFoldingAlpha());
SkRect rect = SkRect::MakeXYWH(1, 2, 3, 4);
buffer.push<DrawRectOp>(rect, draw_flags);
@@ -250,15 +252,15 @@ TEST(PaintOpBufferTest, SaveDrawRestore) {
// Expect the alpha from the draw and the save layer to be folded together.
// Since alpha is stored in a uint8_t and gets rounded, so use tolerance.
- float expected_alpha = alpha * 50 / 255.f;
- EXPECT_LE(std::abs(expected_alpha - canvas.paint_.getAlpha()), 1.f);
+ float expected_alpha = alpha * paint_flags_alpha / 255.0f;
+ EXPECT_LE(std::abs(expected_alpha - canvas.paint_.getAlphaf()), 0.01f);
}
// Verify that we don't optimize SaveLayerAlpha / DrawTextBlob / Restore.
TEST(PaintOpBufferTest, SaveDrawTextBlobRestore) {
PaintOpBuffer buffer;
- uint8_t alpha = 100;
+ float alpha = 0.4f;
buffer.push<SaveLayerAlphaOp>(nullptr, alpha);
PaintFlags paint_flags;
@@ -280,11 +282,11 @@ TEST(PaintOpBufferTest, SaveDrawTextBlobRestore) {
TEST(PaintOpBufferTest, SaveDrawRestoreFail_BadFlags) {
PaintOpBuffer buffer;
- uint8_t alpha = 100;
+ float alpha = 0.4f;
buffer.push<SaveLayerAlphaOp>(nullptr, alpha);
PaintFlags draw_flags;
- draw_flags.setColor(SK_ColorMAGENTA);
+ draw_flags.setColor(SkColors::kMagenta);
draw_flags.setAlpha(50);
draw_flags.setBlendMode(SkBlendMode::kSrc);
EXPECT_FALSE(draw_flags.SupportsFoldingAlpha());
@@ -307,11 +309,11 @@ TEST(PaintOpBufferTest, SaveDrawRestoreFail_BadFlags) {
TEST(PaintOpBufferTest, SaveDrawRestore_BadFlags255Alpha) {
PaintOpBuffer buffer;
- uint8_t alpha = 255;
+ float alpha = 1.0f;
buffer.push<SaveLayerAlphaOp>(nullptr, alpha);
PaintFlags draw_flags;
- draw_flags.setColor(SK_ColorMAGENTA);
+ draw_flags.setColor(SkColors::kMagenta);
draw_flags.setAlpha(50);
draw_flags.setBlendMode(SkBlendMode::kColorBurn);
EXPECT_FALSE(draw_flags.SupportsFoldingAlpha());
@@ -332,11 +334,11 @@ TEST(PaintOpBufferTest, SaveDrawRestore_BadFlags255Alpha) {
TEST(PaintOpBufferTest, SaveDrawRestoreFail_TooManyOps) {
PaintOpBuffer buffer;
- uint8_t alpha = 100;
+ float alpha = 0.4f;
buffer.push<SaveLayerAlphaOp>(nullptr, alpha);
PaintFlags draw_flags;
- draw_flags.setColor(SK_ColorMAGENTA);
+ draw_flags.setColor(SkColors::kMagenta);
draw_flags.setAlpha(50);
draw_flags.setBlendMode(SkBlendMode::kSrcOver);
EXPECT_TRUE(draw_flags.SupportsFoldingAlpha());
@@ -359,7 +361,7 @@ TEST(PaintOpBufferTest, SaveDrawRestoreFail_TooManyOps) {
TEST(PaintOpBufferTest, SaveDrawRestore_SingleOpNotADrawOp) {
PaintOpBuffer buffer;
- uint8_t alpha = 100;
+ float alpha = 0.4f;
buffer.push<SaveLayerAlphaOp>(nullptr, alpha);
buffer.push<NoopOp>();
@@ -377,9 +379,10 @@ TEST(PaintOpBufferTest, SaveDrawRestore_SingleOpNotADrawOp) {
TEST(PaintOpBufferTest, SaveDrawRestore_SingleOpRecordWithSingleOp) {
sk_sp<PaintRecord> record = sk_make_sp<PaintRecord>();
+ int paint_flags_alpha = 50;
PaintFlags draw_flags;
- draw_flags.setColor(SK_ColorMAGENTA);
- draw_flags.setAlpha(50);
+ draw_flags.setColor(SkColors::kMagenta);
+ draw_flags.setAlpha(paint_flags_alpha);
EXPECT_TRUE(draw_flags.SupportsFoldingAlpha());
SkRect rect = SkRect::MakeXYWH(1, 2, 3, 4);
record->push<DrawRectOp>(rect, draw_flags);
@@ -387,7 +390,7 @@ TEST(PaintOpBufferTest, SaveDrawRestore_SingleOpRecordWithSingleOp) {
PaintOpBuffer buffer;
- uint8_t alpha = 100;
+ float alpha = 0.4f;
buffer.push<SaveLayerAlphaOp>(nullptr, alpha);
buffer.push<DrawRecordOp>(std::move(record));
buffer.push<RestoreOp>();
@@ -399,8 +402,8 @@ TEST(PaintOpBufferTest, SaveDrawRestore_SingleOpRecordWithSingleOp) {
EXPECT_EQ(0, canvas.restore_count_);
EXPECT_EQ(rect, canvas.draw_rect_);
- float expected_alpha = alpha * 50 / 255.f;
- EXPECT_LE(std::abs(expected_alpha - canvas.paint_.getAlpha()), 1.f);
+ float expected_alpha = alpha * paint_flags_alpha / 255.f;
+ EXPECT_LE(std::abs(expected_alpha - canvas.paint_.getAlphaf()), 0.01f);
}
// The same as the above SingleOpRecord test, but the single op is not
@@ -415,7 +418,7 @@ TEST(PaintOpBufferTest, SaveDrawRestore_SingleOpRecordWithSingleNonDrawOp) {
PaintOpBuffer buffer;
- uint8_t alpha = 100;
+ float alpha = 0.4f;
buffer.push<SaveLayerAlphaOp>(nullptr, alpha);
buffer.push<DrawRecordOp>(std::move(record));
buffer.push<RestoreOp>();
@@ -429,7 +432,7 @@ TEST(PaintOpBufferTest, SaveDrawRestore_SingleOpRecordWithSingleNonDrawOp) {
TEST(PaintOpBufferTest, SaveLayerRestore_DrawColor) {
PaintOpBuffer buffer;
- uint8_t alpha = 100;
+ float alpha = 0.4f;
SkColor original = SkColorSetA(50, SK_ColorRED);
buffer.push<SaveLayerAlphaOp>(nullptr, alpha);
@@ -507,7 +510,7 @@ TEST(PaintOpBufferTest, DiscardableImagesTracking_OpWithFlags) {
TEST(PaintOpBufferTest, SlowPaths) {
auto buffer = sk_make_sp<PaintOpBuffer>();
- EXPECT_EQ(buffer->num_slow_paths(), 0);
+ EXPECT_EQ(buffer->num_slow_paths_up_to_min_for_MSAA(), 0);
// Op without slow paths
PaintFlags noop_flags;
@@ -523,13 +526,13 @@ TEST(PaintOpBufferTest, SlowPaths) {
line_effect_slow.setPathEffect(SkDashPathEffect::Make(intervals, 2, 0));
buffer->push<DrawLineOp>(1.f, 2.f, 3.f, 4.f, line_effect_slow);
- EXPECT_EQ(buffer->num_slow_paths(), 1);
+ EXPECT_EQ(buffer->num_slow_paths_up_to_min_for_MSAA(), 1);
// Line effect special case that Skia handles specially.
PaintFlags line_effect = line_effect_slow;
line_effect.setStrokeCap(PaintFlags::kButt_Cap);
buffer->push<DrawLineOp>(1.f, 2.f, 3.f, 4.f, line_effect);
- EXPECT_EQ(buffer->num_slow_paths(), 1);
+ EXPECT_EQ(buffer->num_slow_paths_up_to_min_for_MSAA(), 1);
// Antialiased convex path is not slow.
SkPath path;
@@ -537,7 +540,7 @@ TEST(PaintOpBufferTest, SlowPaths) {
EXPECT_TRUE(path.isConvex());
buffer->push<ClipPathOp>(path, SkClipOp::kIntersect, /*antialias=*/true,
UsePaintCache::kDisabled);
- EXPECT_EQ(buffer->num_slow_paths(), 1);
+ EXPECT_EQ(buffer->num_slow_paths_up_to_min_for_MSAA(), 1);
// Concave paths are slow only when antialiased.
SkPath concave = path;
@@ -545,19 +548,19 @@ TEST(PaintOpBufferTest, SlowPaths) {
EXPECT_FALSE(concave.isConvex());
buffer->push<ClipPathOp>(concave, SkClipOp::kIntersect, /*antialias=*/true,
UsePaintCache::kDisabled);
- EXPECT_EQ(buffer->num_slow_paths(), 2);
+ EXPECT_EQ(buffer->num_slow_paths_up_to_min_for_MSAA(), 2);
buffer->push<ClipPathOp>(concave, SkClipOp::kIntersect, /*antialias=*/false,
UsePaintCache::kDisabled);
- EXPECT_EQ(buffer->num_slow_paths(), 2);
+ EXPECT_EQ(buffer->num_slow_paths_up_to_min_for_MSAA(), 2);
// Drawing a record with slow paths into another adds the same
// number of slow paths as the record.
auto buffer2 = sk_make_sp<PaintOpBuffer>();
- EXPECT_EQ(0, buffer2->num_slow_paths());
+ EXPECT_EQ(0, buffer2->num_slow_paths_up_to_min_for_MSAA());
buffer2->push<DrawRecordOp>(buffer);
- EXPECT_EQ(2, buffer2->num_slow_paths());
+ EXPECT_EQ(2, buffer2->num_slow_paths_up_to_min_for_MSAA());
buffer2->push<DrawRecordOp>(buffer);
- EXPECT_EQ(4, buffer2->num_slow_paths());
+ EXPECT_EQ(4, buffer2->num_slow_paths_up_to_min_for_MSAA());
}
TEST(PaintOpBufferTest, NonAAPaint) {
@@ -819,7 +822,7 @@ TEST_F(PaintOpBufferOffsetsTest, ContiguousIndicesWithSaveLayerAlphaRestore) {
push_op<DrawColorOp>(SkColor4f::FromColor(0u), SkBlendMode::kClear);
push_op<DrawColorOp>(SkColor4f::FromColor(1u), SkBlendMode::kClear);
- uint8_t alpha = 100;
+ float alpha = 0.4f;
push_op<SaveLayerAlphaOp>(nullptr, alpha);
push_op<RestoreOp>();
push_op<DrawColorOp>(SkColor4f::FromColor(2u), SkBlendMode::kClear);
@@ -845,7 +848,7 @@ TEST_F(PaintOpBufferOffsetsTest,
push_op<DrawColorOp>(SkColor4f::FromColor(0u), SkBlendMode::kClear);
push_op<DrawColorOp>(SkColor4f::FromColor(1u), SkBlendMode::kClear);
- uint8_t alpha = 100;
+ float alpha = 0.4f;
push_op<SaveLayerAlphaOp>(nullptr, alpha);
push_op<DrawColorOp>(SkColor4f::FromColor(2u), SkBlendMode::kClear);
push_op<DrawColorOp>(SkColor4f::FromColor(3u), SkBlendMode::kClear);
@@ -895,7 +898,7 @@ TEST_F(PaintOpBufferOffsetsTest,
add_draw_rect(0u);
add_draw_rect(1u);
- uint8_t alpha = 100;
+ float alpha = 0.4f;
push_op<SaveLayerAlphaOp>(nullptr, alpha);
add_draw_rect(2u);
push_op<RestoreOp>();
@@ -928,7 +931,7 @@ TEST_F(PaintOpBufferOffsetsTest,
add_draw_rect(0u);
add_draw_rect(1u);
- uint8_t alpha = 100;
+ float alpha = 0.4f;
push_op<SaveLayerAlphaOp>(nullptr, alpha);
add_draw_rect(2u);
add_draw_rect(3u);
@@ -987,7 +990,7 @@ TEST(PaintOpBufferTest, SaveLayerAlphaDrawRestoreWithBadBlendMode) {
};
add_draw_rect(&buffer, 0u);
- uint8_t alpha = 100;
+ float alpha = 0.4f;
buffer.push<SaveLayerAlphaOp>(nullptr, alpha);
add_draw_rect(&buffer, 1u);
buffer.push<RestoreOp>();
@@ -1016,7 +1019,7 @@ TEST(PaintOpBufferTest, UnmatchedSaveRestoreNoSideEffects) {
// Push 2 saves.
- uint8_t alpha = 100;
+ float alpha = 0.4f;
buffer.push<SaveLayerAlphaOp>(nullptr, alpha);
add_draw_rect(&buffer, 0u);
buffer.push<SaveLayerAlphaOp>(nullptr, alpha);
@@ -1127,7 +1130,7 @@ std::vector<PaintFlags> test_flags = {
flags.setStrokeJoin(PaintFlags::kBevel_Join);
flags.setStyle(PaintFlags::kStroke_Style);
flags.setFilterQuality(PaintFlags::FilterQuality::kMedium);
- flags.setShader(PaintShader::MakeColor(SkColorSetARGB(1, 2, 3, 4)));
+ flags.setShader(PaintShader::MakeColor({0.1f, 0.2f, 0.3f, 0.4f}));
return flags;
}(),
[] {
@@ -1159,7 +1162,8 @@ std::vector<PaintFlags> test_flags = {
looper_builder.addLayer(layer_info);
flags.setLooper(looper_builder.detach());
- sk_sp<PaintShader> shader = PaintShader::MakeColor(SK_ColorTRANSPARENT);
+ sk_sp<PaintShader> shader =
+ PaintShader::MakeColor(SkColors::kTransparent);
PaintOpSerializationTestUtils::FillArbitraryShaderValues(shader.get(),
true);
flags.setShader(std::move(shader));
@@ -1168,13 +1172,14 @@ std::vector<PaintFlags> test_flags = {
}(),
[] {
PaintFlags flags;
- flags.setShader(PaintShader::MakeColor(SkColorSetARGB(12, 34, 56, 78)));
+ flags.setShader(PaintShader::MakeColor({0.1f, 0.2f, 0.3f, 0.4f}));
return flags;
}(),
[] {
PaintFlags flags;
- sk_sp<PaintShader> shader = PaintShader::MakeColor(SK_ColorTRANSPARENT);
+ sk_sp<PaintShader> shader =
+ PaintShader::MakeColor(SkColors::kTransparent);
PaintOpSerializationTestUtils::FillArbitraryShaderValues(shader.get(),
false);
flags.setShader(std::move(shader));
@@ -1184,9 +1189,9 @@ std::vector<PaintFlags> test_flags = {
[] {
PaintFlags flags;
SkPoint points[2] = {SkPoint::Make(1, 2), SkPoint::Make(3, 4)};
- SkColor colors[3] = {SkColorSetARGB(1, 2, 3, 4),
- SkColorSetARGB(4, 3, 2, 1),
- SkColorSetARGB(0, 10, 20, 30)};
+ SkColor4f colors[3] = {{0.1f, 0.2f, 0.3f, 0.4f},
+ {0.4f, 0.3f, 0.2f, 0.1f},
+ {0.2f, 0.4f, 0.6f, 0.0f}};
SkScalar positions[3] = {0.f, 0.3f, 1.f};
flags.setShader(PaintShader::MakeLinearGradient(points, colors, positions,
3, SkTileMode::kMirror));
@@ -1195,9 +1200,9 @@ std::vector<PaintFlags> test_flags = {
}(),
[] {
PaintFlags flags;
- SkColor colors[3] = {SkColorSetARGB(1, 2, 3, 4),
- SkColorSetARGB(4, 3, 2, 1),
- SkColorSetARGB(0, 10, 20, 30)};
+ SkColor4f colors[3] = {{0.1f, 0.2f, 0.3f, 0.4f},
+ {0.4f, 0.3f, 0.2f, 0.1f},
+ {0.2f, 0.4f, 0.6f, 0.0f}};
flags.setShader(PaintShader::MakeSweepGradient(
0.2f, -0.8f, colors, nullptr, 3, SkTileMode::kMirror, 10, 20));
return flags;
@@ -1725,12 +1730,12 @@ void PushSaveLayerOps(PaintOpBuffer* buffer) {
}
void PushSaveLayerAlphaOps(PaintOpBuffer* buffer) {
- size_t len = std::min(test_uint8s.size(), test_rects.size());
+ size_t len = std::min(test_floats.size(), test_rects.size());
for (size_t i = 0; i < len; ++i)
- buffer->push<SaveLayerAlphaOp>(&test_rects[i], test_uint8s[i]);
+ buffer->push<SaveLayerAlphaOp>(&test_rects[i], test_floats[i]);
// Test optional args.
- buffer->push<SaveLayerAlphaOp>(nullptr, test_uint8s[0]);
+ buffer->push<SaveLayerAlphaOp>(nullptr, test_floats[0]);
ValidateOps<SaveLayerAlphaOp>(buffer);
}
@@ -2443,11 +2448,11 @@ TEST(PaintOpBufferTest, ClipsImagesDuringSerialization) {
TEST(PaintOpBufferSerializationTest, AlphaFoldingDuringSerialization) {
PaintOpBuffer buffer;
- uint8_t alpha = 100;
+ float alpha = 0.4f;
buffer.push<SaveLayerAlphaOp>(nullptr, alpha);
PaintFlags draw_flags;
- draw_flags.setColor(SK_ColorMAGENTA);
+ draw_flags.setColor(SkColors::kMagenta);
draw_flags.setAlpha(50);
SkRect rect = SkRect::MakeXYWH(1, 2, 3, 4);
buffer.push<DrawRectOp>(rect, draw_flags);
@@ -2497,7 +2502,7 @@ TEST(PaintOpBufferSerializationTest, AlphaFoldingDuringSerialization) {
ASSERT_EQ(op->GetType(), PaintOpType::DrawRect);
// Expect the alpha from the draw and the save layer to be folded together.
// Since alpha is stored in a uint8_t and gets rounded, so use tolerance.
- float expected_alpha = alpha * 50 / 255.f;
+ float expected_alpha = alpha * 50;
EXPECT_LE(std::abs(expected_alpha -
static_cast<const DrawRectOp*>(op)->flags.getAlpha()),
1.f);
@@ -2730,7 +2735,7 @@ TEST(PaintOpBufferTest, ValidateRects) {
buffer.push<DrawRectOp>(bad_rect, test_flags[0]);
buffer.push<SaveLayerOp>(&bad_rect, nullptr);
buffer.push<SaveLayerOp>(&bad_rect, &test_flags[0]);
- buffer.push<SaveLayerAlphaOp>(&bad_rect, test_uint8s[0]);
+ buffer.push<SaveLayerAlphaOp>(&bad_rect, test_floats[0]);
TestOptionsProvider options_provider;
@@ -3387,7 +3392,7 @@ TEST_P(PaintFilterSerializationTest, Basic) {
sk_sp<PaintFilter>{
new BlurPaintFilter(0.5f, 0.3f, SkTileMode::kRepeat, nullptr)},
sk_sp<PaintFilter>{new DropShadowPaintFilter(
- 5.f, 10.f, 0.1f, 0.3f, SK_ColorBLUE,
+ 5.f, 10.f, 0.1f, 0.3f, SkColors::kBlue,
DropShadowPaintFilter::ShadowMode::kDrawShadowOnly, nullptr)},
sk_sp<PaintFilter>{new MagnifierPaintFilter(SkRect::MakeXYWH(5, 6, 7, 8),
10.5f, nullptr)},
@@ -3408,13 +3413,13 @@ TEST_P(PaintFilterSerializationTest, Basic) {
SkMatrix::I(), PaintFlags::FilterQuality::kHigh, nullptr)},
sk_sp<PaintFilter>{new LightingDistantPaintFilter(
PaintFilter::LightingType::kSpecular, SkPoint3::Make(1, 2, 3),
- SK_ColorCYAN, 1.1f, 2.2f, 3.3f, nullptr)},
+ SkColors::kCyan, 1.1f, 2.2f, 3.3f, nullptr)},
sk_sp<PaintFilter>{new LightingPointPaintFilter(
PaintFilter::LightingType::kDiffuse, SkPoint3::Make(2, 3, 4),
- SK_ColorRED, 1.2f, 3.4f, 5.6f, nullptr)},
+ SkColors::kRed, 1.2f, 3.4f, 5.6f, nullptr)},
sk_sp<PaintFilter>{new LightingSpotPaintFilter(
PaintFilter::LightingType::kSpecular, SkPoint3::Make(100, 200, 300),
- SkPoint3::Make(400, 500, 600), 1, 2, SK_ColorMAGENTA, 3, 4, 5,
+ SkPoint3::Make(400, 500, 600), 1, 2, SkColors::kMagenta, 3, 4, 5,
nullptr)},
sk_sp<PaintFilter>{
new ImagePaintFilter(CreateDiscardablePaintImage(gfx::Size(100, 100)),
@@ -4141,7 +4146,7 @@ TEST(PaintOpBufferTest, HasEffectsPreventingLCDTextForSaveLayerAlpha) {
TEST(PaintOpBufferTest, NeedsAdditionalInvalidationForLCDText) {
auto buffer1 = sk_make_sp<PaintOpBuffer>();
- buffer1->push<SaveLayerAlphaOp>(nullptr, uint8_t{100});
+ buffer1->push<SaveLayerAlphaOp>(nullptr, 0.4f);
EXPECT_FALSE(buffer1->has_draw_text_ops());
EXPECT_TRUE(buffer1->has_save_layer_alpha_ops());
EXPECT_FALSE(buffer1->has_effects_preventing_lcd_text_for_save_layer_alpha());
diff --git a/chromium/cc/paint/paint_op_helper_unittest.cc b/chromium/cc/paint/paint_op_helper_unittest.cc
index 8a4aa431d23..9c66ff044f3 100644
--- a/chromium/cc/paint/paint_op_helper_unittest.cc
+++ b/chromium/cc/paint/paint_op_helper_unittest.cc
@@ -272,7 +272,7 @@ TEST(PaintOpHelper, SaveLayerToString) {
TEST(PaintOpHelper, SaveLayerAlphaToString) {
SkRect bounds = SkRect::MakeXYWH(1, 2, 3, 4);
- SaveLayerAlphaOp op(&bounds, 255);
+ SaveLayerAlphaOp op(&bounds, 1.0f);
std::string str = PaintOpHelper::ToString(&op);
EXPECT_EQ(str,
"SaveLayerAlphaOp(bounds=[1.000,2.000 3.000x4.000], alpha=255)");
diff --git a/chromium/cc/paint/paint_op_perftest.cc b/chromium/cc/paint/paint_op_perftest.cc
index 043d818068c..c3bba0bfdc5 100644
--- a/chromium/cc/paint/paint_op_perftest.cc
+++ b/chromium/cc/paint/paint_op_perftest.cc
@@ -137,7 +137,7 @@ TEST_F(PaintOpPerfTest, ManyFlagsOps) {
looper_builder.addLayer(layer_info);
flags.setLooper(looper_builder.detach());
- sk_sp<PaintShader> shader = PaintShader::MakeColor(SK_ColorTRANSPARENT);
+ sk_sp<PaintShader> shader = PaintShader::MakeColor(SkColors::kTransparent);
flags.setShader(std::move(shader));
SkPath path;
diff --git a/chromium/cc/paint/paint_op_reader.cc b/chromium/cc/paint/paint_op_reader.cc
index 26278227497..6f9ad5cd016 100644
--- a/chromium/cc/paint/paint_op_reader.cc
+++ b/chromium/cc/paint/paint_op_reader.cc
@@ -566,7 +566,8 @@ void PaintOpReader::Read(sk_sp<PaintShader>* shader) {
kInsufficientRemainingBytes_Read_PaintShader_ColorSize);
return;
}
- size_t colors_bytes = colors_size * sizeof(SkColor);
+ size_t colors_bytes =
+ colors_size * (colors_size > 0 ? sizeof(ref.colors_[0]) : 0u);
if (colors_bytes > remaining_bytes_) {
SetInvalid(DeserializationError::
kInsufficientRemainingBytes_Read_PaintShader_ColorBytes);
@@ -917,12 +918,12 @@ void PaintOpReader::ReadDropShadowPaintFilter(
Read(&color);
ReadEnum(&shadow_mode);
Read(&input);
-
if (!valid_)
return;
- filter->reset(new DropShadowPaintFilter(dx, dy, sigma_x, sigma_y, color,
- shadow_mode, std::move(input),
- base::OptionalOrNullptr(crop_rect)));
+ // TODO(crbug/1308932): Remove FromColor and make all SkColor4f.
+ filter->reset(new DropShadowPaintFilter(
+ dx, dy, sigma_x, sigma_y, SkColor4f::FromColor(color), shadow_mode,
+ std::move(input), base::OptionalOrNullptr(crop_rect)));
}
void PaintOpReader::ReadMagnifierPaintFilter(
@@ -1296,9 +1297,11 @@ void PaintOpReader::ReadLightingDistantPaintFilter(
Read(&input);
if (!valid_)
return;
+ // TODO(crbug/1308932): Remove FromColor and make all SkColor4f.
filter->reset(new LightingDistantPaintFilter(
- lighting_type, direction, light_color, surface_scale, kconstant,
- shininess, std::move(input), base::OptionalOrNullptr(crop_rect)));
+ lighting_type, direction, SkColor4f::FromColor(light_color),
+ surface_scale, kconstant, shininess, std::move(input),
+ base::OptionalOrNullptr(crop_rect)));
}
void PaintOpReader::ReadLightingPointPaintFilter(
@@ -1321,9 +1324,11 @@ void PaintOpReader::ReadLightingPointPaintFilter(
Read(&input);
if (!valid_)
return;
+ // TODO(crbug/1308932): Remove FromColor and make all SkColor4f.
filter->reset(new LightingPointPaintFilter(
- lighting_type, location, light_color, surface_scale, kconstant, shininess,
- std::move(input), base::OptionalOrNullptr(crop_rect)));
+ lighting_type, location, SkColor4f::FromColor(light_color), surface_scale,
+ kconstant, shininess, std::move(input),
+ base::OptionalOrNullptr(crop_rect)));
}
void PaintOpReader::ReadLightingSpotPaintFilter(
@@ -1353,10 +1358,11 @@ void PaintOpReader::ReadLightingSpotPaintFilter(
if (!valid_)
return;
+ // TODO(crbug/1308932): Remove FromColor and make all SkColor4f.
filter->reset(new LightingSpotPaintFilter(
lighting_type, location, target, specular_exponent, cutoff_angle,
- light_color, surface_scale, kconstant, shininess, std::move(input),
- base::OptionalOrNullptr(crop_rect)));
+ SkColor4f::FromColor(light_color), surface_scale, kconstant, shininess,
+ std::move(input), base::OptionalOrNullptr(crop_rect)));
}
void PaintOpReader::ReadStretchPaintFilter(
diff --git a/chromium/cc/paint/paint_op_writer.cc b/chromium/cc/paint/paint_op_writer.cc
index f899b75f254..497cdeed0db 100644
--- a/chromium/cc/paint/paint_op_writer.cc
+++ b/chromium/cc/paint/paint_op_writer.cc
@@ -544,7 +544,9 @@ void PaintOpWriter::Write(const PaintShader* shader,
}
WriteSize(shader->colors_.size());
- WriteData(shader->colors_.size() * sizeof(SkColor), shader->colors_.data());
+ WriteData(shader->colors_.size() *
+ (shader->colors_.size() > 0 ? sizeof(shader->colors_[0]) : 0u),
+ shader->colors_.data());
WriteSize(shader->positions_.size());
WriteData(shader->positions_.size() * sizeof(SkScalar),
@@ -715,7 +717,8 @@ void PaintOpWriter::Write(const DropShadowPaintFilter& filter,
WriteSimple(filter.dy());
WriteSimple(filter.sigma_x());
WriteSimple(filter.sigma_y());
- WriteSimple(filter.color());
+ // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
+ WriteSimple(filter.color().toSkColor());
WriteEnum(filter.shadow_mode());
Write(filter.input().get(), current_ctm);
}
@@ -879,7 +882,8 @@ void PaintOpWriter::Write(const LightingDistantPaintFilter& filter,
const SkM44& current_ctm) {
WriteEnum(filter.lighting_type());
WriteSimple(filter.direction());
- WriteSimple(filter.light_color());
+ // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
+ WriteSimple(filter.light_color().toSkColor());
WriteSimple(filter.surface_scale());
WriteSimple(filter.kconstant());
WriteSimple(filter.shininess());
@@ -890,7 +894,8 @@ void PaintOpWriter::Write(const LightingPointPaintFilter& filter,
const SkM44& current_ctm) {
WriteEnum(filter.lighting_type());
WriteSimple(filter.location());
- WriteSimple(filter.light_color());
+ // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
+ WriteSimple(filter.light_color().toSkColor());
WriteSimple(filter.surface_scale());
WriteSimple(filter.kconstant());
WriteSimple(filter.shininess());
@@ -904,7 +909,8 @@ void PaintOpWriter::Write(const LightingSpotPaintFilter& filter,
WriteSimple(filter.target());
WriteSimple(filter.specular_exponent());
WriteSimple(filter.cutoff_angle());
- WriteSimple(filter.light_color());
+ // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
+ WriteSimple(filter.light_color().toSkColor());
WriteSimple(filter.surface_scale());
WriteSimple(filter.kconstant());
WriteSimple(filter.shininess());
diff --git a/chromium/cc/paint/paint_shader.cc b/chromium/cc/paint/paint_shader.cc
index 02031a92250..c96bf1c0650 100644
--- a/chromium/cc/paint/paint_shader.cc
+++ b/chromium/cc/paint/paint_shader.cc
@@ -65,7 +65,7 @@ sk_sp<PaintShader> PaintShader::MakeEmpty() {
return shader;
}
-sk_sp<PaintShader> PaintShader::MakeColor(SkColor color) {
+sk_sp<PaintShader> PaintShader::MakeColor(SkColor4f color) {
sk_sp<PaintShader> shader(new PaintShader(Type::kColor));
// Just one color. Store it in the fallback color. Easy.
@@ -76,13 +76,13 @@ sk_sp<PaintShader> PaintShader::MakeColor(SkColor color) {
}
sk_sp<PaintShader> PaintShader::MakeLinearGradient(const SkPoint points[],
- const SkColor colors[],
+ const SkColor4f colors[],
const SkScalar pos[],
int count,
SkTileMode mode,
uint32_t flags,
const SkMatrix* local_matrix,
- SkColor fallback_color) {
+ SkColor4f fallback_color) {
sk_sp<PaintShader> shader(new PaintShader(Type::kLinearGradient));
// There are always two points, the start and the end.
@@ -98,13 +98,13 @@ sk_sp<PaintShader> PaintShader::MakeLinearGradient(const SkPoint points[],
sk_sp<PaintShader> PaintShader::MakeRadialGradient(const SkPoint& center,
SkScalar radius,
- const SkColor colors[],
+ const SkColor4f colors[],
const SkScalar pos[],
int count,
SkTileMode mode,
uint32_t flags,
const SkMatrix* local_matrix,
- SkColor fallback_color) {
+ SkColor4f fallback_color) {
sk_sp<PaintShader> shader(new PaintShader(Type::kRadialGradient));
shader->center_ = center;
@@ -122,13 +122,13 @@ sk_sp<PaintShader> PaintShader::MakeTwoPointConicalGradient(
SkScalar start_radius,
const SkPoint& end,
SkScalar end_radius,
- const SkColor colors[],
+ const SkColor4f colors[],
const SkScalar pos[],
int count,
SkTileMode mode,
uint32_t flags,
const SkMatrix* local_matrix,
- SkColor fallback_color) {
+ SkColor4f fallback_color) {
sk_sp<PaintShader> shader(new PaintShader(Type::kTwoPointConicalGradient));
shader->start_point_ = start;
@@ -145,7 +145,7 @@ sk_sp<PaintShader> PaintShader::MakeTwoPointConicalGradient(
sk_sp<PaintShader> PaintShader::MakeSweepGradient(SkScalar cx,
SkScalar cy,
- const SkColor colors[],
+ const SkColor4f colors[],
const SkScalar pos[],
int color_count,
SkTileMode mode,
@@ -153,7 +153,7 @@ sk_sp<PaintShader> PaintShader::MakeSweepGradient(SkScalar cx,
SkScalar end_degrees,
uint32_t flags,
const SkMatrix* local_matrix,
- SkColor fallback_color) {
+ SkColor4f fallback_color) {
sk_sp<PaintShader> shader(new PaintShader(Type::kSweepGradient));
shader->center_ = SkPoint::Make(cx, cy);
@@ -223,7 +223,7 @@ size_t PaintShader::GetSerializedSize(const PaintShader* shader) {
sizeof(shader->id_) +
PaintOpWriter::GetRecordSize(shader->record_.get()) +
sizeof(shader->colors_.size()) +
- shader->colors_.size() * sizeof(SkColor) +
+ shader->colors_.size() * sizeof(SkColor4f) +
sizeof(shader->positions_.size()) +
shader->positions_.size() * sizeof(SkScalar);
}
@@ -386,6 +386,13 @@ sk_sp<SkShader> PaintShader::GetSkShader(
SkSamplingOptions sampling(
PaintFlags::FilterQualityToSkSamplingOptions(quality));
+ // TODO(crbug/1308932): Remove this helper vector colors and make all
+ // SkColor4f.
+ std::vector<SkColor> colors;
+ colors.reserve(colors.size());
+ for (auto& c : colors_)
+ colors.push_back(c.toSkColor());
+
switch (shader_type_) {
case Type::kEmpty:
return SkShaders::Empty();
@@ -394,27 +401,32 @@ sk_sp<SkShader> PaintShader::GetSkShader(
break;
case Type::kLinearGradient: {
SkPoint points[2] = {start_point_, end_point_};
+ // TODO(crbug/1308932): Remove this helper vector colors and make all
+ // SkColor4f.
return SkGradientShader::MakeLinear(
- points, colors_.data(),
+ points, colors.data(),
positions_.empty() ? nullptr : positions_.data(),
- static_cast<int>(colors_.size()), tx_, flags_,
+ static_cast<int>(colors.size()), tx_, flags_,
base::OptionalOrNullptr(local_matrix_));
}
case Type::kRadialGradient:
return SkGradientShader::MakeRadial(
center_, start_radius_, colors_.data(),
+ nullptr /*sk_sp<SkColorSpace>*/,
positions_.empty() ? nullptr : positions_.data(),
static_cast<int>(colors_.size()), tx_, flags_,
base::OptionalOrNullptr(local_matrix_));
case Type::kTwoPointConicalGradient:
return SkGradientShader::MakeTwoPointConical(
start_point_, start_radius_, end_point_, end_radius_, colors_.data(),
+ nullptr /*sk_sp<SkColorSpace>*/,
positions_.empty() ? nullptr : positions_.data(),
static_cast<int>(colors_.size()), tx_, flags_,
base::OptionalOrNullptr(local_matrix_));
case Type::kSweepGradient:
return SkGradientShader::MakeSweep(
center_.x(), center_.y(), colors_.data(),
+ nullptr /*sk_sp<SkColorSpace>*/,
positions_.empty() ? nullptr : positions_.data(),
static_cast<int>(colors_.size()), tx_, start_degrees_, end_degrees_,
flags_, base::OptionalOrNullptr(local_matrix_));
@@ -453,7 +465,7 @@ sk_sp<SkShader> PaintShader::GetSkShader(
// If we didn't create a shader for whatever reason, create a fallback
// color one.
- return SkShaders::Color(fallback_color_);
+ return SkShaders::Color(fallback_color_.toSkColor());
}
void PaintShader::ResolveSkObjects(const gfx::SizeF* raster_scale,
@@ -476,7 +488,7 @@ void PaintShader::ResolveSkObjects(const gfx::SizeF* raster_scale,
}
}
-void PaintShader::SetColorsAndPositions(const SkColor* colors,
+void PaintShader::SetColorsAndPositions(const SkColor4f* colors,
const SkScalar* positions,
int count) {
#if DCHECK_IS_ON()
@@ -498,7 +510,8 @@ void PaintShader::SetMatrixAndTiling(const SkMatrix* matrix,
ty_ = ty;
}
-void PaintShader::SetFlagsAndFallback(uint32_t flags, SkColor fallback_color) {
+void PaintShader::SetFlagsAndFallback(uint32_t flags,
+ SkColor4f fallback_color) {
flags_ = flags;
fallback_color_ = fallback_color;
}
@@ -516,7 +529,7 @@ bool PaintShader::IsOpaque() const {
if (tx_ == SkTileMode::kDecal)
return false;
for (const auto& c : colors_)
- if (SkColorGetA(c) != 0xFF)
+ if (!c.isOpaque())
return false;
return true;
case Type::kTwoPointConicalGradient:
@@ -538,7 +551,7 @@ bool PaintShader::IsOpaque() const {
NOTREACHED();
break;
}
- return SkColorGetA(fallback_color_) == 0xFF;
+ return fallback_color_.isOpaque();
}
bool PaintShader::IsValid() const {
diff --git a/chromium/cc/paint/paint_shader.h b/chromium/cc/paint/paint_shader.h
index 80519ed3e89..b5317433a8c 100644
--- a/chromium/cc/paint/paint_shader.h
+++ b/chromium/cc/paint/paint_shader.h
@@ -53,47 +53,47 @@ class CC_PAINT_EXPORT PaintShader : public SkRefCnt {
static sk_sp<PaintShader> MakeEmpty();
- static sk_sp<PaintShader> MakeColor(SkColor color);
+ static sk_sp<PaintShader> MakeColor(SkColor4f color);
// TODO(crbug.com/1155544) SkMatrix is deprecated in favor of SkM44.
static sk_sp<PaintShader> MakeLinearGradient(
const SkPoint* points,
- const SkColor* colors,
+ const SkColor4f colors[],
const SkScalar* pos,
int count,
SkTileMode mode,
uint32_t flags = 0,
const SkMatrix* local_matrix = nullptr,
- SkColor fallback_color = SK_ColorTRANSPARENT);
+ SkColor4f fallback_color = SkColors::kTransparent);
static sk_sp<PaintShader> MakeRadialGradient(
const SkPoint& center,
SkScalar radius,
- const SkColor colors[],
+ const SkColor4f colors[],
const SkScalar pos[],
int color_count,
SkTileMode mode,
uint32_t flags = 0,
const SkMatrix* local_matrix = nullptr,
- SkColor fallback_color = SK_ColorTRANSPARENT);
+ SkColor4f fallback_color = SkColors::kTransparent);
static sk_sp<PaintShader> MakeTwoPointConicalGradient(
const SkPoint& start,
SkScalar start_radius,
const SkPoint& end,
SkScalar end_radius,
- const SkColor colors[],
+ const SkColor4f colors[],
const SkScalar pos[],
int color_count,
SkTileMode mode,
uint32_t flags = 0,
const SkMatrix* local_matrix = nullptr,
- SkColor fallback_color = SK_ColorTRANSPARENT);
+ SkColor4f fallback_color = SkColors::kTransparent);
static sk_sp<PaintShader> MakeSweepGradient(
SkScalar cx,
SkScalar cy,
- const SkColor colors[],
+ const SkColor4f colors[],
const SkScalar pos[],
int color_count,
SkTileMode mode,
@@ -101,7 +101,7 @@ class CC_PAINT_EXPORT PaintShader : public SkRefCnt {
SkScalar end_degrees,
uint32_t flags = 0,
const SkMatrix* local_matrix = nullptr,
- SkColor fallback_color = SK_ColorTRANSPARENT);
+ SkColor4f fallback_color = SkColors::kTransparent);
// |tile_rect| is not null only if the |image| is paint worklet backed.
static sk_sp<PaintShader> MakeImage(const PaintImage& image,
@@ -226,11 +226,11 @@ class CC_PAINT_EXPORT PaintShader : public SkRefCnt {
sk_sp<PaintShader> CreatePaintWorkletRecord(
ImageProvider* image_provider) const;
- void SetColorsAndPositions(const SkColor* colors,
+ void SetColorsAndPositions(const SkColor4f* colors,
const SkScalar* positions,
int count);
void SetMatrixAndTiling(const SkMatrix* matrix, SkTileMode tx, SkTileMode ty);
- void SetFlagsAndFallback(uint32_t flags, SkColor fallback_color);
+ void SetFlagsAndFallback(uint32_t flags, SkColor4f fallback_color);
Type shader_type_ = Type::kShaderCount;
@@ -239,7 +239,7 @@ class CC_PAINT_EXPORT PaintShader : public SkRefCnt {
SkScalar start_radius_ = 0;
SkTileMode tx_ = SkTileMode::kClamp;
SkTileMode ty_ = SkTileMode::kClamp;
- SkColor fallback_color_ = SK_ColorTRANSPARENT;
+ SkColor4f fallback_color_ = SkColors::kTransparent;
ScalingBehavior scaling_behavior_ = ScalingBehavior::kRasterAtScale;
absl::optional<SkMatrix> local_matrix_;
@@ -260,10 +260,10 @@ class CC_PAINT_EXPORT PaintShader : public SkRefCnt {
// will be rasterized.
absl::optional<gfx::SizeF> tile_scale_;
- std::vector<SkColor> colors_;
+ std::vector<SkColor4f> colors_;
std::vector<SkScalar> positions_;
- // Cached intermediates, for cc::Paint objects that may not be thread-safe
+ // Cached intermediates, for Paint objects that may not be thread-safe
sk_sp<SkPicture> sk_cached_picture_;
sk_sp<SkImage> sk_cached_image_;
diff --git a/chromium/cc/paint/paint_worklet_input.cc b/chromium/cc/paint/paint_worklet_input.cc
index 4efca99b90e..be838a57cb6 100644
--- a/chromium/cc/paint/paint_worklet_input.cc
+++ b/chromium/cc/paint/paint_worklet_input.cc
@@ -55,7 +55,7 @@ PaintWorkletInput::PropertyValue::PropertyValue() = default;
PaintWorkletInput::PropertyValue::PropertyValue(float value)
: float_value(value) {}
-PaintWorkletInput::PropertyValue::PropertyValue(SkColor value)
+PaintWorkletInput::PropertyValue::PropertyValue(SkColor4f value)
: color_value(value) {}
PaintWorkletInput::PropertyValue::PropertyValue(const PropertyValue& other) =
diff --git a/chromium/cc/paint/paint_worklet_input.h b/chromium/cc/paint/paint_worklet_input.h
index 88b4d2fa67e..9a76ec28391 100644
--- a/chromium/cc/paint/paint_worklet_input.h
+++ b/chromium/cc/paint/paint_worklet_input.h
@@ -70,13 +70,13 @@ class CC_PAINT_EXPORT PaintWorkletInput
struct CC_PAINT_EXPORT PropertyValue {
PropertyValue();
explicit PropertyValue(float value);
- explicit PropertyValue(SkColor value);
+ explicit PropertyValue(SkColor4f value);
PropertyValue(const PropertyValue&);
~PropertyValue();
bool has_value() const;
void reset();
absl::optional<float> float_value;
- absl::optional<SkColor> color_value;
+ absl::optional<SkColor4f> color_value;
};
virtual gfx::SizeF GetSize() const = 0;
diff --git a/chromium/cc/paint/record_paint_canvas.cc b/chromium/cc/paint/record_paint_canvas.cc
index 0f917af47e1..1ddabced058 100644
--- a/chromium/cc/paint/record_paint_canvas.cc
+++ b/chromium/cc/paint/record_paint_canvas.cc
@@ -95,7 +95,7 @@ int RecordPaintCanvas::saveLayer(const SkRect* bounds,
}
int RecordPaintCanvas::saveLayerAlpha(const SkRect* bounds, uint8_t alpha) {
- push<SaveLayerAlphaOp>(bounds, alpha);
+ push<SaveLayerAlphaOp>(bounds, static_cast<float>(alpha / 255.0f));
return GetCanvas()->saveLayerAlpha(bounds, alpha);
}
@@ -227,12 +227,12 @@ bool RecordPaintCanvas::getDeviceClipBounds(SkIRect* bounds) const {
return GetCanvas()->getDeviceClipBounds(bounds);
}
-void RecordPaintCanvas::drawColor(SkColor color, SkBlendMode mode) {
- push<DrawColorOp>(SkColor4f::FromColor(color), mode);
+void RecordPaintCanvas::drawColor(SkColor4f color, SkBlendMode mode) {
+ push<DrawColorOp>(color, mode);
}
-void RecordPaintCanvas::clear(SkColor color) {
- push<DrawColorOp>(SkColor4f::FromColor(color), SkBlendMode::kSrc);
+void RecordPaintCanvas::clear(SkColor4f color) {
+ push<DrawColorOp>(color, SkBlendMode::kSrc);
}
void RecordPaintCanvas::drawLine(SkScalar x0,
diff --git a/chromium/cc/paint/record_paint_canvas.h b/chromium/cc/paint/record_paint_canvas.h
index 31d36d54b60..cda8ce7ad82 100644
--- a/chromium/cc/paint/record_paint_canvas.h
+++ b/chromium/cc/paint/record_paint_canvas.h
@@ -63,8 +63,8 @@ class CC_PAINT_EXPORT RecordPaintCanvas : public PaintCanvas {
bool getLocalClipBounds(SkRect* bounds) const override;
SkIRect getDeviceClipBounds() const override;
bool getDeviceClipBounds(SkIRect* bounds) const override;
- void drawColor(SkColor color, SkBlendMode mode) override;
- void clear(SkColor color) override;
+ void drawColor(SkColor4f color, SkBlendMode mode) override;
+ void clear(SkColor4f color) override;
void drawLine(SkScalar x0,
SkScalar y0,
diff --git a/chromium/cc/paint/scoped_raster_flags.cc b/chromium/cc/paint/scoped_raster_flags.cc
index 171b5514ae3..b6260303e7a 100644
--- a/chromium/cc/paint/scoped_raster_flags.cc
+++ b/chromium/cc/paint/scoped_raster_flags.cc
@@ -4,41 +4,14 @@
#include "cc/paint/scoped_raster_flags.h"
+#include <utility>
+
#include "cc/paint/image_provider.h"
#include "cc/paint/image_transfer_cache_entry.h"
#include "cc/paint/paint_filter.h"
#include "cc/paint/paint_image_builder.h"
namespace cc {
-ScopedRasterFlags::ScopedRasterFlags(const PaintFlags* flags,
- ImageProvider* image_provider,
- const SkMatrix& ctm,
- int max_texture_size,
- uint8_t alpha)
- : original_flags_(flags) {
- if (image_provider) {
- decode_stashing_image_provider_.emplace(image_provider);
-
- // We skip the op if any images fail to decode.
- DecodeImageShader(ctm);
- if (decode_failed_)
- return;
- DecodeRecordShader(ctm, max_texture_size);
- if (decode_failed_)
- return;
- DecodeFilter();
- if (decode_failed_)
- return;
- }
-
- if (alpha != 255) {
- DCHECK(flags->SupportsFoldingAlpha());
- MutableFlags()->setAlpha(SkMulDiv255Round(flags->getAlpha(), alpha));
- }
-
- AdjustStrokeIfNeeded(ctm);
-}
-
ScopedRasterFlags::~ScopedRasterFlags() = default;
void ScopedRasterFlags::DecodeImageShader(const SkMatrix& ctm) {
diff --git a/chromium/cc/paint/scoped_raster_flags.h b/chromium/cc/paint/scoped_raster_flags.h
index 792cbc19fdd..0c2dcf01254 100644
--- a/chromium/cc/paint/scoped_raster_flags.h
+++ b/chromium/cc/paint/scoped_raster_flags.h
@@ -18,11 +18,35 @@ namespace cc {
class CC_PAINT_EXPORT ScopedRasterFlags {
public:
// |flags| and |image_provider| must outlive this class.
+ template <class F, class = std::enable_if_t<std::is_same_v<F, float>>>
ScopedRasterFlags(const PaintFlags* flags,
ImageProvider* image_provider,
const SkMatrix& ctm,
int max_texture_size,
- uint8_t alpha);
+ F alpha)
+ : original_flags_(flags) {
+ if (image_provider) {
+ decode_stashing_image_provider_.emplace(image_provider);
+
+ // We skip the op if any images fail to decode.
+ DecodeImageShader(ctm);
+ if (decode_failed_)
+ return;
+ DecodeRecordShader(ctm, max_texture_size);
+ if (decode_failed_)
+ return;
+ DecodeFilter();
+ if (decode_failed_)
+ return;
+ }
+
+ if (alpha != 1.0f) {
+ DCHECK(flags->SupportsFoldingAlpha());
+ MutableFlags()->setAlphaf(flags->getAlphaf() * alpha);
+ }
+
+ AdjustStrokeIfNeeded(ctm);
+ }
ScopedRasterFlags(const ScopedRasterFlags&) = delete;
~ScopedRasterFlags();
diff --git a/chromium/cc/paint/scoped_raster_flags_unittest.cc b/chromium/cc/paint/scoped_raster_flags_unittest.cc
index 232bf0ed06b..78e1f3e616c 100644
--- a/chromium/cc/paint/scoped_raster_flags_unittest.cc
+++ b/chromium/cc/paint/scoped_raster_flags_unittest.cc
@@ -81,7 +81,7 @@ TEST(ScopedRasterFlagsTest, DecodePaintWorkletImageShader) {
flags.setShader(shader);
MockPaintWorkletImageProvider provider;
- ScopedRasterFlags scoped_flags(&flags, &provider, SkMatrix::I(), 0, 255);
+ ScopedRasterFlags scoped_flags(&flags, &provider, SkMatrix::I(), 0, 1.0f);
ASSERT_TRUE(scoped_flags.flags());
EXPECT_TRUE(scoped_flags.flags()->getShader()->shader_type() ==
PaintShader::Type::kPaintRecord);
@@ -104,7 +104,7 @@ TEST(ScopedRasterFlagsTest, KeepsDecodesAlive) {
PaintFlags flags;
flags.setShader(record_shader);
{
- ScopedRasterFlags scoped_flags(&flags, &provider, SkMatrix::I(), 0, 255);
+ ScopedRasterFlags scoped_flags(&flags, &provider, SkMatrix::I(), 0, 1.0f);
ASSERT_TRUE(scoped_flags.flags());
EXPECT_NE(scoped_flags.flags(), &flags);
SkPaint paint = scoped_flags.flags()->ToSkPaint();
@@ -116,13 +116,13 @@ TEST(ScopedRasterFlagsTest, KeepsDecodesAlive) {
TEST(ScopedRasterFlagsTest, NoImageProvider) {
PaintFlags flags;
- flags.setAlpha(255);
+ flags.setAlphaf(1.0f);
flags.setShader(PaintShader::MakeImage(
CreateDiscardablePaintImage(gfx::Size(10, 10)), SkTileMode::kClamp,
SkTileMode::kClamp, &SkMatrix::I()));
- ScopedRasterFlags scoped_flags(&flags, nullptr, SkMatrix::I(), 0, 10);
+ ScopedRasterFlags scoped_flags(&flags, nullptr, SkMatrix::I(), 0, 0.1f);
EXPECT_NE(scoped_flags.flags(), &flags);
- EXPECT_EQ(scoped_flags.flags()->getAlpha(), SkMulDiv255Round(255, 10));
+ EXPECT_EQ(scoped_flags.flags()->getAlphaf(), 1.0f * 0.1f);
}
TEST(ScopedRasterFlagsTest, ThinAliasedStroke) {
@@ -133,21 +133,21 @@ TEST(ScopedRasterFlagsTest, ThinAliasedStroke) {
struct {
SkMatrix ctm;
- uint8_t alpha;
+ float alpha;
bool expect_same_flags;
bool expect_aa;
float expect_stroke_width;
- uint8_t expect_alpha;
+ float expect_alpha;
} tests[] = {
// No downscaling => no stroke change.
- {SkMatrix::Scale(1.0f, 1.0f), 255, true, false, 1.0f, 0xFF},
+ {SkMatrix::Scale(1.0f, 1.0f), 1.0f, true, false, 1.0f, 1.0f},
// Symmetric downscaling => modulated hairline stroke.
- {SkMatrix::Scale(0.5f, 0.5f), 255, false, false, 0.0f, 0x80},
+ {SkMatrix::Scale(0.5f, 0.5f), 1.0f, false, false, 0.0f, 0.5f},
// Symmetric downscaling w/ alpha => modulated hairline stroke.
- {SkMatrix::Scale(0.5f, 0.5f), 127, false, false, 0.0f, 0x40},
+ {SkMatrix::Scale(0.5f, 0.5f), 0.5f, false, false, 0.0f, 0.25f},
// Anisotropic scaling => AA stroke.
- {SkMatrix::Scale(0.5f, 1.5f), 255, false, true, 1.0f, 0xFF},
+ {SkMatrix::Scale(0.5f, 1.5f), 1.0f, false, true, 1.0f, 1.0f},
};
for (const auto& test : tests) {
@@ -157,7 +157,8 @@ TEST(ScopedRasterFlagsTest, ThinAliasedStroke) {
EXPECT_EQ(scoped_flags.flags() == &flags, test.expect_same_flags);
EXPECT_EQ(scoped_flags.flags()->isAntiAlias(), test.expect_aa);
EXPECT_EQ(scoped_flags.flags()->getStrokeWidth(), test.expect_stroke_width);
- EXPECT_EQ(scoped_flags.flags()->getAlpha(), test.expect_alpha);
+ EXPECT_LE(std::abs(scoped_flags.flags()->getAlphaf() - test.expect_alpha),
+ 0.01f);
}
}
diff --git a/chromium/cc/paint/skia_paint_canvas.cc b/chromium/cc/paint/skia_paint_canvas.cc
index d90b124fb79..bd49fa4cc1f 100644
--- a/chromium/cc/paint/skia_paint_canvas.cc
+++ b/chromium/cc/paint/skia_paint_canvas.cc
@@ -160,11 +160,11 @@ bool SkiaPaintCanvas::getDeviceClipBounds(SkIRect* bounds) const {
return canvas_->getDeviceClipBounds(bounds);
}
-void SkiaPaintCanvas::drawColor(SkColor color, SkBlendMode mode) {
+void SkiaPaintCanvas::drawColor(SkColor4f color, SkBlendMode mode) {
canvas_->drawColor(color, mode);
}
-void SkiaPaintCanvas::clear(SkColor color) {
+void SkiaPaintCanvas::clear(SkColor4f color) {
canvas_->clear(color);
}
@@ -175,7 +175,7 @@ void SkiaPaintCanvas::drawLine(SkScalar x0,
const PaintFlags& flags) {
ScopedRasterFlags raster_flags(&flags, image_provider_,
canvas_->getTotalMatrix(), GetMaxTextureSize(),
- 255u);
+ 1.0f);
if (!raster_flags.flags())
return;
@@ -189,7 +189,7 @@ void SkiaPaintCanvas::drawLine(SkScalar x0,
void SkiaPaintCanvas::drawRect(const SkRect& rect, const PaintFlags& flags) {
ScopedRasterFlags raster_flags(&flags, image_provider_,
canvas_->getTotalMatrix(), GetMaxTextureSize(),
- 255u);
+ 1.0f);
if (!raster_flags.flags())
return;
raster_flags.flags()->DrawToSk(
@@ -201,7 +201,7 @@ void SkiaPaintCanvas::drawRect(const SkRect& rect, const PaintFlags& flags) {
void SkiaPaintCanvas::drawIRect(const SkIRect& rect, const PaintFlags& flags) {
ScopedRasterFlags raster_flags(&flags, image_provider_,
canvas_->getTotalMatrix(), GetMaxTextureSize(),
- 255u);
+ 1.0f);
if (!raster_flags.flags())
return;
raster_flags.flags()->DrawToSk(
@@ -213,7 +213,7 @@ void SkiaPaintCanvas::drawIRect(const SkIRect& rect, const PaintFlags& flags) {
void SkiaPaintCanvas::drawOval(const SkRect& oval, const PaintFlags& flags) {
ScopedRasterFlags raster_flags(&flags, image_provider_,
canvas_->getTotalMatrix(), GetMaxTextureSize(),
- 255u);
+ 1.0f);
if (!raster_flags.flags())
return;
raster_flags.flags()->DrawToSk(
@@ -225,7 +225,7 @@ void SkiaPaintCanvas::drawOval(const SkRect& oval, const PaintFlags& flags) {
void SkiaPaintCanvas::drawRRect(const SkRRect& rrect, const PaintFlags& flags) {
ScopedRasterFlags raster_flags(&flags, image_provider_,
canvas_->getTotalMatrix(), GetMaxTextureSize(),
- 255u);
+ 1.0f);
if (!raster_flags.flags())
return;
raster_flags.flags()->DrawToSk(
@@ -239,7 +239,7 @@ void SkiaPaintCanvas::drawDRRect(const SkRRect& outer,
const PaintFlags& flags) {
ScopedRasterFlags raster_flags(&flags, image_provider_,
canvas_->getTotalMatrix(), GetMaxTextureSize(),
- 255u);
+ 1.0f);
if (!raster_flags.flags())
return;
raster_flags.flags()->DrawToSk(
@@ -255,7 +255,7 @@ void SkiaPaintCanvas::drawRoundRect(const SkRect& rect,
const PaintFlags& flags) {
ScopedRasterFlags raster_flags(&flags, image_provider_,
canvas_->getTotalMatrix(), GetMaxTextureSize(),
- 255u);
+ 1.0f);
if (!raster_flags.flags())
return;
raster_flags.flags()->DrawToSk(
@@ -270,7 +270,7 @@ void SkiaPaintCanvas::drawPath(const SkPath& path,
UsePaintCache) {
ScopedRasterFlags raster_flags(&flags, image_provider_,
canvas_->getTotalMatrix(), GetMaxTextureSize(),
- 255u);
+ 1.0f);
if (!raster_flags.flags())
return;
raster_flags.flags()->DrawToSk(
@@ -288,7 +288,7 @@ void SkiaPaintCanvas::drawImage(const PaintImage& image,
absl::optional<ScopedRasterFlags> scoped_flags;
if (flags) {
scoped_flags.emplace(flags, image_provider_, canvas_->getTotalMatrix(),
- GetMaxTextureSize(), 255u);
+ GetMaxTextureSize(), 1.0f);
if (!scoped_flags->flags())
return;
}
@@ -309,7 +309,7 @@ void SkiaPaintCanvas::drawImageRect(const PaintImage& image,
absl::optional<ScopedRasterFlags> scoped_flags;
if (flags) {
scoped_flags.emplace(flags, image_provider_, canvas_->getTotalMatrix(),
- GetMaxTextureSize(), 255u);
+ GetMaxTextureSize(), 1.0f);
if (!scoped_flags->flags())
return;
}
@@ -347,7 +347,7 @@ void SkiaPaintCanvas::drawTextBlob(sk_sp<SkTextBlob> blob,
const PaintFlags& flags) {
ScopedRasterFlags raster_flags(&flags, image_provider_,
canvas_->getTotalMatrix(), GetMaxTextureSize(),
- 255u);
+ 1.0f);
if (!raster_flags.flags())
return;
raster_flags.flags()->DrawToSk(canvas_,
diff --git a/chromium/cc/paint/skia_paint_canvas.h b/chromium/cc/paint/skia_paint_canvas.h
index e4f8131228f..09e7d3b8f9f 100644
--- a/chromium/cc/paint/skia_paint_canvas.h
+++ b/chromium/cc/paint/skia_paint_canvas.h
@@ -103,8 +103,8 @@ class CC_PAINT_EXPORT SkiaPaintCanvas final : public PaintCanvas {
bool getLocalClipBounds(SkRect* bounds) const override;
SkIRect getDeviceClipBounds() const override;
bool getDeviceClipBounds(SkIRect* bounds) const override;
- void drawColor(SkColor color, SkBlendMode mode) override;
- void clear(SkColor color) override;
+ void drawColor(SkColor4f color, SkBlendMode mode) override;
+ void clear(SkColor4f color) override;
void drawLine(SkScalar x0,
SkScalar y0,
diff --git a/chromium/cc/paint/skia_paint_image_generator.cc b/chromium/cc/paint/skia_paint_image_generator.cc
index a49188fd299..37df37e1e02 100644
--- a/chromium/cc/paint/skia_paint_image_generator.cc
+++ b/chromium/cc/paint/skia_paint_image_generator.cc
@@ -41,8 +41,8 @@ bool SkiaPaintImageGenerator::onQueryYUVAInfo(
}
bool SkiaPaintImageGenerator::onGetYUVAPlanes(const SkYUVAPixmaps& planes) {
- return paint_image_generator_->GetYUVAPlanes(planes, frame_index_,
- uniqueID());
+ return paint_image_generator_->GetYUVAPlanes(planes, frame_index_, uniqueID(),
+ client_id_);
}
} // namespace cc
diff --git a/chromium/cc/paint/skottie_wrapper_impl.cc b/chromium/cc/paint/skottie_wrapper_impl.cc
index 703575304f0..85901b8d48e 100644
--- a/chromium/cc/paint/skottie_wrapper_impl.cc
+++ b/chromium/cc/paint/skottie_wrapper_impl.cc
@@ -295,6 +295,7 @@ class SkottieWrapperImpl : public SkottieWrapper {
void Seek(float t, FrameDataCallback frame_data_cb) override
LOCKS_EXCLUDED(lock_) {
+ TRACE_EVENT1("cc", "SkottieWrapperImpl::Seek", "timestamp", t);
base::AutoLock lock(lock_);
// There's no need to reset |current_frame_data_cb_| to null when finished.
// The callback is guaranteed to only be invoked synchronously during calls
@@ -310,6 +311,7 @@ class SkottieWrapperImpl : public SkottieWrapper {
const SkottieColorMap& color_map,
const SkottieTextPropertyValueMap& text_map) override
LOCKS_EXCLUDED(lock_) {
+ TRACE_EVENT1("cc", "SkottieWrapperImpl::Draw", "timestamp", t);
base::AutoLock lock(lock_);
current_frame_data_cb_ = std::move(frame_data_cb);
property_manager_->color_property_manager().SetNewValues(color_map);
diff --git a/chromium/cc/paint/solid_color_analyzer_unittest.cc b/chromium/cc/paint/solid_color_analyzer_unittest.cc
index a343e1d4cc5..aac6c8a4f9b 100644
--- a/chromium/cc/paint/solid_color_analyzer_unittest.cc
+++ b/chromium/cc/paint/solid_color_analyzer_unittest.cc
@@ -81,21 +81,21 @@ TEST_F(SolidColorAnalyzerTest, Empty) {
TEST_F(SolidColorAnalyzerTest, ClearTransparent) {
Initialize();
SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(0, 12, 34, 56));
- canvas()->clear(color.toSkColor());
+ canvas()->clear(color);
EXPECT_EQ(SkColors::kTransparent, GetColor());
}
TEST_F(SolidColorAnalyzerTest, ClearSolid) {
Initialize();
SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 65, 43, 21));
- canvas()->clear(color.toSkColor());
+ canvas()->clear(color);
EXPECT_EQ(color, GetColor());
}
TEST_F(SolidColorAnalyzerTest, ClearTranslucent) {
Initialize();
SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(128, 11, 22, 33));
- canvas()->clear(color.toSkColor());
+ canvas()->clear(color);
#if BUILDFLAG(IS_MAC)
// TODO(andrescj): remove the special treatment of OS_MAC once
// https://crbug.com/922899 is fixed.
@@ -108,7 +108,7 @@ TEST_F(SolidColorAnalyzerTest, ClearTranslucent) {
TEST_F(SolidColorAnalyzerTest, DrawColor) {
Initialize();
SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33));
- canvas()->drawColor(color.toSkColor());
+ canvas()->drawColor(color);
EXPECT_EQ(color, GetColor());
}
@@ -197,8 +197,8 @@ TEST_F(SolidColorAnalyzerTest, DrawRectWithTranslateSolid) {
TEST_F(SolidColorAnalyzerTest, TwoOpsNotSolid) {
Initialize();
SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 65, 43, 21));
- canvas()->clear(color.toSkColor());
- canvas()->clear(color.toSkColor());
+ canvas()->clear(color);
+ canvas()->clear(color);
EXPECT_FALSE(IsSolidColor());
}
diff --git a/chromium/cc/paint/target_color_params.cc b/chromium/cc/paint/target_color_params.cc
index 0bdad5f4170..fcfdd27c48e 100644
--- a/chromium/cc/paint/target_color_params.cc
+++ b/chromium/cc/paint/target_color_params.cc
@@ -15,16 +15,19 @@ size_t TargetColorParams::GetHash() const {
reinterpret_cast<const uint32_t*>(&hdr_max_luminance_relative);
const uint32_t* sdr_max_luminance_nits_int =
reinterpret_cast<const uint32_t*>(&sdr_max_luminance_nits);
- return base::HashInts(color_space.GetHash(),
- base::HashInts(*hdr_max_luminance_relative_int,
- *sdr_max_luminance_nits_int));
+ size_t hash = color_space.GetHash();
+ hash = base::HashInts(hash, *hdr_max_luminance_relative_int);
+ hash = base::HashInts(hash, *sdr_max_luminance_nits_int);
+ hash = base::HashInts(hash, enable_tone_mapping);
+ return hash;
}
std::string TargetColorParams::ToString() const {
std::ostringstream str;
str << "color_space: " << color_space.ToString()
<< "sdr_max_luminance_nits: " << sdr_max_luminance_nits
- << "hdr_max_luminance_relative: " << hdr_max_luminance_relative;
+ << "hdr_max_luminance_relative: " << hdr_max_luminance_relative
+ << "enable_tone_mapping: " << enable_tone_mapping;
return str.str();
}
diff --git a/chromium/cc/paint/target_color_params.h b/chromium/cc/paint/target_color_params.h
index f4eb00b83c1..f7189d51a59 100644
--- a/chromium/cc/paint/target_color_params.h
+++ b/chromium/cc/paint/target_color_params.h
@@ -33,6 +33,9 @@ struct CC_PAINT_EXPORT TargetColorParams {
// luminance (a non-HDR-capable display will have a value of 1).
float hdr_max_luminance_relative = 1.f;
+ // Whether or not tone mapping should be applied.
+ bool enable_tone_mapping = true;
+
bool operator==(const TargetColorParams& other) const {
return color_space == other.color_space &&
sdr_max_luminance_nits == other.sdr_max_luminance_nits &&
diff --git a/chromium/cc/raster/gpu_raster_buffer_provider.cc b/chromium/cc/raster/gpu_raster_buffer_provider.cc
index bf0d9d7b2d4..f77c3ae2492 100644
--- a/chromium/cc/raster/gpu_raster_buffer_provider.cc
+++ b/chromium/cc/raster/gpu_raster_buffer_provider.cc
@@ -150,8 +150,7 @@ GpuRasterBufferProvider::GpuRasterBufferProvider(
tile_format_(tile_format),
max_tile_size_(max_tile_size),
pending_raster_queries_(pending_raster_queries),
- random_generator_(static_cast<uint32_t>(base::RandUint64())),
- bernoulli_distribution_(raster_metric_probability),
+ raster_metric_probability_(raster_metric_probability),
is_using_raw_draw_(features::IsUsingRawDraw()) {
DCHECK(pending_raster_queries);
DCHECK(compositor_context_provider);
@@ -288,8 +287,8 @@ void GpuRasterBufferProvider::RasterBufferImpl::PlaybackOnWorkerThreadInternal(
client_->worker_context_provider_->RasterInterface();
DCHECK(ri);
- const bool measure_raster_metric =
- client_->bernoulli_distribution_(client_->random_generator_);
+ const bool measure_raster_metric = client_->metrics_subsampler_.ShouldSample(
+ client_->raster_metric_probability_);
gfx::Rect playback_rect = raster_full_rect;
if (resource_has_previous_content_) {
@@ -412,8 +411,8 @@ void GpuRasterBufferProvider::RasterBufferImpl::RasterizeSource(
"Gpu.Rasterization.Raster.NumPaintOps",
raster_source->GetDisplayItemList()->num_paint_ops());
UMA_HISTOGRAM_COUNTS_100(
- "Gpu.Rasterization.Raster.NumSlowPaths",
- raster_source->GetDisplayItemList()->num_slow_paths());
+ "Gpu.Rasterization.Raster.NumSlowPathsUpToMinForMSAA",
+ raster_source->GetDisplayItemList()->num_slow_paths_up_to_min_for_MSAA());
ri->EndRasterCHROMIUM();
// TODO(ericrk): Handle unpremultiply+dither for 4444 cases.
diff --git a/chromium/cc/raster/gpu_raster_buffer_provider.h b/chromium/cc/raster/gpu_raster_buffer_provider.h
index f8ca6f9f656..30eb7a0e06f 100644
--- a/chromium/cc/raster/gpu_raster_buffer_provider.h
+++ b/chromium/cc/raster/gpu_raster_buffer_provider.h
@@ -7,10 +7,10 @@
#include <stdint.h>
#include <memory>
-#include <random>
#include <vector>
#include "base/memory/raw_ptr.h"
+#include "base/rand_util.h"
#include "base/time/time.h"
#include "cc/raster/raster_buffer_provider.h"
#include "cc/raster/raster_query_queue.h"
@@ -145,9 +145,9 @@ class CC_EXPORT GpuRasterBufferProvider : public RasterBufferProvider {
const raw_ptr<RasterQueryQueue> pending_raster_queries_;
+ const double raster_metric_probability_;
// Accessed with the worker context lock acquired.
- std::mt19937 random_generator_;
- std::bernoulli_distribution bernoulli_distribution_;
+ base::MetricsSubSampler metrics_subsampler_;
const bool is_using_raw_draw_;
};
diff --git a/chromium/cc/raster/raster_source.cc b/chromium/cc/raster/raster_source.cc
index 42f1a147ec5..dfe4361c5a5 100644
--- a/chromium/cc/raster/raster_source.cc
+++ b/chromium/cc/raster/raster_source.cc
@@ -181,9 +181,9 @@ bool RasterSource::IsSolidColor() const {
return is_solid_color_;
}
-SkColor RasterSource::GetSolidColor() const {
+SkColor4f RasterSource::GetSolidColor() const {
DCHECK(IsSolidColor());
- return solid_color_.toSkColor();
+ return solid_color_;
}
bool RasterSource::HasRecordings() const {
diff --git a/chromium/cc/raster/raster_source.h b/chromium/cc/raster/raster_source.h
index 9e0fc1b719e..a7cc8567ed0 100644
--- a/chromium/cc/raster/raster_source.h
+++ b/chromium/cc/raster/raster_source.h
@@ -88,7 +88,7 @@ class CC_EXPORT RasterSource : public base::RefCountedThreadSafe<RasterSource> {
// Returns the color of the raster source if it is solid color. The results
// are unspecified if IsSolidColor returns false.
- SkColor GetSolidColor() const;
+ SkColor4f GetSolidColor() const;
// Returns the recorded layer size of this raster source.
gfx::Size GetSize() const;
diff --git a/chromium/cc/raster/tile_task.cc b/chromium/cc/raster/tile_task.cc
index f0c1574663a..d4bc5c153b4 100644
--- a/chromium/cc/raster/tile_task.cc
+++ b/chromium/cc/raster/tile_task.cc
@@ -31,4 +31,14 @@ bool TileTask::HasCompleted() const {
return did_complete_;
}
+bool TileTask::TaskContainsLCPCandidateImages() const {
+ for (auto dependent : dependencies_) {
+ if (!dependent->HasCompleted() &&
+ dependent->TaskContainsLCPCandidateImages()) {
+ return true;
+ }
+ }
+ return false;
+}
+
} // namespace cc
diff --git a/chromium/cc/raster/tile_task.h b/chromium/cc/raster/tile_task.h
index d835dbe26f2..7544e234f59 100644
--- a/chromium/cc/raster/tile_task.h
+++ b/chromium/cc/raster/tile_task.h
@@ -35,6 +35,10 @@ class CC_EXPORT TileTask : public Task {
// of the task.
virtual void OnTaskCompleted() = 0;
+ // This method should report true if the task contains image decodes that
+ // might be for LCP candidates.
+ virtual bool TaskContainsLCPCandidateImages() const;
+
void DidComplete();
bool HasCompleted() const;
diff --git a/chromium/cc/resources/scoped_ui_resource.h b/chromium/cc/resources/scoped_ui_resource.h
index 716741c898a..e0a11045e58 100644
--- a/chromium/cc/resources/scoped_ui_resource.h
+++ b/chromium/cc/resources/scoped_ui_resource.h
@@ -40,6 +40,8 @@ class CC_EXPORT ScopedUIResource : public UIResourceClient {
// Returns the memory usage of the bitmap.
size_t EstimateMemoryUsage() const { return bitmap_.SizeInBytes(); }
+ bool IsUniquelyOwned() const { return bitmap_.IsUniquelyOwned(); }
+
protected:
ScopedUIResource(UIResourceManager* ui_resource_manager,
const UIResourceBitmap& bitmap);
diff --git a/chromium/cc/resources/ui_resource_bitmap.cc b/chromium/cc/resources/ui_resource_bitmap.cc
index ca32943d825..b917278724c 100644
--- a/chromium/cc/resources/ui_resource_bitmap.cc
+++ b/chromium/cc/resources/ui_resource_bitmap.cc
@@ -79,7 +79,11 @@ UIResourceBitmap::UIResourceBitmap(const SkBitmap& skbitmap) {
SkBitmap copy;
if (features::IsDrDcEnabled()) {
// TODO(vikassoni): Forcing everything to N32 while android backing cannot
- // support some other formats.
+ // support some other formats. Note that DrDc is disabled on some gl
+ // renderers and hence gpus via gpu driver bug workaround. That workaround
+ // is not applied here and so on those disable gpus, everything will still
+ // be forced to N32 even though drdc is disabled. This should be fine for
+ // now and would be fixed later. crbug.com/1354201.
if (skbitmap.colorType() != kN32_SkColorType) {
SkImageInfo new_info = skbitmap.info().makeColorType(kN32_SkColorType);
copy.allocPixels(new_info, new_info.minRowBytes());
diff --git a/chromium/cc/resources/ui_resource_bitmap.h b/chromium/cc/resources/ui_resource_bitmap.h
index a919811f9bc..73082cb9faa 100644
--- a/chromium/cc/resources/ui_resource_bitmap.h
+++ b/chromium/cc/resources/ui_resource_bitmap.h
@@ -52,6 +52,8 @@ class CC_EXPORT UIResourceBitmap {
size_t SizeInBytes() const;
size_t row_bytes() const { return pixel_ref_ ? pixel_ref_->rowBytes() : 0; }
+ bool IsUniquelyOwned() const { return pixel_ref_->unique(); }
+
private:
friend class AutoLockUIResourceBitmap;
diff --git a/chromium/cc/resources/ui_resource_manager.cc b/chromium/cc/resources/ui_resource_manager.cc
index 83cfdccbade..e0d184eda7d 100644
--- a/chromium/cc/resources/ui_resource_manager.cc
+++ b/chromium/cc/resources/ui_resource_manager.cc
@@ -7,6 +7,8 @@
#include <algorithm>
#include <utility>
+#include "base/check.h"
+#include "base/containers/cxx20_erase.h"
#include "cc/resources/scoped_ui_resource.h"
namespace cc {
@@ -65,10 +67,11 @@ void UIResourceManager::RecreateUIResources() {
base::flat_map<UIResourceId, gfx::Size> UIResourceManager::GetUIResourceSizes()
const {
- base::flat_map<UIResourceId, gfx::Size> result;
+ base::flat_map<UIResourceId, gfx::Size>::container_type items(
+ ui_resource_client_map_.size());
for (const auto pair : ui_resource_client_map_)
- result.emplace(pair.first, pair.second.size);
- return result;
+ items.push_back({pair.first, pair.second.size});
+ return base::flat_map<UIResourceId, gfx::Size>(std::move(items));
}
std::vector<UIResourceRequest> UIResourceManager::TakeUIResourcesRequests() {
@@ -83,6 +86,18 @@ UIResourceId UIResourceManager::GetOrCreateUIResource(const SkBitmap& bitmap) {
if (resource != owned_shared_resources_.end())
return resource->second->id();
+ // Evict all UIResources whose bitmaps are no longer referenced outside of the
+ // map.
+ base::EraseIf(owned_shared_resources_,
+ [](auto& pair) { return pair.second->IsUniquelyOwned(); });
+
+ // Max capacity of `owned_shared_resources_`. A DCHECK() would fire if cache
+ // size after eviction does not fall below the limit. 256 is an arbitrarily
+ // chosen number that is greater than the max number of images we expect to
+ // ever use concurrently.
+ constexpr size_t kMaxSkBitmapResources = 256u;
+ DCHECK_LT(owned_shared_resources_.size(), kMaxSkBitmapResources);
+
auto scoped_resource =
ScopedUIResource::Create(this, UIResourceBitmap(bitmap));
auto id = scoped_resource->id();
diff --git a/chromium/cc/resources/ui_resource_manager.h b/chromium/cc/resources/ui_resource_manager.h
index cf18142a115..1806a8f6c40 100644
--- a/chromium/cc/resources/ui_resource_manager.h
+++ b/chromium/cc/resources/ui_resource_manager.h
@@ -16,6 +16,15 @@
namespace cc {
class ScopedUIResource;
+// UIResourceManager creates and manages UIResourceBitmaps and UIResourceIDs
+// for given bitmaps for a LayerTreeHost. There are two ways to use the
+// interface:
+// 1. `CreateUIResource`/`DeleteUIResource` to explicitly manage the lifetime
+// of UIResources.
+// 2. `GetOrCreateUIResource` to create shared UIResources backed by the same
+// SkBitmap (SkPixelRef to be exact). The created UIResources are owned by
+// the manager and are released when all references outside the manager's
+// map are dropped.
class CC_EXPORT UIResourceManager {
public:
UIResourceManager();
@@ -46,10 +55,16 @@ class CC_EXPORT UIResourceManager {
// were evicted on the impl thread.
void RecreateUIResources();
- // Creates a resource given an SkBitmap. Multiple calls with bitmaps that
- // share the same SkPixelRef will share a single resource ID.
+ // Creates a resource given a SkBitmap. Multiple calls with bitmaps that
+ // share the same SkPixelRef will share a single resource ID. The returned
+ // `UIResourceId` will only be valid as long as something else holds a
+ // reference to the SkBitmap
UIResourceId GetOrCreateUIResource(const SkBitmap& bitmap);
+ size_t owned_shared_resources_size_for_test() const {
+ return owned_shared_resources_.size();
+ }
+
private:
struct UIResourceClientData {
UIResourceClient* client;
@@ -64,9 +79,8 @@ class CC_EXPORT UIResourceManager {
UIResourceRequestQueue ui_resource_request_queue_;
// A map from bitmaps to the ScopedUIResource we've created for them. The
- // resources are never released over the duration of the lifetime of |this|.
- // If you want to release a resource added here, add a function (or extend
- // DeleteUIResource).
+ // resources are released when all references of SkPixelRefs outside the map
+ // are dropped.
std::unordered_map<SkPixelRef*, std::unique_ptr<ScopedUIResource>>
owned_shared_resources_;
};
diff --git a/chromium/cc/scheduler/commit_earlyout_reason.h b/chromium/cc/scheduler/commit_earlyout_reason.h
index 7fe59e45962..050da072348 100644
--- a/chromium/cc/scheduler/commit_earlyout_reason.h
+++ b/chromium/cc/scheduler/commit_earlyout_reason.h
@@ -32,7 +32,7 @@ inline const char* CommitEarlyOutReasonToString(CommitEarlyOutReason reason) {
return "???";
}
-inline bool CommitEarlyOutHandledCommit(CommitEarlyOutReason reason) {
+inline bool MainFrameAppliedDeltas(CommitEarlyOutReason reason) {
return reason == CommitEarlyOutReason::FINISHED_NO_UPDATES;
}
diff --git a/chromium/cc/scheduler/scheduler.h b/chromium/cc/scheduler/scheduler.h
index bf83e8447a7..1ace7b5b90e 100644
--- a/chromium/cc/scheduler/scheduler.h
+++ b/chromium/cc/scheduler/scheduler.h
@@ -296,7 +296,7 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase {
// Owned by LayerTreeHostImpl and is destroyed when LayerTreeHostImpl is
// destroyed.
- raw_ptr<CompositorFrameReportingController>
+ raw_ptr<CompositorFrameReportingController, DanglingUntriaged>
compositor_frame_reporting_controller_;
// What the latest deadline was, and when it was scheduled.
diff --git a/chromium/cc/tiles/gpu_image_decode_cache.cc b/chromium/cc/tiles/gpu_image_decode_cache.cc
index f9c24c2c0c5..4b5068986f3 100644
--- a/chromium/cc/tiles/gpu_image_decode_cache.cc
+++ b/chromium/cc/tiles/gpu_image_decode_cache.cc
@@ -27,6 +27,7 @@
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/memory_dump_manager.h"
#include "cc/base/devtools_instrumentation.h"
+#include "cc/base/features.h"
#include "cc/base/histograms.h"
#include "cc/base/switches.h"
#include "cc/paint/paint_flags.h"
@@ -551,7 +552,10 @@ class GpuImageDecodeTaskImpl : public TileTask {
const ImageDecodeCache::TracingInfo& tracing_info,
GpuImageDecodeCache::DecodeTaskType task_type)
: TileTask(TileTask::SupportsConcurrentExecution::kYes,
- TileTask::SupportsBackgroundThreadPriority::kYes),
+ (base::FeatureList::IsEnabled(
+ features::kNormalPriorityImageDecoding)
+ ? TileTask::SupportsBackgroundThreadPriority::kNo
+ : TileTask::SupportsBackgroundThreadPriority::kYes)),
cache_(cache),
image_(draw_image),
tracing_info_(tracing_info),
@@ -584,6 +588,13 @@ class GpuImageDecodeTaskImpl : public TileTask {
cache_->OnImageDecodeTaskCompleted(image_, task_type_);
}
+ // Overridden from TileTask:
+ bool TaskContainsLCPCandidateImages() const override {
+ if (!HasCompleted() && image_.paint_image().may_be_lcp_candidate())
+ return true;
+ return TileTask::TaskContainsLCPCandidateImages();
+ }
+
protected:
~GpuImageDecodeTaskImpl() override = default;
@@ -977,13 +988,12 @@ GpuImageDecodeCache::GpuImageDecodeCache(
SkColorType color_type,
size_t max_working_set_bytes,
int max_texture_size,
- PaintImage::GeneratorClientId generator_client_id,
RasterDarkModeFilter* const dark_mode_filter)
: color_type_(color_type),
use_transfer_cache_(use_transfer_cache),
context_(context),
max_texture_size_(max_texture_size),
- generator_client_id_(generator_client_id),
+ generator_client_id_(PaintImage::GetNextGeneratorClientId()),
enable_clipped_image_scaling_(
base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableClippedImageScaling)),
@@ -1582,6 +1592,8 @@ void GpuImageDecodeCache::OnImageDecodeTaskCompleted(
// Decode task is complete, remove our reference to it.
ImageData* image_data = GetImageDataForDrawImage(draw_image, cache_key);
DCHECK(image_data);
+ UMA_HISTOGRAM_BOOLEAN("Compositing.DecodeLCPCandidateImage.Hardware",
+ draw_image.paint_image().may_be_lcp_candidate());
if (task_type == DecodeTaskType::kPartOfUploadTask) {
DCHECK(image_data->decode.task);
image_data->decode.task = nullptr;
@@ -3015,16 +3027,12 @@ bool GpuImageDecodeCache::NeedsDarkModeFilterForTesting(
void GpuImageDecodeCache::OnMemoryPressure(
base::MemoryPressureListener::MemoryPressureLevel level) {
+ if (!ImageDecodeCacheUtils::ShouldEvictCaches(level))
+ return;
+
base::AutoLock lock(lock_);
- switch (level) {
- case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
- case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
- break;
- case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
- base::AutoReset<bool> reset(&aggressively_freeing_resources_, true);
- EnsureCapacity(0);
- break;
- }
+ base::AutoReset<bool> reset(&aggressively_freeing_resources_, true);
+ EnsureCapacity(0);
}
bool GpuImageDecodeCache::SupportsColorSpaceConversion() const {
diff --git a/chromium/cc/tiles/gpu_image_decode_cache.h b/chromium/cc/tiles/gpu_image_decode_cache.h
index c159315df72..c1625780abc 100644
--- a/chromium/cc/tiles/gpu_image_decode_cache.h
+++ b/chromium/cc/tiles/gpu_image_decode_cache.h
@@ -145,7 +145,6 @@ class CC_EXPORT GpuImageDecodeCache
SkColorType color_type,
size_t max_working_set_bytes,
int max_texture_size,
- PaintImage::GeneratorClientId client_id,
RasterDarkModeFilter* const dark_mode_filter);
~GpuImageDecodeCache() override;
diff --git a/chromium/cc/tiles/gpu_image_decode_cache_perftest.cc b/chromium/cc/tiles/gpu_image_decode_cache_perftest.cc
index 0e8bba94795..ac48ff8cc7f 100644
--- a/chromium/cc/tiles/gpu_image_decode_cache_perftest.cc
+++ b/chromium/cc/tiles/gpu_image_decode_cache_perftest.cc
@@ -55,8 +55,7 @@ class GpuImageDecodeCachePerfTest
ASSERT_EQ(result, gpu::ContextResult::kSuccess);
cache_ = std::make_unique<GpuImageDecodeCache>(
context_provider_.get(), UseTransferCache(), kRGBA_8888_SkColorType,
- kCacheSize, MaxTextureSize(), PaintImage::GetNextGeneratorClientId(),
- nullptr);
+ kCacheSize, MaxTextureSize(), nullptr);
}
protected:
diff --git a/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc b/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc
index b72b54d5569..4a97f9713e7 100644
--- a/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc
+++ b/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc
@@ -428,8 +428,7 @@ class GpuImageDecodeCacheTest
RasterDarkModeFilter* const dark_mode_filter = nullptr) {
return std::make_unique<GpuImageDecodeCache>(
context_provider_.get(), use_transfer_cache_, color_type_,
- memory_limit_bytes, max_texture_size_,
- PaintImage::GetNextGeneratorClientId(), dark_mode_filter);
+ memory_limit_bytes, max_texture_size_, dark_mode_filter);
}
// Returns dimensions for an image that will not fit in GPU memory and hence
diff --git a/chromium/cc/tiles/image_controller.cc b/chromium/cc/tiles/image_controller.cc
index 9fba377bf2c..1dec3e72d4e 100644
--- a/chromium/cc/tiles/image_controller.cc
+++ b/chromium/cc/tiles/image_controller.cc
@@ -4,66 +4,81 @@
#include "cc/tiles/image_controller.h"
+#include <utility>
+
#include "base/bind.h"
+#include "base/feature_list.h"
#include "base/task/task_traits.h"
-#include "base/threading/thread_restrictions.h"
#include "base/trace_event/trace_event.h"
#include "cc/base/completion_event.h"
#include "cc/tiles/tile_task_manager.h"
namespace cc {
+namespace {
+
+// When this feature is enabled, StopWorkerTasks() skips waiting synchronously
+// if no task is running.
+const base::Feature kImageControllerWaitOnlyForRunningTask{
+ "ImageControllerWaitOnlyForRunningTask", base::FEATURE_DISABLED_BY_DEFAULT};
+
+} // namespace
+
ImageController::ImageDecodeRequestId
ImageController::s_next_image_decode_queue_id_ = 1;
ImageController::ImageController(
- base::SequencedTaskRunner* origin_task_runner,
+ scoped_refptr<base::SequencedTaskRunner> origin_task_runner,
scoped_refptr<base::SequencedTaskRunner> worker_task_runner)
- : worker_task_runner_(std::move(worker_task_runner)),
- origin_task_runner_(origin_task_runner) {
- weak_ptr_ = weak_ptr_factory_.GetWeakPtr();
+ : worker_task_runner_(std::move(worker_task_runner)) {
+ worker_state_ = std::make_unique<WorkerState>(std::move(origin_task_runner),
+ weak_ptr_factory_.GetWeakPtr());
}
ImageController::~ImageController() {
StopWorkerTasks();
for (auto& request : orphaned_decode_requests_)
std::move(request.callback).Run(request.id, ImageDecodeResult::FAILURE);
+ if (worker_task_runner_) {
+ // Delete `worker_state_` on `worker_task_runner_` (or elsewhere via the
+ // callback's destructor if `worker_task_runner_` stopped accepting tasks).
+ worker_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce([](std::unique_ptr<WorkerState>) {},
+ std::move(worker_state_)));
+ }
}
+ImageController::WorkerState::WorkerState(
+ scoped_refptr<base::SequencedTaskRunner> origin_task_runner,
+ base::WeakPtr<ImageController> weak_ptr)
+ : origin_task_runner(std::move(origin_task_runner)), weak_ptr(weak_ptr) {}
+ImageController::WorkerState::~WorkerState() = default;
+
void ImageController::StopWorkerTasks() {
// We can't have worker threads without a cache_ or a worker_task_runner_, so
// terminate early.
if (!cache_ || !worker_task_runner_)
return;
- // Abort all tasks that are currently scheduled to run (we'll wait for them to
- // finish next).
- {
- base::AutoLock hold(lock_);
- abort_tasks_ = true;
+ base::AutoLock hold(worker_state_->lock);
+ worker_state_->abort_task = true;
+
+ // If a worker task is running (or if the "wait only for running task" feature
+ // is disabled), post a task and wait for its completion to "flush" the queue.
+ if (!base::FeatureList::IsEnabled(kImageControllerWaitOnlyForRunningTask) ||
+ worker_state_->task_state == WorkerTaskState::kRunningTask) {
+ base::AutoUnlock release(worker_state_->lock);
+ CompletionEvent completion_event;
+ worker_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&CompletionEvent::Signal,
+ base::Unretained(&completion_event)));
+ completion_event.Wait();
}
- // Post a task that will simply signal a completion event to ensure that we
- // "flush" any scheduled tasks (they will abort).
- CompletionEvent completion_event;
- worker_task_runner_->PostTask(
- FROM_HERE, base::BindOnce([](CompletionEvent* event) { event->Signal(); },
- base::Unretained(&completion_event)));
- completion_event.Wait();
+ DCHECK_EQ(worker_state_->task_state, WorkerTaskState::kNoTask);
// Reset the abort flag so that new tasks can be scheduled.
- {
- base::AutoLock hold(lock_);
- abort_tasks_ = false;
- }
-
- // Now that we flushed everything, if there was a task running and it
- // finished, it would have posted a completion callback back to the compositor
- // thread. We don't want that, so invalidate the weak ptrs again. Note that
- // nothing can start running between wait and this invalidate, since it would
- // only run on the current (compositor) thread.
- weak_ptr_factory_.InvalidateWeakPtrs();
- weak_ptr_ = weak_ptr_factory_.GetWeakPtr();
+ worker_state_->abort_task = false;
// Now, begin cleanup.
@@ -76,7 +91,7 @@ void ImageController::StopWorkerTasks() {
// Now, complete the tasks that already ran but haven't completed. These would
// be posted in the run loop, but since we invalidated the weak ptrs, we need
// to run everything manually.
- for (auto& request_to_complete : requests_needing_completion_) {
+ for (auto& request_to_complete : worker_state_->requests_needing_completion) {
ImageDecodeRequest& request = request_to_complete.second;
// The task (if one exists) would have run already, we just need to make
@@ -95,12 +110,12 @@ void ImageController::StopWorkerTasks() {
request.need_unref = false;
orphaned_decode_requests_.push_back(std::move(request));
}
- requests_needing_completion_.clear();
+ worker_state_->requests_needing_completion.clear();
// Finally, complete all of the tasks that never started running. This is
// similar to the |requests_needing_completion_|, but happens at a different
// stage in the pipeline.
- for (auto& request_pair : image_decode_queue_) {
+ for (auto& request_pair : worker_state_->image_decode_queue) {
ImageDecodeRequest& request = request_pair.second;
if (request.task) {
@@ -124,7 +139,7 @@ void ImageController::StopWorkerTasks() {
request.need_unref = false;
orphaned_decode_requests_.push_back(std::move(request));
}
- image_decode_queue_.clear();
+ worker_state_->image_decode_queue.clear();
}
void ImageController::SetImageDecodeCache(ImageDecodeCache* cache) {
@@ -238,20 +253,11 @@ ImageController::ImageDecodeRequestId ImageController::QueueImageDecode(
DCHECK(result.need_unref || !result.task);
// Schedule the task and signal that there is more work.
- base::AutoLock hold(lock_);
- image_decode_queue_[id] =
+ base::AutoLock hold(worker_state_->lock);
+ worker_state_->image_decode_queue[id] =
ImageDecodeRequest(id, draw_image, std::move(callback),
std::move(result.task), result.need_unref);
-
- // If this is the only image decode request, schedule a task to run.
- // Otherwise, the task will be scheduled in the previou task's completion.
- if (image_decode_queue_.size() == 1) {
- // Post a worker task.
- worker_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&ImageController::ProcessNextImageDecodeOnWorkerThread,
- base::Unretained(this)));
- }
+ ScheduleImageDecodeOnWorkerIfNeeded();
return id;
}
@@ -266,60 +272,71 @@ void ImageController::UnlockImageDecode(ImageDecodeRequestId id) {
requested_locked_images_.erase(it);
}
-void ImageController::ProcessNextImageDecodeOnWorkerThread() {
+// static
+void ImageController::ProcessNextImageDecodeOnWorkerThread(
+ WorkerState* worker_state) {
TRACE_EVENT0("cc", "ImageController::ProcessNextImageDecodeOnWorkerThread");
- scoped_refptr<TileTask> decode_task;
- ImageDecodeRequestId decode_id;
- {
- base::AutoLock hold(lock_);
- // If we don't have any work, abort.
- if (image_decode_queue_.empty() || abort_tasks_)
- return;
+ base::AutoLock hold(worker_state->lock);
+ DCHECK_EQ(worker_state->task_state, WorkerTaskState::kQueuedTask);
+ worker_state->task_state = WorkerTaskState::kRunningTask;
- // Take the next request from the queue.
- auto decode_it = image_decode_queue_.begin();
- DCHECK(decode_it != image_decode_queue_.end());
- decode_task = decode_it->second.task;
- decode_id = decode_it->second.id;
-
- // Notify that the task will need completion. Note that there are two cases
- // where we process this. First, we might complete this task as a response
- // to the posted task below. Second, we might complete it in
- // StopWorkerTasks(). In either case, the task would have already run
- // (either post task happens after running, or the thread was already joined
- // which means the task ran). This means that we can put the decode into
- // |requests_needing_completion_| here before actually running the task.
- requests_needing_completion_[decode_id] = std::move(decode_it->second);
-
- image_decode_queue_.erase(decode_it);
+ // If we don't have any work, abort.
+ if (worker_state->image_decode_queue.empty() || worker_state->abort_task) {
+ worker_state->task_state = WorkerTaskState::kNoTask;
+ return;
}
- // Run the task if we need to run it. If the task state isn't new, then
- // there is another task that is responsible for finishing it and cleaning
- // up (and it already ran); we just need to post a completion callback.
- // Note that the other tasks's completion will also run first, since the
- // requests are ordered. So, when we process this task's completion, we
- // won't actually do anything with the task and simply issue the callback.
+ // Take the next request from the queue.
+ auto decode_it = worker_state->image_decode_queue.begin();
+ DCHECK(decode_it != worker_state->image_decode_queue.end());
+ scoped_refptr<TileTask> decode_task = decode_it->second.task;
+ ImageDecodeRequestId decode_id = decode_it->second.id;
+
+ // Notify that the task will need completion. Note that there are two cases
+ // where we process this. First, we might complete this task as a response to
+ // the posted task below. Second, we might complete it in StopWorkerTasks().
+ // In either case, the task would have already run (either post task happens
+ // after running, or the thread was already joined which means the task ran).
+ // This means that we can put the decode into |requests_needing_completion_|
+ // here before actually running the task.
+ worker_state->requests_needing_completion[decode_id] =
+ std::move(decode_it->second);
+
+ worker_state->image_decode_queue.erase(decode_it);
+
+ // Run the task if we need to run it. If the task state isn't new, then there
+ // is another task that is responsible for finishing it and cleaning up (and
+ // it already ran); we just need to post a completion callback. Note that the
+ // other tasks's completion will also run first, since the requests are
+ // ordered. So, when we process this task's completion, we won't actually do
+ // anything with the task and simply issue the callback.
if (decode_task && decode_task->state().IsNew()) {
+ base::AutoUnlock release(worker_state->lock);
decode_task->state().DidSchedule();
decode_task->state().DidStart();
decode_task->RunOnWorkerThread();
decode_task->state().DidFinish();
}
- origin_task_runner_->PostTask(
+
+ worker_state->origin_task_runner->PostTask(
FROM_HERE, base::BindOnce(&ImageController::ImageDecodeCompleted,
- weak_ptr_, decode_id));
+ worker_state->weak_ptr, decode_id));
+
+ DCHECK_EQ(worker_state->task_state, WorkerTaskState::kRunningTask);
+ worker_state->task_state = WorkerTaskState::kNoTask;
}
void ImageController::ImageDecodeCompleted(ImageDecodeRequestId id) {
ImageDecodedCallback callback;
ImageDecodeResult result = ImageDecodeResult::SUCCESS;
{
- base::AutoLock hold(lock_);
+ base::AutoLock hold(worker_state_->lock);
- auto request_it = requests_needing_completion_.find(id);
- DCHECK(request_it != requests_needing_completion_.end());
+ auto request_it = worker_state_->requests_needing_completion.find(id);
+ // The request may have been completed by StopWorkerTasks().
+ if (request_it == worker_state_->requests_needing_completion.end())
+ return;
id = request_it->first;
ImageDecodeRequest& request = request_it->second;
@@ -350,23 +367,19 @@ void ImageController::ImageDecodeCompleted(ImageDecodeRequestId id) {
// Finally, save the callback so we can run it without the lock, and erase
// the request from |requests_needing_completion_|.
callback = std::move(request.callback);
- requests_needing_completion_.erase(request_it);
- }
+ worker_state_->requests_needing_completion.erase(request_it);
- // Post another task to run.
- worker_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&ImageController::ProcessNextImageDecodeOnWorkerThread,
- base::Unretained(this)));
+ ScheduleImageDecodeOnWorkerIfNeeded();
+ }
// Finally run the requested callback.
std::move(callback).Run(id, result);
}
void ImageController::GenerateTasksForOrphanedRequests() {
- base::AutoLock hold(lock_);
- DCHECK_EQ(0u, image_decode_queue_.size());
- DCHECK_EQ(0u, requests_needing_completion_.size());
+ base::AutoLock hold(worker_state_->lock);
+ DCHECK_EQ(0u, worker_state_->image_decode_queue.size());
+ DCHECK_EQ(0u, worker_state_->requests_needing_completion.size());
DCHECK(cache_);
for (auto& request : orphaned_decode_requests_) {
@@ -379,16 +392,24 @@ void ImageController::GenerateTasksForOrphanedRequests() {
request.need_unref = result.need_unref;
request.task = result.task;
}
- image_decode_queue_[request.id] = std::move(request);
+ worker_state_->image_decode_queue[request.id] = std::move(request);
}
orphaned_decode_requests_.clear();
- if (!image_decode_queue_.empty()) {
- // Post a worker task.
+ ScheduleImageDecodeOnWorkerIfNeeded();
+}
+
+void ImageController::ScheduleImageDecodeOnWorkerIfNeeded() {
+ if (worker_state_->task_state == WorkerTaskState::kNoTask &&
+ !worker_state_->image_decode_queue.empty()) {
+ worker_state_->task_state = WorkerTaskState::kQueuedTask;
+ // base::Unretained is safe because `worker_state_` is guaranteed to be
+ // deleted from a task posted to `worker_task_runner_` after this (see
+ // ~ImageController).
worker_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&ImageController::ProcessNextImageDecodeOnWorkerThread,
- base::Unretained(this)));
+ base::Unretained(worker_state_.get())));
}
}
diff --git a/chromium/cc/tiles/image_controller.h b/chromium/cc/tiles/image_controller.h
index 20c4a0dc249..a93aca54925 100644
--- a/chromium/cc/tiles/image_controller.h
+++ b/chromium/cc/tiles/image_controller.h
@@ -5,7 +5,8 @@
#ifndef CC_TILES_IMAGE_CONTROLLER_H_
#define CC_TILES_IMAGE_CONTROLLER_H_
-#include <set>
+#include <map>
+#include <memory>
#include <vector>
#include "base/callback.h"
@@ -13,8 +14,9 @@
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
+#include "base/synchronization/lock.h"
#include "base/task/sequenced_task_runner.h"
-#include "base/threading/simple_thread.h"
+#include "base/thread_annotations.h"
#include "cc/base/unique_notifier.h"
#include "cc/cc_export.h"
#include "cc/paint/draw_image.h"
@@ -31,7 +33,7 @@ class CC_EXPORT ImageController {
using ImageDecodedCallback =
base::OnceCallback<void(ImageDecodeRequestId, ImageDecodeResult)>;
explicit ImageController(
- base::SequencedTaskRunner* origin_task_runner,
+ scoped_refptr<base::SequencedTaskRunner> origin_task_runner,
scoped_refptr<base::SequencedTaskRunner> worker_task_runner);
ImageController(const ImageController&) = delete;
virtual ~ImageController();
@@ -105,32 +107,51 @@ class CC_EXPORT ImageController {
bool need_unref;
};
+ enum class WorkerTaskState {
+ kNoTask,
+ kQueuedTask,
+ kRunningTask,
+ };
+
+ // State accessible from the worker thread. Held in a isolated struct so it
+ // can be deleted asynchronously on the worker thread after the
+ // ImageController is deleted.
+ struct WorkerState {
+ WorkerState(scoped_refptr<base::SequencedTaskRunner> origin_task_runner,
+ base::WeakPtr<ImageController> weak_ptr);
+ ~WorkerState();
+
+ base::Lock lock;
+ std::map<ImageDecodeRequestId, ImageDecodeRequest> image_decode_queue
+ GUARDED_BY(lock);
+ std::map<ImageDecodeRequestId, ImageDecodeRequest>
+ requests_needing_completion GUARDED_BY(lock);
+ WorkerTaskState task_state GUARDED_BY(lock) = WorkerTaskState::kNoTask;
+ bool abort_task GUARDED_BY(lock) = false;
+
+ const scoped_refptr<base::SequencedTaskRunner> origin_task_runner;
+ const base::WeakPtr<ImageController> weak_ptr;
+ };
+
void StopWorkerTasks();
- // Called from the worker thread.
- void ProcessNextImageDecodeOnWorkerThread();
+ static void ProcessNextImageDecodeOnWorkerThread(WorkerState* worker_state);
void ImageDecodeCompleted(ImageDecodeRequestId id);
void GenerateTasksForOrphanedRequests();
- base::WeakPtr<ImageController> weak_ptr_;
+ void ScheduleImageDecodeOnWorkerIfNeeded()
+ EXCLUSIVE_LOCKS_REQUIRED(worker_state_->lock);
raw_ptr<ImageDecodeCache> cache_ = nullptr;
std::vector<DrawImage> predecode_locked_images_;
static ImageDecodeRequestId s_next_image_decode_queue_id_;
base::flat_map<ImageDecodeRequestId, DrawImage> requested_locked_images_;
-
- raw_ptr<base::SequencedTaskRunner> origin_task_runner_ = nullptr;
size_t image_cache_max_limit_bytes_ = 0u;
- // The variables defined below this lock (aside from weak_ptr_factory_) can
- // only be accessed when the lock is acquired.
- base::Lock lock_;
- std::map<ImageDecodeRequestId, ImageDecodeRequest> image_decode_queue_;
- std::map<ImageDecodeRequestId, ImageDecodeRequest>
- requests_needing_completion_;
- bool abort_tasks_ = false;
+ std::unique_ptr<WorkerState> worker_state_;
+
// Orphaned requests are requests that were either in queue or needed a
// completion callback when we set the decode cache to be nullptr. When a new
// decode cache is set, these requests are re-enqueued again with tasks
diff --git a/chromium/cc/tiles/image_controller_unittest.cc b/chromium/cc/tiles/image_controller_unittest.cc
index 386cb0e45f1..42bb926aad4 100644
--- a/chromium/cc/tiles/image_controller_unittest.cc
+++ b/chromium/cc/tiles/image_controller_unittest.cc
@@ -11,10 +11,13 @@
#include "base/callback_helpers.h"
#include "base/run_loop.h"
#include "base/synchronization/condition_variable.h"
-#include "base/test/test_simple_task_runner.h"
+#include "base/task/thread_pool.h"
#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/threading/simple_thread.h"
#include "base/threading/thread_checker_impl.h"
+#include "base/threading/thread_restrictions.h"
#include "cc/paint/paint_image_builder.h"
+#include "cc/test/cc_test_suite.h"
#include "cc/test/skia_common.h"
#include "cc/test/stub_decode_cache.h"
#include "cc/test/test_paint_worklet_input.h"
@@ -25,78 +28,6 @@
namespace cc {
namespace {
-class TestWorkerThread : public base::SimpleThread {
- public:
- TestWorkerThread()
- : base::SimpleThread("test_worker_thread"), condition_(&lock_) {}
-
- void Run() override {
- for (;;) {
- base::OnceClosure task;
- {
- base::AutoLock hold(lock_);
- if (shutdown_)
- break;
-
- if (queue_.empty()) {
- condition_.Wait();
- continue;
- }
-
- task = std::move(queue_.front());
- queue_.erase(queue_.begin());
- }
- std::move(task).Run();
- }
- }
-
- void Shutdown() {
- base::AutoLock hold(lock_);
- shutdown_ = true;
- condition_.Signal();
- }
-
- void PostTask(base::OnceClosure task) {
- base::AutoLock hold(lock_);
- queue_.push_back(std::move(task));
- condition_.Signal();
- }
-
- private:
- base::Lock lock_;
- base::ConditionVariable condition_;
- std::vector<base::OnceClosure> queue_;
- bool shutdown_ = false;
-};
-
-class WorkerTaskRunner : public base::SequencedTaskRunner {
- public:
- WorkerTaskRunner() { thread_.Start(); }
-
- bool PostNonNestableDelayedTask(const base::Location& from_here,
- base::OnceClosure task,
- base::TimeDelta delay) override {
- return PostDelayedTask(from_here, std::move(task), delay);
- }
-
- bool PostDelayedTask(const base::Location& from_here,
- base::OnceClosure task,
- base::TimeDelta delay) override {
- thread_.PostTask(std::move(task));
- return true;
- }
-
- bool RunsTasksInCurrentSequence() const override { return false; }
-
- protected:
- ~WorkerTaskRunner() override {
- thread_.Shutdown();
- thread_.Join();
- }
-
- TestWorkerThread thread_;
-};
-
// Image decode cache with introspection!
class TestableCache : public StubDecodeCache {
public:
@@ -208,6 +139,7 @@ class BlockingTask : public TileTask {
EXPECT_FALSE(HasCompleted());
EXPECT_FALSE(thread_checker_.CalledOnValidThread());
base::AutoLock hold(lock_);
+ base::ScopedAllowBaseSyncPrimitivesForTesting allow_base_sync_primitives;
while (!can_run_)
run_cv_.Wait();
has_run_ = true;
@@ -262,16 +194,16 @@ class ImageControllerTest : public testing::Test {
~ImageControllerTest() override = default;
void SetUp() override {
- worker_task_runner_ = base::MakeRefCounted<WorkerTaskRunner>();
- controller_ = std::make_unique<ImageController>(task_runner_.get(),
- worker_task_runner_);
+ controller_ = std::make_unique<ImageController>(
+ task_runner_,
+ base::ThreadPool::CreateSequencedTaskRunner(base::TaskTraits()));
cache_ = TestableCache();
controller_->SetImageDecodeCache(&cache_);
}
void TearDown() override {
controller_.reset();
- worker_task_runner_ = nullptr;
+ CCTestSuite::RunUntilIdle();
weak_ptr_factory_.InvalidateWeakPtrs();
}
@@ -318,7 +250,6 @@ class ImageControllerTest : public testing::Test {
private:
scoped_refptr<base::SequencedTaskRunner> task_runner_;
- scoped_refptr<WorkerTaskRunner> worker_task_runner_;
TestableCache cache_;
std::unique_ptr<ImageController> controller_;
DrawImage image_;
@@ -474,7 +405,9 @@ TEST_F(ImageControllerTest, QueueImageDecodeMultipleImagesSameTask) {
EXPECT_TRUE(task->HasCompleted());
}
-TEST_F(ImageControllerTest, QueueImageDecodeChangeControllerWithTaskQueued) {
+// TODO(crbug.com/1336053): Re-enable this test
+TEST_F(ImageControllerTest,
+ DISABLED_QueueImageDecodeChangeControllerWithTaskQueued) {
scoped_refptr<BlockingTask> task_one(new BlockingTask);
cache()->SetTaskToUse(task_one);
diff --git a/chromium/cc/tiles/image_decode_cache_utils.cc b/chromium/cc/tiles/image_decode_cache_utils.cc
index b730d060a54..b6a1faef323 100644
--- a/chromium/cc/tiles/image_decode_cache_utils.cc
+++ b/chromium/cc/tiles/image_decode_cache_utils.cc
@@ -15,6 +15,7 @@
namespace cc {
+// static
bool ImageDecodeCacheUtils::ScaleToHalfFloatPixmapUsingN32Intermediate(
const SkPixmap& source_pixmap,
SkPixmap* scaled_pixmap,
@@ -51,6 +52,20 @@ bool ImageDecodeCacheUtils::ScaleToHalfFloatPixmapUsingN32Intermediate(
return n32_resized_bitmap.readPixels(*scaled_pixmap, 0, 0);
}
+// static
+bool ImageDecodeCacheUtils::ShouldEvictCaches(
+ base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
+ switch (memory_pressure_level) {
+ case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
+ case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
+ return false;
+ case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
+ return true;
+ }
+ NOTREACHED();
+ return false;
+}
+
} // namespace cc
#endif // CC_TILES_IMAGE_DECODE_CACHE_UTILS_CC_
diff --git a/chromium/cc/tiles/image_decode_cache_utils.h b/chromium/cc/tiles/image_decode_cache_utils.h
index 6bfac749287..cbc64b2d3fb 100644
--- a/chromium/cc/tiles/image_decode_cache_utils.h
+++ b/chromium/cc/tiles/image_decode_cache_utils.h
@@ -5,6 +5,7 @@
#ifndef CC_TILES_IMAGE_DECODE_CACHE_UTILS_H_
#define CC_TILES_IMAGE_DECODE_CACHE_UTILS_H_
+#include "base/memory/memory_pressure_listener.h"
#include "build/build_config.h"
#include "cc/paint/paint_flags.h"
#include "third_party/skia/include/core/SkPixmap.h"
@@ -35,6 +36,9 @@ class ImageDecodeCacheUtils {
const SkPixmap& source_pixmap,
SkPixmap* scaled_pixmap,
PaintFlags::FilterQuality filter_quality);
+
+ static bool ShouldEvictCaches(
+ base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level);
};
} // namespace cc
diff --git a/chromium/cc/tiles/software_image_decode_cache.cc b/chromium/cc/tiles/software_image_decode_cache.cc
index 28b6a196983..3cbe0a52a20 100644
--- a/chromium/cc/tiles/software_image_decode_cache.cc
+++ b/chromium/cc/tiles/software_image_decode_cache.cc
@@ -20,6 +20,7 @@
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/memory_dump_manager.h"
#include "cc/base/devtools_instrumentation.h"
+#include "cc/base/features.h"
#include "cc/base/histograms.h"
#include "cc/raster/tile_task.h"
#include "cc/tiles/mipmap_util.h"
@@ -65,7 +66,10 @@ class SoftwareImageDecodeTaskImpl : public TileTask {
SoftwareImageDecodeCache::DecodeTaskType task_type,
const ImageDecodeCache::TracingInfo& tracing_info)
: TileTask(TileTask::SupportsConcurrentExecution::kYes,
- TileTask::SupportsBackgroundThreadPriority::kYes),
+ (base::FeatureList::IsEnabled(
+ features::kNormalPriorityImageDecoding)
+ ? TileTask::SupportsBackgroundThreadPriority::kNo
+ : TileTask::SupportsBackgroundThreadPriority::kYes)),
cache_(cache),
image_key_(image_key),
paint_image_(paint_image),
@@ -103,6 +107,13 @@ class SoftwareImageDecodeTaskImpl : public TileTask {
cache_->OnImageDecodeTaskCompleted(image_key_, task_type_);
}
+ // Overridden from TileTask:
+ bool TaskContainsLCPCandidateImages() const override {
+ if (!HasCompleted() && paint_image_.may_be_lcp_candidate())
+ return true;
+ return TileTask::TaskContainsLCPCandidateImages();
+ }
+
protected:
~SoftwareImageDecodeTaskImpl() override = default;
@@ -142,12 +153,11 @@ PaintFlags::FilterQuality GetDecodedFilterQuality(
SoftwareImageDecodeCache::SoftwareImageDecodeCache(
SkColorType color_type,
- size_t locked_memory_limit_bytes,
- PaintImage::GeneratorClientId generator_client_id)
+ size_t locked_memory_limit_bytes)
: decoded_images_(ImageLRUCache::NO_AUTO_EVICT),
locked_images_budget_(locked_memory_limit_bytes),
color_type_(color_type),
- generator_client_id_(generator_client_id),
+ generator_client_id_(PaintImage::GetNextGeneratorClientId()),
max_items_in_cache_(kNormalMaxItemsInCacheForSoftware) {
DCHECK_NE(generator_client_id_, PaintImage::kDefaultGeneratorClientId);
// In certain cases, ThreadTaskRunnerHandle isn't set (Android Webview).
@@ -634,6 +644,8 @@ void SoftwareImageDecodeCache::OnImageDecodeTaskCompleted(
auto image_it = decoded_images_.Peek(key);
DCHECK(image_it != decoded_images_.end());
CacheEntry* cache_entry = image_it->second.get();
+ UMA_HISTOGRAM_BOOLEAN("Compositing.DecodeLCPCandidateImage.Software",
+ key.may_be_lcp_candidate());
auto& task = task_type == DecodeTaskType::USE_IN_RASTER_TASKS
? cache_entry->in_raster_task
: cache_entry->out_of_raster_task;
diff --git a/chromium/cc/tiles/software_image_decode_cache.h b/chromium/cc/tiles/software_image_decode_cache.h
index e88adfe1ef6..dfc55b72965 100644
--- a/chromium/cc/tiles/software_image_decode_cache.h
+++ b/chromium/cc/tiles/software_image_decode_cache.h
@@ -38,8 +38,7 @@ class CC_EXPORT SoftwareImageDecodeCache
enum class TaskProcessingResult { kFullDecode, kLockOnly, kCancelled };
SoftwareImageDecodeCache(SkColorType color_type,
- size_t locked_memory_limit_bytes,
- PaintImage::GeneratorClientId generator_client_id);
+ size_t locked_memory_limit_bytes);
~SoftwareImageDecodeCache() override;
// ImageDecodeCache overrides.
diff --git a/chromium/cc/tiles/software_image_decode_cache_unittest.cc b/chromium/cc/tiles/software_image_decode_cache_unittest.cc
index 90abb8dc920..5600eb023a7 100644
--- a/chromium/cc/tiles/software_image_decode_cache_unittest.cc
+++ b/chromium/cc/tiles/software_image_decode_cache_unittest.cc
@@ -27,9 +27,7 @@ size_t kLockedMemoryLimitBytes = 128 * 1024 * 1024;
class TestSoftwareImageDecodeCache : public SoftwareImageDecodeCache {
public:
TestSoftwareImageDecodeCache()
- : SoftwareImageDecodeCache(kN32_SkColorType,
- kLockedMemoryLimitBytes,
- PaintImage::GetNextGeneratorClientId()) {}
+ : SoftwareImageDecodeCache(kN32_SkColorType, kLockedMemoryLimitBytes) {}
};
SkM44 CreateMatrix(const SkSize& scale, bool is_decomposable) {
diff --git a/chromium/cc/tiles/software_image_decode_cache_unittest_combinations.cc b/chromium/cc/tiles/software_image_decode_cache_unittest_combinations.cc
index 0a89147856e..6f1fefff476 100644
--- a/chromium/cc/tiles/software_image_decode_cache_unittest_combinations.cc
+++ b/chromium/cc/tiles/software_image_decode_cache_unittest_combinations.cc
@@ -81,27 +81,24 @@ class BaseTest : public testing::Test {
class N32Cache : public virtual BaseTest {
protected:
std::unique_ptr<SoftwareImageDecodeCache> CreateCache() override {
- return std::make_unique<SoftwareImageDecodeCache>(
- kN32_SkColorType, kLockedMemoryLimitBytes,
- PaintImage::GetNextGeneratorClientId());
+ return std::make_unique<SoftwareImageDecodeCache>(kN32_SkColorType,
+ kLockedMemoryLimitBytes);
}
};
class RGBA4444Cache : public virtual BaseTest {
protected:
std::unique_ptr<SoftwareImageDecodeCache> CreateCache() override {
- return std::make_unique<SoftwareImageDecodeCache>(
- kARGB_4444_SkColorType, kLockedMemoryLimitBytes,
- PaintImage::GetNextGeneratorClientId());
+ return std::make_unique<SoftwareImageDecodeCache>(kARGB_4444_SkColorType,
+ kLockedMemoryLimitBytes);
}
};
class RGBA_F16Cache : public virtual BaseTest {
protected:
std::unique_ptr<SoftwareImageDecodeCache> CreateCache() override {
- return std::make_unique<SoftwareImageDecodeCache>(
- kRGBA_F16_SkColorType, kLockedMemoryLimitBytes,
- PaintImage::GetNextGeneratorClientId());
+ return std::make_unique<SoftwareImageDecodeCache>(kRGBA_F16_SkColorType,
+ kLockedMemoryLimitBytes);
}
};
diff --git a/chromium/cc/tiles/software_image_decode_cache_utils.cc b/chromium/cc/tiles/software_image_decode_cache_utils.cc
index 43f02627797..a9bdd7ae99c 100644
--- a/chromium/cc/tiles/software_image_decode_cache_utils.cc
+++ b/chromium/cc/tiles/software_image_decode_cache_utils.cc
@@ -196,7 +196,8 @@ SoftwareImageDecodeCacheUtils::CacheKey::FromDrawImage(const DrawImage& image,
// If the target size is empty, then we'll be skipping the decode anyway, so
// the filter quality doesn't matter. Early out instead.
if (target_size.IsEmpty()) {
- return CacheKey(frame_key, stable_id, kSubrectAndScale, false, src_rect,
+ return CacheKey(frame_key, stable_id, kSubrectAndScale, false,
+ image.paint_image().may_be_lcp_candidate(), src_rect,
target_size, image.target_color_params());
}
@@ -250,7 +251,8 @@ SoftwareImageDecodeCacheUtils::CacheKey::FromDrawImage(const DrawImage& image,
}
}
- return CacheKey(frame_key, stable_id, type, is_nearest_neighbor, src_rect,
+ return CacheKey(frame_key, stable_id, type, is_nearest_neighbor,
+ image.paint_image().may_be_lcp_candidate(), src_rect,
target_size, image.target_color_params());
}
@@ -259,6 +261,7 @@ SoftwareImageDecodeCacheUtils::CacheKey::CacheKey(
PaintImage::Id stable_id,
ProcessingType type,
bool is_nearest_neighbor,
+ bool may_be_lcp_candidate,
const gfx::Rect& src_rect,
const gfx::Size& target_size,
const TargetColorParams& target_color_params)
@@ -266,6 +269,7 @@ SoftwareImageDecodeCacheUtils::CacheKey::CacheKey(
stable_id_(stable_id),
type_(type),
is_nearest_neighbor_(is_nearest_neighbor),
+ may_be_lcp_candidate_(may_be_lcp_candidate),
src_rect_(src_rect),
target_size_(target_size),
target_color_params_(target_color_params) {
diff --git a/chromium/cc/tiles/software_image_decode_cache_utils.h b/chromium/cc/tiles/software_image_decode_cache_utils.h
index 51aaa1acf0f..c11d05b65ea 100644
--- a/chromium/cc/tiles/software_image_decode_cache_utils.h
+++ b/chromium/cc/tiles/software_image_decode_cache_utils.h
@@ -74,6 +74,7 @@ class SoftwareImageDecodeCacheUtils {
PaintImage::Id stable_id() const { return stable_id_; }
ProcessingType type() const { return type_; }
bool is_nearest_neighbor() const { return is_nearest_neighbor_; }
+ bool may_be_lcp_candidate() const { return may_be_lcp_candidate_; }
gfx::Rect src_rect() const { return src_rect_; }
gfx::Size target_size() const { return target_size_; }
const TargetColorParams& target_color_params() const {
@@ -99,6 +100,7 @@ class SoftwareImageDecodeCacheUtils {
PaintImage::Id stable_id,
ProcessingType type,
bool is_nearest_neighbor,
+ bool may_be_lcp_candidate,
const gfx::Rect& src_rect,
const gfx::Size& size,
const TargetColorParams& target_color_params);
@@ -110,6 +112,7 @@ class SoftwareImageDecodeCacheUtils {
PaintImage::Id stable_id_;
ProcessingType type_;
bool is_nearest_neighbor_;
+ bool may_be_lcp_candidate_;
gfx::Rect src_rect_;
gfx::Size target_size_;
TargetColorParams target_color_params_;
diff --git a/chromium/cc/tiles/tile.cc b/chromium/cc/tiles/tile.cc
index a8cb3fd52e5..1d9edab34e8 100644
--- a/chromium/cc/tiles/tile.cc
+++ b/chromium/cc/tiles/tile.cc
@@ -83,6 +83,10 @@ void Tile::AsValueInto(base::trace_event::TracedValue* value) const {
base::saturated_cast<int>(GPUMemoryUsageInBytes()));
}
+bool Tile::HasMissingLCPCandidateImages() const {
+ return HasRasterTask() && raster_task_->TaskContainsLCPCandidateImages();
+}
+
size_t Tile::GPUMemoryUsageInBytes() const {
if (draw_info_.resource_) {
// We can use UncheckedSizeInBytes, since the tile size is determined by the
diff --git a/chromium/cc/tiles/tile.h b/chromium/cc/tiles/tile.h
index cde7850f9e4..60afa44eee1 100644
--- a/chromium/cc/tiles/tile.h
+++ b/chromium/cc/tiles/tile.h
@@ -112,6 +112,8 @@ class CC_EXPORT Tile {
bool HasRasterTask() const { return !!raster_task_.get(); }
+ bool HasMissingLCPCandidateImages() const;
+
void set_solid_color_analysis_performed(bool performed) {
is_solid_color_analysis_performed_ = performed;
}
diff --git a/chromium/cc/tiles/tile_draw_info.cc b/chromium/cc/tiles/tile_draw_info.cc
index 4b4bac2eb82..e73bb0b7ede 100644
--- a/chromium/cc/tiles/tile_draw_info.cc
+++ b/chromium/cc/tiles/tile_draw_info.cc
@@ -19,7 +19,7 @@ TileDrawInfo::~TileDrawInfo() {
void TileDrawInfo::AsValueInto(base::trace_event::TracedValue* state) const {
state->SetBoolean("is_solid_color", mode_ == SOLID_COLOR_MODE);
state->SetBoolean("is_transparent",
- mode_ == SOLID_COLOR_MODE && !SkColorGetA(solid_color_));
+ mode_ == SOLID_COLOR_MODE && !solid_color_.isOpaque());
}
void TileDrawInfo::SetResource(ResourcePool::InUsePoolResource resource,
diff --git a/chromium/cc/tiles/tile_draw_info.h b/chromium/cc/tiles/tile_draw_info.h
index e0fbe4fe598..2e4d35535ba 100644
--- a/chromium/cc/tiles/tile_draw_info.h
+++ b/chromium/cc/tiles/tile_draw_info.h
@@ -65,7 +65,7 @@ class CC_EXPORT TileDrawInfo {
return resource_.format();
}
- SkColor solid_color() const {
+ SkColor4f solid_color() const {
DCHECK(mode_ == SOLID_COLOR_MODE);
return solid_color_;
}
@@ -85,7 +85,7 @@ class CC_EXPORT TileDrawInfo {
return resource_is_checker_imaged_;
}
- void SetSolidColorForTesting(SkColor color) { set_solid_color(color); }
+ void SetSolidColorForTesting(SkColor4f color) { set_solid_color(color); }
void AsValueInto(base::trace_event::TracedValue* state) const;
@@ -102,7 +102,7 @@ class CC_EXPORT TileDrawInfo {
is_resource_ready_to_draw_ = true;
}
- void set_solid_color(const SkColor& color) {
+ void set_solid_color(const SkColor4f& color) {
DCHECK(!resource_);
mode_ = SOLID_COLOR_MODE;
solid_color_ = color;
@@ -111,7 +111,7 @@ class CC_EXPORT TileDrawInfo {
void set_oom() { mode_ = OOM_MODE; }
Mode mode_ = RESOURCE_MODE;
- SkColor solid_color_ = SK_ColorWHITE;
+ SkColor4f solid_color_ = SkColors::kWhite;
ResourcePool::InUsePoolResource resource_;
bool is_premultiplied_ = false;
bool is_resource_ready_to_draw_ = false;
diff --git a/chromium/cc/tiles/tile_manager.cc b/chromium/cc/tiles/tile_manager.cc
index 000c0c5a02d..ea2ddbf8283 100644
--- a/chromium/cc/tiles/tile_manager.cc
+++ b/chromium/cc/tiles/tile_manager.cc
@@ -176,7 +176,9 @@ class RasterTaskImpl : public TileTask {
TileResolution tile_resolution_;
int layer_id_;
uint64_t source_prepare_tiles_id_;
- raw_ptr<void> tile_tracing_id_;
+ // TODO(crbug.com/1298696): views_unittests breaks with MTECheckedPtr
+ // enabled. Triage.
+ raw_ptr<void, DanglingUntriagedDegradeToNoOpWhenMTE> tile_tracing_id_;
uint64_t new_content_id_;
int source_frame_number_;
std::unique_ptr<RasterBuffer> raster_buffer_;
@@ -368,7 +370,7 @@ class DidFinishRunningAllTilesTask : public TileTask {
private:
raw_ptr<base::SequencedTaskRunner> task_runner_;
- raw_ptr<RasterQueryQueue> pending_raster_queries_;
+ raw_ptr<RasterQueryQueue, DanglingUntriaged> pending_raster_queries_;
CompletionCb completion_cb_;
};
@@ -459,6 +461,7 @@ void TileManager::FinishTasksAndCleanUp() {
tile_task_manager_ = nullptr;
resource_pool_ = nullptr;
+ pending_raster_queries_ = nullptr;
more_tiles_need_prepare_check_notifier_.Cancel();
signals_check_notifier_.Cancel();
task_set_finished_weak_ptr_factory_.InvalidateWeakPtrs();
@@ -753,7 +756,7 @@ TileManager::PrioritizedWorkToSchedule TileManager::AssignGpuMemoryToTiles() {
prioritized_tile.raster_source()->PerformSolidColorAnalysis(
tile->enclosing_layer_rect(), &color);
if (is_solid_color) {
- tile->draw_info().set_solid_color(color.toSkColor());
+ tile->draw_info().set_solid_color(color);
client_->NotifyTileStateChanged(tile);
continue;
}
@@ -1527,7 +1530,9 @@ void TileManager::IssueSignals() {
if (signals_.activate_tile_tasks_completed &&
signals_.activate_gpu_work_completed &&
!signals_.did_notify_ready_to_activate) {
- if (!client_->HasPendingTree() || IsReadyToActivate()) {
+ // If commit_to_active_tree is true(no pending tree), NotifyReadyToActivate
+ // isn't sent to client, so don't call IsReadyToActivate() to save CPU time
+ if (client_->HasPendingTree() && IsReadyToActivate()) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"TileManager::IssueSignals - ready to activate");
signals_.did_notify_ready_to_activate = true;
@@ -1538,7 +1543,7 @@ void TileManager::IssueSignals() {
// Ready to draw.
if (signals_.draw_tile_tasks_completed && signals_.draw_gpu_work_completed &&
!signals_.did_notify_ready_to_draw) {
- if (IsReadyToDraw()) {
+ if (tile_manager_settings_.needs_notify_ready_to_draw && IsReadyToDraw()) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"TileManager::IssueSignals - ready to draw");
signals_.did_notify_ready_to_draw = true;
@@ -1561,6 +1566,12 @@ void TileManager::IssueSignals() {
}
}
+ bool notify_ready_to_activate_pending =
+ client_->HasPendingTree() && !signals_.did_notify_ready_to_activate;
+ bool notify_ready_to_draw_pending =
+ tile_manager_settings_.needs_notify_ready_to_draw &&
+ !signals_.did_notify_ready_to_draw;
+
// Allow decodes for rasterized tiles if all required for draw/activate tiles
// are done. And pre-decode tiles once all tile tasks are done.
// Note that the order is important here, since all signals could have become
@@ -1568,8 +1579,8 @@ void TileManager::IssueSignals() {
if (signals_.did_notify_all_tile_tasks_completed) {
checker_image_tracker_.SetMaxDecodePriorityAllowed(
CheckerImageTracker::DecodeType::kPreDecode);
- } else if (signals_.did_notify_ready_to_activate &&
- signals_.did_notify_ready_to_draw) {
+ } else if (!notify_ready_to_activate_pending &&
+ !notify_ready_to_draw_pending) {
checker_image_tracker_.SetMaxDecodePriorityAllowed(
CheckerImageTracker::DecodeType::kRaster);
}
diff --git a/chromium/cc/tiles/tile_manager.h b/chromium/cc/tiles/tile_manager.h
index ebac463ac34..680fa77b7ce 100644
--- a/chromium/cc/tiles/tile_manager.h
+++ b/chromium/cc/tiles/tile_manager.h
@@ -441,11 +441,11 @@ class CC_EXPORT TileManager : CheckerImageTrackerClient {
bool ShouldRasterOccludedTiles() const;
- raw_ptr<TileManagerClient> client_;
+ raw_ptr<TileManagerClient, DanglingUntriaged> client_;
raw_ptr<base::SequencedTaskRunner> task_runner_;
- raw_ptr<ResourcePool> resource_pool_;
+ raw_ptr<ResourcePool, DanglingUntriaged> resource_pool_;
std::unique_ptr<TileTaskManager> tile_task_manager_;
- raw_ptr<RasterBufferProvider> raster_buffer_provider_;
+ raw_ptr<RasterBufferProvider, DanglingUntriaged> raster_buffer_provider_;
GlobalStateThatImpactsTilePriority global_state_;
size_t scheduled_raster_task_limit_;
diff --git a/chromium/cc/tiles/tile_manager_settings.h b/chromium/cc/tiles/tile_manager_settings.h
index 6a7f7fb1f0c..7c1d81ab409 100644
--- a/chromium/cc/tiles/tile_manager_settings.h
+++ b/chromium/cc/tiles/tile_manager_settings.h
@@ -13,6 +13,7 @@ struct CC_EXPORT TileManagerSettings {
bool use_partial_raster = false;
bool enable_checker_imaging = false;
size_t min_image_bytes_to_checker = 1 * 1024 * 1024;
+ bool needs_notify_ready_to_draw = true;
};
} // namespace cc
diff --git a/chromium/cc/tiles/tile_manager_unittest.cc b/chromium/cc/tiles/tile_manager_unittest.cc
index 3086adbf21e..9c329f50969 100644
--- a/chromium/cc/tiles/tile_manager_unittest.cc
+++ b/chromium/cc/tiles/tile_manager_unittest.cc
@@ -1236,7 +1236,7 @@ TEST_F(TileManagerTilePriorityQueueTest,
// On the second iteration, mark everything as ready to draw (solid color).
if (i == 1) {
TileDrawInfo& draw_info = last_tile.tile()->draw_info();
- draw_info.SetSolidColorForTesting(SK_ColorRED);
+ draw_info.SetSolidColorForTesting(SkColors::kRed);
}
queue->Pop();
int eventually_bin_order_correct_count = 0;
@@ -1272,7 +1272,7 @@ TEST_F(TileManagerTilePriorityQueueTest,
// color).
if (i == 1) {
TileDrawInfo& draw_info = last_tile.tile()->draw_info();
- draw_info.SetSolidColorForTesting(SK_ColorRED);
+ draw_info.SetSolidColorForTesting(SkColors::kRed);
}
}
@@ -1519,13 +1519,13 @@ TEST_F(TileManagerTilePriorityQueueTest, NoRasterTasksforSolidColorTiles) {
FakeRecordingSource::CreateFilledRecordingSource(layer_bounds);
PaintFlags solid_flags;
- SkColor solid_color = SkColorSetARGB(255, 12, 23, 34);
+ SkColor4f solid_color{0.1f, 0.2f, 0.3f, 1.0f};
solid_flags.setColor(solid_color);
recording_source->add_draw_rect_with_flags(gfx::Rect(layer_bounds),
solid_flags);
// Create non solid tile as well, otherwise tilings wouldnt be created.
- SkColor non_solid_color = SkColorSetARGB(128, 45, 56, 67);
+ SkColor4f non_solid_color{0.2f, 0.3f, 0.4f, 0.5f};
PaintFlags non_solid_flags;
non_solid_flags.setColor(non_solid_color);
@@ -1682,7 +1682,6 @@ TEST_F(TileManagerTest, AllWorkFinished) {
base::RunLoop run_loop;
EXPECT_FALSE(
host_impl()->tile_manager()->HasScheduledTileTasksForTesting());
- EXPECT_CALL(MockHostImpl(), NotifyReadyToActivate());
EXPECT_CALL(MockHostImpl(), NotifyReadyToDraw());
EXPECT_CALL(MockHostImpl(), NotifyAllTileTasksCompleted())
.WillOnce(testing::Invoke([&run_loop]() { run_loop.Quit(); }));
@@ -1697,7 +1696,6 @@ TEST_F(TileManagerTest, AllWorkFinished) {
base::RunLoop run_loop;
EXPECT_FALSE(
host_impl()->tile_manager()->HasScheduledTileTasksForTesting());
- EXPECT_CALL(MockHostImpl(), NotifyReadyToActivate());
EXPECT_CALL(MockHostImpl(), NotifyReadyToDraw());
EXPECT_CALL(MockHostImpl(), NotifyAllTileTasksCompleted())
.WillOnce(testing::Invoke([&run_loop]() { run_loop.Quit(); }));
@@ -1713,7 +1711,6 @@ TEST_F(TileManagerTest, AllWorkFinished) {
base::RunLoop run_loop;
EXPECT_FALSE(
host_impl()->tile_manager()->HasScheduledTileTasksForTesting());
- EXPECT_CALL(MockHostImpl(), NotifyReadyToActivate());
EXPECT_CALL(MockHostImpl(), NotifyReadyToDraw());
EXPECT_CALL(MockHostImpl(), NotifyAllTileTasksCompleted())
.WillOnce(testing::Invoke([&run_loop]() { run_loop.Quit(); }));
@@ -1728,7 +1725,6 @@ TEST_F(TileManagerTest, AllWorkFinished) {
base::RunLoop run_loop;
EXPECT_FALSE(
host_impl()->tile_manager()->HasScheduledTileTasksForTesting());
- EXPECT_CALL(MockHostImpl(), NotifyReadyToActivate());
EXPECT_CALL(MockHostImpl(), NotifyReadyToDraw());
EXPECT_CALL(MockHostImpl(), NotifyAllTileTasksCompleted())
.WillOnce(testing::Invoke([&run_loop]() { run_loop.Quit(); }));
@@ -3261,7 +3257,7 @@ TEST_F(CheckerImagingTileManagerTest,
->tile_manager()
->checker_image_tracker()
.no_decodes_allowed_for_testing());
- while (!host_impl()->client()->ready_to_draw()) {
+ while (!host_impl()->tile_manager()->IsReadyToDraw()) {
static_cast<SynchronousTaskGraphRunner*>(task_graph_runner())
->RunSingleTaskForTesting();
base::RunLoop().RunUntilIdle();
diff --git a/chromium/cc/trees/clip_expander.cc b/chromium/cc/trees/clip_expander.cc
deleted file mode 100644
index ee3b2560371..00000000000
--- a/chromium/cc/trees/clip_expander.cc
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/trees/clip_expander.h"
-#include "cc/trees/effect_node.h"
-#include "cc/trees/property_tree.h"
-#include "ui/gfx/geometry/transform.h"
-
-namespace cc {
-
-ClipExpander::ClipExpander(int filter_effect_id)
- : target_effect_id_(filter_effect_id) {}
-
-ClipExpander::ClipExpander(const ClipExpander& other) = default;
-
-ClipExpander& ClipExpander::operator=(const ClipExpander& other) = default;
-
-bool ClipExpander::operator==(const ClipExpander& other) const {
- return target_effect_id_ == other.target_effect_id_;
-}
-
-gfx::Rect ClipExpander::MapRect(const gfx::Rect& rect,
- const PropertyTrees* property_trees) const {
- const EffectNode* effect_node =
- property_trees->effect_tree().Node(target_effect_id_);
- gfx::Transform filter_draw_transform;
- filter_draw_transform.Scale(effect_node->surface_contents_scale.x(),
- effect_node->surface_contents_scale.y());
- return effect_node->filters.MapRect(rect,
- filter_draw_transform.matrix().asM33());
-}
-
-gfx::Rect ClipExpander::MapRectReverse(
- const gfx::Rect& rect,
- const PropertyTrees* property_trees) const {
- const EffectNode* effect_node =
- property_trees->effect_tree().Node(target_effect_id_);
- gfx::Transform filter_draw_transform;
- filter_draw_transform.Scale(effect_node->surface_contents_scale.x(),
- effect_node->surface_contents_scale.y());
- return effect_node->filters.MapRectReverse(
- rect, filter_draw_transform.matrix().asM33());
-}
-
-} // namespace cc
diff --git a/chromium/cc/trees/clip_expander.h b/chromium/cc/trees/clip_expander.h
deleted file mode 100644
index fef2ad5ecda..00000000000
--- a/chromium/cc/trees/clip_expander.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_TREES_CLIP_EXPANDER_H_
-#define CC_TREES_CLIP_EXPANDER_H_
-
-#include "cc/cc_export.h"
-#include "ui/gfx/geometry/rect.h"
-
-namespace cc {
-
-class PropertyTrees;
-
-class CC_EXPORT ClipExpander {
- public:
- explicit ClipExpander(int filter_effect_id);
- ClipExpander(const ClipExpander& other);
- ClipExpander& operator=(const ClipExpander& other);
-
- bool operator==(const ClipExpander& other) const;
-
- bool operator!=(const ClipExpander& other) const { return !(*this == other); }
-
- // Maps "forward" to determine which pixels in a destination rect are affected
- // by pixels in the given source rect.
- gfx::Rect MapRect(const gfx::Rect& rect,
- const PropertyTrees* property_trees) const;
-
- // Maps "backward" to determine which pixels in the source affect the pixels
- // in the given destination rect.
- gfx::Rect MapRectReverse(const gfx::Rect& rect,
- const PropertyTrees* property_trees) const;
-
- // The id of the effect node in whose transform space the expansion happens.
- int target_effect_id() const { return target_effect_id_; }
-
- private:
- int target_effect_id_;
-};
-
-} // namespace cc
-
-#endif // CC_TREES_CLIP_EXPANDER_H_
diff --git a/chromium/cc/trees/clip_node.cc b/chromium/cc/trees/clip_node.cc
index 9815ce36019..ab9140bf909 100644
--- a/chromium/cc/trees/clip_node.cc
+++ b/chromium/cc/trees/clip_node.cc
@@ -4,18 +4,17 @@
#include "cc/trees/clip_node.h"
+#include "base/trace_event/traced_value.h"
#include "cc/base/math_util.h"
#include "cc/layers/layer.h"
#include "cc/trees/property_tree.h"
-#include "base/trace_event/traced_value.h"
-
namespace cc {
ClipNode::ClipNode()
: id(kInvalidPropertyNodeId),
parent_id(kInvalidPropertyNodeId),
- clip_type(ClipType::APPLIES_LOCAL_CLIP),
+ pixel_moving_filter_id(kInvalidPropertyNodeId),
transform_id(kInvalidPropertyNodeId) {}
ClipNode::ClipNode(const ClipNode& other) = default;
@@ -24,11 +23,14 @@ ClipNode& ClipNode::operator=(const ClipNode& other) = default;
ClipNode::~ClipNode() = default;
+bool ClipNode::AppliesLocalClip() const {
+ return pixel_moving_filter_id == kInvalidPropertyNodeId;
+}
+
#if DCHECK_IS_ON()
bool ClipNode::operator==(const ClipNode& other) const {
- return id == other.id && parent_id == other.parent_id &&
- clip_type == other.clip_type && clip == other.clip &&
- clip_expander == other.clip_expander &&
+ return id == other.id && parent_id == other.parent_id && clip == other.clip &&
+ pixel_moving_filter_id == other.pixel_moving_filter_id &&
transform_id == other.transform_id;
}
#endif
@@ -36,8 +38,8 @@ bool ClipNode::operator==(const ClipNode& other) const {
void ClipNode::AsValueInto(base::trace_event::TracedValue* value) const {
value->SetInteger("id", id);
value->SetInteger("parent_id", parent_id);
- value->SetInteger("clip_type", static_cast<int>(clip_type));
MathUtil::AddToTracedValue("clip", clip, value);
+ value->SetInteger("pixel_moving_filter_id", pixel_moving_filter_id);
value->SetInteger("transform_id", transform_id);
}
diff --git a/chromium/cc/trees/clip_node.h b/chromium/cc/trees/clip_node.h
index 16fa425da8c..c187b582c30 100644
--- a/chromium/cc/trees/clip_node.h
+++ b/chromium/cc/trees/clip_node.h
@@ -7,8 +7,6 @@
#include "base/containers/stack_container.h"
#include "cc/cc_export.h"
-#include "cc/trees/clip_expander.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/gfx/geometry/rect_f.h"
namespace base {
@@ -37,28 +35,17 @@ struct CC_EXPORT ClipNode {
~ClipNode();
+ // Returns true if we should apply |clip|. Otherwise we should map the
+ // accumulated clip by the filter specified by |pixel_moving_filter_id|.
+ bool AppliesLocalClip() const;
+
// The node index of this node in the clip tree node vector.
int id;
// The node index of the parent node in the clip tree node vector.
int parent_id;
- enum class ClipType {
- // The node contributes a new clip (that is, |clip| needs to be applied).
- APPLIES_LOCAL_CLIP,
-
- // This node represents a space expansion. When computing visible rects,
- // the accumulated clip inherited by this node gets expanded. Similarly,
- // when mapping a rect in descendant space to the rect in ancestor space
- // that depends on the descendant rect's contents, this node expands the
- // descendant rect. This is used for effects like pixel-moving filters,
- // where clipped-out content can affect visible output.
- EXPANDS_CLIP
- };
-
- ClipType clip_type;
-
// The clip rect that this node contributes, expressed in the space of its
- // transform node.
+ // transform node. This field is ignored if AppliesLocalClip() is false.
gfx::RectF clip;
// Each element of this cache stores the accumulated clip from this clip
@@ -74,8 +61,11 @@ struct CC_EXPORT ClipNode {
// It is used in the computation of layer's visible rect.
gfx::RectF cached_accumulated_rect_in_screen_space;
- // For nodes that expand, this represents the amount of expansion.
- absl::optional<ClipExpander> clip_expander;
+ // If valid, it's the id of a pixel-moving filter in the effect tree.
+ // Instead of applying |clip|, this clip node expands the accumulated clip
+ // to include any pixels in the contents that can affect the rendering result
+ // with the filter.
+ int pixel_moving_filter_id;
// The id of the transform node that defines the clip node's local space.
int transform_id;
diff --git a/chromium/cc/trees/commit_state.h b/chromium/cc/trees/commit_state.h
index 85f2ad29805..676bfbf1664 100644
--- a/chromium/cc/trees/commit_state.h
+++ b/chromium/cc/trees/commit_state.h
@@ -102,7 +102,7 @@ struct CC_EXPORT CommitState {
LayerSelection selection;
LayerTreeDebugState debug_state;
OverscrollBehavior overscroll_behavior;
- SkColor background_color = SK_ColorWHITE;
+ SkColor4f background_color = SkColors::kWhite;
ViewportPropertyIds viewport_property_ids;
viz::LocalSurfaceId local_surface_id_from_parent;
base::TimeDelta previous_surfaces_visual_update_duration;
diff --git a/chromium/cc/trees/draw_properties_unittest.cc b/chromium/cc/trees/draw_properties_unittest.cc
index 6534341fdfa..016ed515758 100644
--- a/chromium/cc/trees/draw_properties_unittest.cc
+++ b/chromium/cc/trees/draw_properties_unittest.cc
@@ -976,6 +976,8 @@ TEST_F(DrawPropertiesTest, DrawableContentRectForReferenceFilter) {
auto& child_effect_node = CreateEffectNode(child);
child_effect_node.render_surface_reason = RenderSurfaceReason::kTest;
child_effect_node.filters = filters;
+ auto& child_clip_node = CreateClipNode(child);
+ child_clip_node.pixel_moving_filter_id = child_effect_node.id;
UpdateActiveTreeDrawProperties();
@@ -1005,6 +1007,8 @@ TEST_F(DrawPropertiesTest, DrawableContentRectForReferenceFilterHighDpi) {
auto& child_effect_node = CreateEffectNode(child);
child_effect_node.render_surface_reason = RenderSurfaceReason::kTest;
child_effect_node.filters = filters;
+ auto& child_clip_node = CreateClipNode(child);
+ child_clip_node.pixel_moving_filter_id = child_effect_node.id;
UpdateActiveTreeDrawProperties(device_scale_factor);
@@ -1017,6 +1021,53 @@ TEST_F(DrawPropertiesTest, DrawableContentRectForReferenceFilterHighDpi) {
GetRenderSurface(child)->DrawableContentRect());
}
+TEST_F(DrawPropertiesTest, VisibleLayerRectForBlurFilterUnderClip) {
+ LayerImpl* root = root_layer();
+ LayerImpl* child = AddLayer<LayerImpl>();
+
+ root->SetBounds(gfx::Size(100, 100));
+ child->SetBounds(gfx::Size(300, 300));
+ child->SetDrawsContent(true);
+ FilterOperations filters;
+ filters.Append(FilterOperation::CreateBlurFilter(10));
+
+ CreateClipNode(root);
+ CopyProperties(root, child);
+ child->SetOffsetToTransformParent(gfx::Vector2dF(-100, -100));
+ auto& filter_node = CreateEffectNode(child);
+ filter_node.render_surface_reason = RenderSurfaceReason::kFilter;
+ filter_node.filters = filters;
+ auto& clip_node = CreateClipNode(child);
+ clip_node.pixel_moving_filter_id = filter_node.id;
+
+ UpdateActiveTreeDrawProperties();
+ EXPECT_EQ(gfx::Rect(70, 70, 160, 160), child->visible_layer_rect());
+}
+
+TEST_F(DrawPropertiesTest, VisibleLayerRectForReferenceFilterUnderClip) {
+ LayerImpl* root = root_layer();
+ LayerImpl* child = AddLayer<LayerImpl>();
+
+ root->SetBounds(gfx::Size(100, 100));
+ child->SetBounds(gfx::Size(300, 300));
+ child->SetDrawsContent(true);
+ FilterOperations filters;
+ filters.Append(FilterOperation::CreateReferenceFilter(
+ sk_make_sp<OffsetPaintFilter>(50, 50, nullptr)));
+
+ CreateClipNode(root);
+ CopyProperties(root, child);
+ child->SetOffsetToTransformParent(gfx::Vector2dF(-100, -100));
+ auto& filter_node = CreateEffectNode(child);
+ filter_node.render_surface_reason = RenderSurfaceReason::kFilter;
+ filter_node.filters = filters;
+ auto& clip_node = CreateClipNode(child);
+ clip_node.pixel_moving_filter_id = filter_node.id;
+
+ UpdateActiveTreeDrawProperties();
+ EXPECT_EQ(gfx::Rect(100, 100, 150, 150), child->visible_layer_rect());
+}
+
TEST_F(DrawPropertiesTest, RenderSurfaceForBlendMode) {
LayerImpl* root = root_layer();
LayerImpl* child = AddLayer<LayerImpl>();
@@ -2410,6 +2461,32 @@ TEST_F(DrawPropertiesTest,
EXPECT_EQ(gfx::Rect(), grand_child->visible_layer_rect());
}
+TEST_F(DrawPropertiesTest, ClipExpanderWithUninvertibleTransform) {
+ LayerImpl* root = root_layer();
+ LayerImpl* child = AddLayer<LayerImpl>();
+
+ root->SetBounds(gfx::Size(100, 100));
+ child->SetBounds(gfx::Size(50, 50));
+ child->SetDrawsContent(true);
+
+ gfx::Transform uninvertible_matrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
+ ASSERT_FALSE(uninvertible_matrix.IsInvertible());
+
+ CopyProperties(root, child);
+ CreateTransformNode(child).local = uninvertible_matrix;
+ FilterOperations filters;
+ auto& filter_node = CreateEffectNode(child);
+ filter_node.render_surface_reason = RenderSurfaceReason::kFilter;
+ filter_node.filters.Append(FilterOperation::CreateBlurFilter(10));
+ auto& clip_node = CreateClipNode(child);
+ clip_node.pixel_moving_filter_id = filter_node.id;
+
+ UpdateActiveTreeDrawProperties();
+
+ EXPECT_TRUE(child->visible_layer_rect().IsEmpty());
+ EXPECT_TRUE(child->visible_drawable_content_rect().IsEmpty());
+}
+
// Needs layer tree mode: mask layer.
TEST_F(DrawPropertiesTestWithLayerTree, OcclusionBySiblingOfTarget) {
auto root = Layer::Create();
@@ -5411,6 +5488,171 @@ TEST_F(DrawPropertiesStickyPositionTest, StickyPositionNested) {
inner_sticky_impl->ScreenSpaceTransform().To2dTranslation());
}
+class DrawPropertiesAnchorScrollTest : public DrawPropertiesTest {
+ protected:
+ void CreateRoot() {
+ root_ = Layer::Create();
+ root_->SetBounds(gfx::Size(100, 100));
+ host()->SetRootLayer(root_);
+ SetupRootProperties(root_.get());
+ }
+
+ std::pair<scoped_refptr<Layer>, scoped_refptr<Layer>> CreateScroller(
+ Layer* parent) {
+ scoped_refptr<Layer> container = Layer::Create();
+ scoped_refptr<Layer> scroller = Layer::Create();
+ scroller->SetElementId(LayerIdToElementIdForTesting(scroller->id()));
+
+ container->SetBounds(gfx::Size(100, 100));
+ CopyProperties(parent, container.get());
+ root_->AddChild(container);
+
+ scroller->SetBounds(gfx::Size(1000, 1000));
+ CopyProperties(container.get(), scroller.get());
+ CreateTransformNode(scroller.get());
+ CreateScrollNode(scroller.get(), container->bounds());
+ root_->AddChild(scroller);
+
+ return std::make_pair(std::move(container), std::move(scroller));
+ }
+
+ scoped_refptr<Layer> CreateAnchored(Layer* parent,
+ Layer* inner_most_scroller,
+ Layer* outer_most_scroller) {
+ scoped_refptr<Layer> anchored = Layer::Create();
+ anchored->SetBounds(gfx::Size(10, 10));
+ CopyProperties(parent, anchored.get());
+ CreateTransformNode(anchored.get());
+ SetAnchorScrollContainers(anchored.get(),
+ inner_most_scroller->scroll_tree_index(),
+ outer_most_scroller->scroll_tree_index());
+ root_->AddChild(anchored);
+ return anchored;
+ }
+
+ void Commit() {
+ UpdateMainDrawProperties();
+ host_impl()->CreatePendingTree();
+ host()->CommitAndCreatePendingTree();
+ host_impl()->ActivateSyncTree();
+ }
+
+ LayerImpl* GetImpl(Layer* layer) {
+ LayerTreeImpl* layer_tree_impl = host_impl()->active_tree();
+ return layer_tree_impl->LayerById(layer->id());
+ }
+
+ void SetAnchorScrollContainers(Layer* anchored,
+ int inner_most_scroll_container_id,
+ int outer_most_scroll_container_id) {
+ auto& data =
+ GetPropertyTrees(anchored)
+ ->transform_tree_mutable()
+ .EnsureAnchorScrollContainersData(anchored->transform_tree_index());
+ data.inner_most_scroll_container_id = inner_most_scroll_container_id;
+ data.outer_most_scroll_container_id = outer_most_scroll_container_id;
+ }
+
+ scoped_refptr<Layer> root_;
+};
+
+TEST_F(DrawPropertiesAnchorScrollTest, Basics) {
+ // Virtual layer hierarchy:
+ // + root
+ // + container
+ // + scroller <-- anchor
+ // + anchored
+ CreateRoot();
+
+ scoped_refptr<Layer> container;
+ scoped_refptr<Layer> scroller;
+ std::tie(container, scroller) = CreateScroller(root_.get());
+
+ scoped_refptr<Layer> anchored =
+ CreateAnchored(root_.get(), scroller.get(), scroller.get());
+
+ SetPostTranslation(anchored.get(), gfx::Vector2dF(10, 20));
+ Commit();
+
+ EXPECT_VECTOR2DF_EQ(
+ gfx::Vector2dF(10, 20),
+ GetImpl(anchored.get())->ScreenSpaceTransform().To2dTranslation());
+
+ // Scroll the scroller. Anchored element should always move with it.
+
+ SetScrollOffsetDelta(GetImpl(scroller.get()), gfx::Vector2dF(5, 5));
+
+ UpdateActiveTreeDrawProperties();
+ EXPECT_VECTOR2DF_EQ(
+ gfx::Vector2dF(5, 15),
+ GetImpl(anchored.get())->ScreenSpaceTransform().To2dTranslation());
+
+ SetScrollOffsetDelta(GetImpl(scroller.get()), gfx::Vector2dF(15, 25));
+
+ UpdateActiveTreeDrawProperties();
+ EXPECT_VECTOR2DF_EQ(
+ gfx::Vector2dF(-5, -5),
+ GetImpl(anchored.get())->ScreenSpaceTransform().To2dTranslation());
+}
+
+TEST_F(DrawPropertiesAnchorScrollTest, NestedScrollers) {
+ // Virtual layer hierarchy:
+ // + root
+ // + container1
+ // + scroller1
+ // + container2
+ // + scroller2
+ // + container3
+ // + scroller3 <-- anchor
+ // + anchored
+ CreateRoot();
+
+ scoped_refptr<Layer> container1;
+ scoped_refptr<Layer> scroller1;
+ std::tie(container1, scroller1) = CreateScroller(root_.get());
+
+ scoped_refptr<Layer> container2;
+ scoped_refptr<Layer> scroller2;
+ std::tie(container2, scroller2) = CreateScroller(scroller1.get());
+
+ scoped_refptr<Layer> container3;
+ scoped_refptr<Layer> scroller3;
+ std::tie(container3, scroller3) = CreateScroller(scroller2.get());
+
+ scoped_refptr<Layer> anchored =
+ CreateAnchored(scroller1.get(), scroller3.get(), scroller2.get());
+
+ SetPostTranslation(anchored.get(), gfx::Vector2dF(10, 20));
+ Commit();
+
+ EXPECT_VECTOR2DF_EQ(
+ gfx::Vector2dF(10, 20),
+ GetImpl(anchored.get())->ScreenSpaceTransform().To2dTranslation());
+
+ // Scrolling scroller3 will apply the same translation offset to the anchored
+ // element even if it's not a descendant of scroller 3.
+ SetScrollOffsetDelta(GetImpl(scroller3.get()), gfx::Vector2dF(5, 5));
+ UpdateActiveTreeDrawProperties();
+ EXPECT_VECTOR2DF_EQ(
+ gfx::Vector2dF(5, 15),
+ GetImpl(anchored.get())->ScreenSpaceTransform().To2dTranslation());
+
+ // Same to scroller 2.
+ SetScrollOffsetDelta(GetImpl(scroller2.get()), gfx::Vector2dF(10, 15));
+ UpdateActiveTreeDrawProperties();
+ EXPECT_VECTOR2DF_EQ(
+ gfx::Vector2dF(-5, 0),
+ GetImpl(anchored.get())->ScreenSpaceTransform().To2dTranslation());
+
+ // Scrolling scroller1 natually moves the anchored element because it's
+ // already a descendant. Note that we should not apply a double translation
+ // offset to it.
+ SetScrollOffsetDelta(GetImpl(scroller1.get()), gfx::Vector2dF(15, 20));
+ UpdateActiveTreeDrawProperties();
+ EXPECT_VECTOR2DF_EQ(
+ gfx::Vector2dF(-20, -20),
+ GetImpl(anchored.get())->ScreenSpaceTransform().To2dTranslation());
+}
class AnimationScaleFactorTrackingLayerImpl : public LayerImpl {
public:
static std::unique_ptr<AnimationScaleFactorTrackingLayerImpl> Create(
diff --git a/chromium/cc/trees/draw_property_utils.cc b/chromium/cc/trees/draw_property_utils.cc
index b9d99c69cb4..5c592fac0c0 100644
--- a/chromium/cc/trees/draw_property_utils.cc
+++ b/chromium/cc/trees/draw_property_utils.cc
@@ -161,58 +161,65 @@ ConditionalClip ComputeCurrentClip(const ClipNode* clip_node,
return ConditionalClip{true /* is_clipped */, current_clip};
}
+bool ExpandClipForPixelMovingFilter(const PropertyTrees* property_trees,
+ int target_id,
+ const EffectNode* filter_node,
+ gfx::RectF* clip_rect) {
+ // Bring the accumulated clip to the space of the pixel-moving filter.
+ gfx::RectF clip_rect_in_mapping_space;
+ bool success = ConvertRectBetweenSurfaceSpaces(property_trees, target_id,
+ filter_node->id, *clip_rect,
+ &clip_rect_in_mapping_space);
+ // If transform is not invertible, no clip will be applied.
+ if (!success)
+ return false;
+
+ // Do the expansion.
+ SkMatrix filter_draw_matrix =
+ SkMatrix::Scale(filter_node->surface_contents_scale.x(),
+ filter_node->surface_contents_scale.y());
+ gfx::RectF mapped_clip_in_mapping_space(filter_node->filters.MapRect(
+ ToEnclosingClipRect(clip_rect_in_mapping_space), filter_draw_matrix));
+
+ // Put the expanded clip back into the original target space.
+ gfx::RectF original_clip_rect = *clip_rect;
+ success = ConvertRectBetweenSurfaceSpaces(
+ property_trees, filter_node->id, target_id, mapped_clip_in_mapping_space,
+ clip_rect);
+ // If transform is not invertible, no clip will be applied.
+ if (!success)
+ return false;
+
+ // Ensure the clip is expanded in the target space, in case that the
+ // mapped accumulated_clip doesn't contain the original.
+ clip_rect->Union(original_clip_rect);
+ return true;
+}
+
bool ApplyClipNodeToAccumulatedClip(const PropertyTrees* property_trees,
bool include_expanding_clips,
int target_id,
int target_transform_id,
const ClipNode* clip_node,
gfx::RectF* accumulated_clip) {
- switch (clip_node->clip_type) {
- case ClipNode::ClipType::APPLIES_LOCAL_CLIP: {
- ConditionalClip current_clip = ComputeCurrentClip(
- clip_node, property_trees, target_transform_id, target_id);
-
- // If transform is not invertible, no clip will be applied.
- if (!current_clip.is_clipped)
- return false;
-
- *accumulated_clip =
- gfx::IntersectRects(*accumulated_clip, current_clip.clip_rect);
+ if (!clip_node->AppliesLocalClip()) {
+ if (!include_expanding_clips)
return true;
- }
- case ClipNode::ClipType::EXPANDS_CLIP: {
- if (!include_expanding_clips)
- return true;
-
- // Bring the accumulated clip to the space of the expanding effect.
- const EffectNode* expanding_effect_node =
- property_trees->effect_tree().Node(
- clip_node->clip_expander->target_effect_id());
- gfx::RectF accumulated_clip_rect_in_expanding_space;
- bool success = ConvertRectBetweenSurfaceSpaces(
- property_trees, target_id, expanding_effect_node->id,
- *accumulated_clip, &accumulated_clip_rect_in_expanding_space);
- // If transform is not invertible, no clip will be applied.
- if (!success)
- return false;
-
- // Do the expansion.
- gfx::RectF expanded_clip_in_expanding_space =
- gfx::RectF(clip_node->clip_expander->MapRect(
- ToEnclosingClipRect(accumulated_clip_rect_in_expanding_space),
- property_trees));
-
- // Put the expanded clip back into the original target space.
- success = ConvertRectBetweenSurfaceSpaces(
- property_trees, expanding_effect_node->id, target_id,
- expanded_clip_in_expanding_space, accumulated_clip);
- // If transform is not invertible, no clip will be applied.
- if (!success)
- return false;
- return true;
- }
+ const EffectNode* filter_node =
+ property_trees->effect_tree().Node(clip_node->pixel_moving_filter_id);
+ DCHECK(filter_node);
+ return ExpandClipForPixelMovingFilter(property_trees, target_id,
+ filter_node, accumulated_clip);
}
- NOTREACHED();
+
+ ConditionalClip current_clip = ComputeCurrentClip(
+ clip_node, property_trees, target_transform_id, target_id);
+
+ // If transform is not invertible, no clip will be applied.
+ if (!current_clip.is_clipped)
+ return false;
+
+ accumulated_clip->Intersect(current_clip.clip_rect);
return true;
}
@@ -293,13 +300,12 @@ ConditionalClip ComputeAccumulatedClip(PropertyTrees* property_trees,
} else {
// No cache hit or the cached clip has no clip to apply. We need to find
// the first clip that applies clip as there is no clip to expand.
- while (clip_node->clip_type != ClipNode::ClipType::APPLIES_LOCAL_CLIP &&
- parent_chain.size() > 0) {
+ while (!clip_node->AppliesLocalClip() && parent_chain.size() > 0) {
clip_node = parent_chain.top();
parent_chain.pop();
}
- if (clip_node->clip_type != ClipNode::ClipType::APPLIES_LOCAL_CLIP) {
+ if (!clip_node->AppliesLocalClip()) {
// No clip to apply.
cached_data->clip = unclipped;
return unclipped;
@@ -555,7 +561,7 @@ void SetSurfaceIsClipped(const ClipTree& clip_tree,
// If the clips between the render surface and its target only expand the
// clips and do not apply any new clip, we need not clip the render surface.
const ClipNode* clip_node = clip_tree.Node(render_surface->ClipTreeIndex());
- is_clipped = clip_node->clip_type != ClipNode::ClipType::EXPANDS_CLIP;
+ is_clipped = clip_node->AppliesLocalClip();
}
render_surface->SetIsClipped(is_clipped);
}
@@ -847,8 +853,8 @@ void ComputeClips(PropertyTrees* property_trees) {
bool success = ApplyClipNodeToAccumulatedClip(
property_trees, include_expanding_clips, target_effect_id,
target_transform_id, clip_node, &accumulated_clip);
- DCHECK(success);
- clip_node->cached_accumulated_rect_in_screen_space = accumulated_clip;
+ if (success)
+ clip_node->cached_accumulated_rect_in_screen_space = accumulated_clip;
}
clip_tree->set_needs_update(false);
}
diff --git a/chromium/cc/trees/effect_node.cc b/chromium/cc/trees/effect_node.cc
index ffaddbaecc2..4397d4178e1 100644
--- a/chromium/cc/trees/effect_node.cc
+++ b/chromium/cc/trees/effect_node.cc
@@ -189,7 +189,8 @@ void EffectNode::AsValueInto(base::trace_event::TracedValue* value) const {
}
if (mask_filter_info.HasGradientMask()) {
MathUtil::AddToTracedValue("mask_filter_gradient_mask",
- mask_filter_info.gradient_mask(), value);
+ mask_filter_info.gradient_mask().value(),
+ value);
}
}
value->SetString("blend_mode", SkBlendMode_Name(blend_mode));
diff --git a/chromium/cc/trees/layer_tree_host.cc b/chromium/cc/trees/layer_tree_host.cc
index 9636bffb09f..e40fd58b7ef 100644
--- a/chromium/cc/trees/layer_tree_host.cc
+++ b/chromium/cc/trees/layer_tree_host.cc
@@ -650,10 +650,12 @@ bool LayerTreeHost::IsDeferringCommits() const {
return proxy_->IsDeferringCommits();
}
-void LayerTreeHost::OnDeferCommitsChanged(bool defer_status,
- PaintHoldingReason reason) {
+void LayerTreeHost::OnDeferCommitsChanged(
+ bool defer_status,
+ PaintHoldingReason reason,
+ absl::optional<PaintHoldingCommitTrigger> trigger) {
DCHECK(IsMainThread());
- client_->OnDeferCommitsChanged(defer_status, reason);
+ client_->OnDeferCommitsChanged(defer_status, reason, trigger);
}
DISABLE_CFI_PERF
@@ -1978,9 +1980,9 @@ LayerTreeHost::TakeDocumentTransitionCallbacksForTesting() {
return result;
}
-uint32_t LayerTreeHost::GetAverageThroughput() const {
+double LayerTreeHost::GetPercentDroppedFrames() const {
DCHECK(IsMainThread());
- return proxy_->GetAverageThroughput();
+ return proxy_->GetPercentDroppedFrames();
}
void LayerTreeHost::IncrementVisualUpdateDuration(
diff --git a/chromium/cc/trees/layer_tree_host.h b/chromium/cc/trees/layer_tree_host.h
index abe129ddb22..cdba296d01c 100644
--- a/chromium/cc/trees/layer_tree_host.h
+++ b/chromium/cc/trees/layer_tree_host.h
@@ -317,7 +317,9 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
bool IsDeferringCommits() const;
// Notification that the proxy started or stopped deferring commits.
- void OnDeferCommitsChanged(bool defer_status, PaintHoldingReason reason);
+ void OnDeferCommitsChanged(bool defer_status,
+ PaintHoldingReason reason,
+ absl::optional<PaintHoldingCommitTrigger> trigger);
// Returns whether there are any outstanding ScopedDeferMainFrameUpdate,
// though commits may be deferred also when the local_surface_id_from_parent()
@@ -498,10 +500,10 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
return pending_commit_state()->max_page_scale_factor;
}
- void set_background_color(SkColor color) {
+ void set_background_color(SkColor4f color) {
pending_commit_state()->background_color = color;
}
- SkColor background_color() const {
+ SkColor4f background_color() const {
return pending_commit_state()->background_color;
}
@@ -837,8 +839,8 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
std::vector<base::OnceClosure> TakeDocumentTransitionCallbacksForTesting();
- // Returns a percentage representing average throughput of last X seconds.
- uint32_t GetAverageThroughput() const;
+ // Returns a percentage of dropped frames of the last second.
+ double GetPercentDroppedFrames() const;
// TODO(szager): Remove these once threaded compositing is enabled for all
// web_tests.
diff --git a/chromium/cc/trees/layer_tree_host_client.h b/chromium/cc/trees/layer_tree_host_client.h
index f52db87ce1a..63415aad372 100644
--- a/chromium/cc/trees/layer_tree_host_client.h
+++ b/chromium/cc/trees/layer_tree_host_client.h
@@ -13,6 +13,7 @@
#include "cc/input/browser_controls_state.h"
#include "cc/metrics/event_latency_tracker.h"
#include "cc/metrics/frame_sequence_tracker_collection.h"
+#include "cc/trees/paint_holding_commit_trigger.h"
#include "cc/trees/paint_holding_reason.h"
#include "cc/trees/property_tree.h"
#include "ui/gfx/geometry/vector2d_f.h"
@@ -125,9 +126,13 @@ class LayerTreeHostClient {
virtual void OnDeferMainFrameUpdatesChanged(bool) = 0;
// Notification that the proxy started or stopped deferring commits. |reason|
- // indicates why commits are/were deferred.
- virtual void OnDeferCommitsChanged(bool defer_status,
- PaintHoldingReason reason) = 0;
+ // indicates why commits are/were deferred. |trigger| indicates why the commit
+ // restarted. |trigger| is always provided on restarts, when |defer_status|
+ // switches to false.
+ virtual void OnDeferCommitsChanged(
+ bool defer_status,
+ PaintHoldingReason reason,
+ absl::optional<PaintHoldingCommitTrigger> trigger) = 0;
// Visual frame-based updates to the state of the LayerTreeHost are expected
// to happen only in calls to LayerTreeHostClient::UpdateLayerTreeHost, which
diff --git a/chromium/cc/trees/layer_tree_host_impl.cc b/chromium/cc/trees/layer_tree_host_impl.cc
index aca208728d0..5542037a338 100644
--- a/chromium/cc/trees/layer_tree_host_impl.cc
+++ b/chromium/cc/trees/layer_tree_host_impl.cc
@@ -257,6 +257,26 @@ void RecordSourceIdConsistency(bool all_valid, bool all_unique) {
consistency);
}
+// Dump verbose log with
+// --vmodule=layer_tree_host_impl=3 for renderer only, or
+// --vmodule=layer_tree_host_impl=4 for all clients.
+bool VerboseLogEnabled() {
+ if (!VLOG_IS_ON(3))
+ return false;
+ if (VLOG_IS_ON(4))
+ return true;
+ const char* client_name = GetClientNameForMetrics();
+ return client_name && strcmp(client_name, "Renderer") == 0;
+}
+
+const char* ClientNameForVerboseLog() {
+ const char* client_name = GetClientNameForMetrics();
+ return client_name ? client_name : "<unknown client>";
+}
+
+#define VERBOSE_LOG() \
+ VLOG_IF(3, VerboseLogEnabled()) << ClientNameForVerboseLog() << ": "
+
} // namespace
void LayerTreeHostImpl::DidUpdateScrollAnimationCurve() {
@@ -385,12 +405,6 @@ LayerTreeHostImpl::LayerTreeHostImpl(
scheduling_client_(scheduling_client),
task_runner_provider_(task_runner_provider),
current_begin_frame_tracker_(FROM_HERE),
- compositor_frame_reporting_controller_(
- std::make_unique<CompositorFrameReportingController>(
- /*should_report_histograms=*/!settings
- .single_thread_proxy_scheduler,
- /*should_report_ukm=*/!settings.single_thread_proxy_scheduler,
- id)),
settings_(settings),
is_synchronous_single_threaded_(!task_runner_provider->HasImplThread() &&
!settings_.single_thread_proxy_scheduler),
@@ -418,7 +432,12 @@ LayerTreeHostImpl::LayerTreeHostImpl(
image_animation_controller_(GetTaskRunner(),
this,
settings_.enable_image_animation_resync),
- paint_image_generator_client_id_(PaintImage::GetNextGeneratorClientId()),
+ compositor_frame_reporting_controller_(
+ std::make_unique<CompositorFrameReportingController>(
+ /*should_report_histograms=*/!settings
+ .single_thread_proxy_scheduler,
+ /*should_report_ukm=*/!settings.single_thread_proxy_scheduler,
+ id)),
frame_trackers_(settings.single_thread_proxy_scheduler,
compositor_frame_reporting_controller_.get()),
lcd_text_metrics_reporter_(LCDTextMetricsReporter::CreateIfNeeded(this)),
@@ -463,11 +482,11 @@ LayerTreeHostImpl::LayerTreeHostImpl(
if (is_ui) {
compositor_frame_reporting_controller_->set_event_latency_tracker(this);
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
dropped_frame_counter_.EnableReporForUI();
compositor_frame_reporting_controller_->SetThreadAffectsSmoothness(
FrameInfo::SmoothEffectDrivingThread::kMain, true);
-#endif // BUILDFLAG(IS_CHROMEOS_ASH)
+#endif // BUILDFLAG(IS_CHROMEOS)
}
dropped_frame_counter_.set_total_counter(&total_frame_counter_);
@@ -513,19 +532,27 @@ LayerTreeHostImpl::~LayerTreeHostImpl() {
// Clear the UKM Manager so that we do not try to report when the
// UKM System has shut down.
compositor_frame_reporting_controller_->SetUkmManager(nullptr);
- compositor_frame_reporting_controller_ = nullptr;
+ // `frame_trackers_` holds a pointer to
+ // `compositor_frame_reporting_controller_`. Setting
+ // `compositor_frame_reporting_controller_` to nullptr here leads to
+ // `frame_trackers_` holding a dangling ptr. Don't set to null here and let
+ // members be destroyed in reverse order of declaration.
+ // Since `frame_trackers_` is destroyed first, we need to clear the ptr that
+ // `compositor_frame_reporting_controller_` holds.
+ compositor_frame_reporting_controller_->SetFrameSequenceTrackerCollection(
+ nullptr);
}
-ThreadedInputHandler& LayerTreeHostImpl::GetInputHandler() {
+InputHandler& LayerTreeHostImpl::GetInputHandler() {
DCHECK(input_delegate_) << "Requested InputHandler when one wasn't bound. "
"Call BindToInputHandler to bind to one";
- return static_cast<ThreadedInputHandler&>(*input_delegate_.get());
+ return static_cast<InputHandler&>(*input_delegate_.get());
}
-const ThreadedInputHandler& LayerTreeHostImpl::GetInputHandler() const {
+const InputHandler& LayerTreeHostImpl::GetInputHandler() const {
DCHECK(input_delegate_) << "Requested InputHandler when one wasn't bound. "
"Call BindToInputHandler to bind to one";
- return static_cast<const ThreadedInputHandler&>(*input_delegate_.get());
+ return static_cast<const InputHandler&>(*input_delegate_.get());
}
void LayerTreeHostImpl::DidSendBeginMainFrame(const viz::BeginFrameArgs& args) {
@@ -547,8 +574,10 @@ void LayerTreeHostImpl::BeginMainFrameAborted(
// If the begin frame data was handled, then scroll and scale set was applied
// by the main thread, so the active tree needs to be updated as if these sent
// values were applied and committed.
- if (CommitEarlyOutHandledCommit(reason)) {
- active_tree_->ApplySentScrollAndScaleDeltasFromAbortedCommit();
+ bool main_frame_applied_deltas = MainFrameAppliedDeltas(reason);
+ active_tree_->ApplySentScrollAndScaleDeltasFromAbortedCommit(
+ main_frame_applied_deltas);
+ if (main_frame_applied_deltas) {
if (pending_tree_) {
pending_tree_->AppendSwapPromises(std::move(swap_promises));
} else {
@@ -627,19 +656,12 @@ void LayerTreeHostImpl::FinishCommit(
for (auto& benchmark : state.benchmarks)
ScheduleMicroBenchmark(std::move(benchmark));
- // Dump property trees and layers if run with:
- // --vmodule=layer_tree_host=3
- if (VLOG_IS_ON(3)) {
- const char* client_name = GetClientNameForMetrics();
- if (!client_name)
- client_name = "<unknown client>";
- VLOG(3) << "After finishing (" << client_name
- << ") commit on impl, the sync tree:"
- << "\nproperty_trees:\n"
- << tree->property_trees()->ToString() << "\n"
- << "cc::LayerImpls:\n"
- << tree->LayerListAsJson();
- }
+ // Dump property trees and layers if VerboseLogEnabled().
+ VERBOSE_LOG() << "After finishing commit on impl, the sync tree:"
+ << "\nproperty_trees:\n"
+ << tree->property_trees()->ToString() << "\n"
+ << "cc::LayerImpls:\n"
+ << tree->LayerListAsJson();
}
void LayerTreeHostImpl::PullLayerTreeHostPropertiesFrom(
@@ -701,7 +723,7 @@ void LayerTreeHostImpl::CommitComplete() {
// Start animations before UpdateDrawProperties and PrepareTiles, as they can
// change the results. When doing commit to the active tree, this must happen
- // after ActivateAnimations() in order for this ticking to be propogated
+ // after ActivateAnimations() in order for this ticking to be propagated
// to layers on the active tree.
if (CommitToActiveTree())
Animate();
@@ -1081,7 +1103,7 @@ void LayerTreeHostImpl::FrameData::AsValueInto(
// Quad data can be quite large, so only dump render passes if we are
// logging verbosely or viz.quads tracing category is enabled.
- bool quads_enabled = VLOG_IS_ON(3);
+ bool quads_enabled = VerboseLogEnabled();
if (!quads_enabled) {
TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("viz.quads"),
&quads_enabled);
@@ -1116,9 +1138,9 @@ DrawMode LayerTreeHostImpl::GetDrawMode() const {
static void AppendQuadsToFillScreen(
viz::CompositorRenderPass* target_render_pass,
const RenderSurfaceImpl* root_render_surface,
- SkColor screen_background_color,
+ SkColor4f screen_background_color,
const Region& fill_region) {
- if (!root_render_surface || !SkColorGetA(screen_background_color))
+ if (!root_render_surface || !screen_background_color.fA)
return;
if (fill_region.IsEmpty())
return;
@@ -1131,13 +1153,12 @@ static void AppendQuadsToFillScreen(
gfx::Rect root_target_rect = root_render_surface->content_rect();
float opacity = 1.f;
int sorting_context_id = 0;
- bool are_contents_opaque = SkColorGetA(screen_background_color) == 0xFF;
viz::SharedQuadState* shared_quad_state =
target_render_pass->CreateAndAppendSharedQuadState();
shared_quad_state->SetAll(gfx::Transform(), root_target_rect,
root_target_rect, gfx::MaskFilterInfo(),
- absl::nullopt, are_contents_opaque, opacity,
- SkBlendMode::kSrcOver, sorting_context_id);
+ absl::nullopt, screen_background_color.isOpaque(),
+ opacity, SkBlendMode::kSrcOver, sorting_context_id);
for (gfx::Rect screen_space_rect : fill_region) {
gfx::Rect visible_screen_space_rect = screen_space_rect;
@@ -1442,7 +1463,7 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) {
active_tree_->GetDeviceViewport().origin());
#endif
bool has_transparent_background =
- SkColorGetA(active_tree_->background_color()) != SK_AlphaOPAQUE;
+ !active_tree_->background_color().isOpaque();
auto* root_render_surface = active_tree_->RootRenderSurface();
if (root_render_surface && !has_transparent_background) {
frame->render_passes.back()->has_transparent_background = false;
@@ -1539,36 +1560,41 @@ DrawResult LayerTreeHostImpl::PrepareToDraw(FrameData* frame) {
if (input_delegate_)
input_delegate_->WillDraw();
- // |client_name| is used for various UMA histograms below.
- // GetClientNameForMetrics only returns one non-null value over the lifetime
- // of the process, so the histogram names are runtime constant.
- const char* client_name = GetClientNameForMetrics();
- if (client_name) {
- size_t total_gpu_memory_for_tilings_in_bytes = 0;
- for (const PictureLayerImpl* layer : active_tree()->picture_layers())
- total_gpu_memory_for_tilings_in_bytes += layer->GPUMemoryUsageInBytes();
-
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- base::StringPrintf("Compositing.%s.NumActiveLayers", client_name),
- base::saturated_cast<int>(active_tree_->NumLayers()), 1, 1000, 20);
-
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- base::StringPrintf("Compositing.%s.NumActivePictureLayers",
- client_name),
- base::saturated_cast<int>(active_tree_->picture_layers().size()), 1,
- 1000, 20);
-
- // TODO(pdr): Instead of skipping empty picture layers, maybe we should
- // accumulate layer->GetRasterSource()->GetMemoryUsage() above and skip
- // recording when the accumulated memory usage is 0.
- if (!active_tree()->picture_layers().empty()) {
+ // No need to record metrics each time we draw, 1% is enough.
+ constexpr double kSamplingFrequency = .01;
+ if (!downsample_metrics_ ||
+ metrics_subsampler_.ShouldSample(kSamplingFrequency)) {
+ // |client_name| is used for various UMA histograms below.
+ // GetClientNameForMetrics only returns one non-null value over the lifetime
+ // of the process, so the histogram names are runtime constant.
+ const char* client_name = GetClientNameForMetrics();
+ if (client_name) {
+ size_t total_gpu_memory_for_tilings_in_bytes = 0;
+ for (const PictureLayerImpl* layer : active_tree()->picture_layers())
+ total_gpu_memory_for_tilings_in_bytes += layer->GPUMemoryUsageInBytes();
+
UMA_HISTOGRAM_CUSTOM_COUNTS(
- base::StringPrintf("Compositing.%s.GPUMemoryForTilingsInKb",
+ base::StringPrintf("Compositing.%s.NumActiveLayers", client_name),
+ base::saturated_cast<int>(active_tree_->NumLayers()), 1, 1000, 20);
+
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ base::StringPrintf("Compositing.%s.NumActivePictureLayers",
client_name),
- base::saturated_cast<int>(total_gpu_memory_for_tilings_in_bytes /
- 1024),
- 1, kGPUMemoryForTilingsLargestBucketKb,
- kGPUMemoryForTilingsBucketCount);
+ base::saturated_cast<int>(active_tree_->picture_layers().size()), 1,
+ 1000, 20);
+
+ // TODO(pdr): Instead of skipping empty picture layers, maybe we should
+ // accumulate layer->GetRasterSource()->GetMemoryUsage() above and skip
+ // recording when the accumulated memory usage is 0.
+ if (!active_tree()->picture_layers().empty()) {
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ base::StringPrintf("Compositing.%s.GPUMemoryForTilingsInKb",
+ client_name),
+ base::saturated_cast<int>(total_gpu_memory_for_tilings_in_bytes /
+ 1024),
+ 1, kGPUMemoryForTilingsLargestBucketKb,
+ kGPUMemoryForTilingsBucketCount);
+ }
}
}
@@ -1601,13 +1627,8 @@ DrawResult LayerTreeHostImpl::PrepareToDraw(FrameData* frame) {
DrawResult draw_result = CalculateRenderPasses(frame);
- // Dump render passes and draw quads if run with:
- // --vmodule=layer_tree_host_impl=3
- if (VLOG_IS_ON(3)) {
- VLOG(3) << "Prepare to draw ("
- << (client_name ? client_name : "<unknown client>") << ")\n"
- << frame->ToString();
- }
+ // Dump render passes and draw quads if VerboseLogEnabled().
+ VERBOSE_LOG() << "Prepare to draw\n" << frame->ToString();
if (draw_result != DRAW_SUCCESS) {
DCHECK(!resourceless_software_draw_);
@@ -1937,10 +1958,10 @@ size_t LayerTreeHostImpl::GetFrameIndexForImage(const PaintImage& paint_image,
int LayerTreeHostImpl::GetMSAASampleCountForRaster(
const scoped_refptr<DisplayItemList>& display_list) {
- constexpr int kMinNumberOfSlowPathsForMSAA = 6;
- if (display_list->num_slow_paths() < kMinNumberOfSlowPathsForMSAA)
+ if (display_list->num_slow_paths_up_to_min_for_MSAA() <
+ kMinNumberOfSlowPathsForMSAA) {
return 0;
-
+ }
if (!can_use_msaa_)
return 0;
@@ -2258,6 +2279,7 @@ viz::CompositorFrameMetadata LayerTreeHostImpl::MakeCompositorFrameMetadata() {
metadata.page_scale_factor = active_tree_->current_page_scale_factor();
metadata.scrollable_viewport_size = active_tree_->ScrollableViewportSize();
+
metadata.root_background_color = active_tree_->background_color();
metadata.may_throttle_if_undrawn_frames = may_throttle_if_undrawn_frames_;
@@ -2459,13 +2481,10 @@ absl::optional<LayerTreeHostImpl::SubmitInfo> LayerTreeHostImpl::DrawLayers(
lag_tracking_manager_.CollectScrollEventsFromFrame(frame_token,
events_metrics);
- // Dump property trees and layers if run with:
- // --vmodule=layer_tree_host_impl=3
- if (VLOG_IS_ON(3)) {
- VLOG(3) << "Submitting a frame:\n"
- << viz::TransitionUtils::RenderPassListToString(
- compositor_frame.render_pass_list);
- }
+ // Dump property trees and layers if VerboseLogEnabled().
+ VERBOSE_LOG() << "Submitting a frame:\n"
+ << viz::TransitionUtils::RenderPassListToString(
+ compositor_frame.render_pass_list);
base::TimeTicks submit_time = base::TimeTicks::Now();
{
@@ -2936,11 +2955,16 @@ bool LayerTreeHostImpl::WillBeginImplFrame(const viz::BeginFrameArgs& args) {
// it will push the updated viz::LocalSurfaceId. Begin Impl Frame production
// if it has already become activated, or is on the |pending_tree| to be
// activated during this frame's production.
- const viz::LocalSurfaceId& upcoming_lsid =
- pending_tree() ? pending_tree()->local_surface_id_from_parent()
- : active_tree()->local_surface_id_from_parent();
- if (target_local_surface_id_.IsNewerThan(upcoming_lsid)) {
- return false;
+ //
+ // However when using a synchronous compositor we skip this throttling
+ // completely.
+ if (!settings_.using_synchronous_renderer_compositor) {
+ const viz::LocalSurfaceId& upcoming_lsid =
+ pending_tree() ? pending_tree()->local_surface_id_from_parent()
+ : active_tree()->local_surface_id_from_parent();
+ if (target_local_surface_id_.IsNewerThan(upcoming_lsid)) {
+ return false;
+ }
}
if (is_likely_to_require_a_draw_) {
@@ -3388,19 +3412,12 @@ void LayerTreeHostImpl::ActivateSyncTree() {
AllocateLocalSurfaceId();
}
- // Dump property trees and layers if run with:
- // --vmodule=layer_tree_host_impl=3
- if (VLOG_IS_ON(3)) {
- const char* client_name = GetClientNameForMetrics();
- if (!client_name)
- client_name = "<unknown client>";
- VLOG(3) << "After activating (" << client_name
- << ") sync tree, the active tree:"
- << "\nproperty_trees:\n"
- << active_tree_->property_trees()->ToString() << "\n"
- << "cc::LayerImpls:\n"
- << active_tree_->LayerListAsJson();
- }
+ // Dump property trees and layers if VerboseLogEnabled().
+ VERBOSE_LOG() << "After activating sync tree, the active tree:"
+ << "\nproperty_trees:\n"
+ << active_tree_->property_trees()->ToString() << "\n"
+ << "cc::LayerImpls:\n"
+ << active_tree_->LayerListAsJson();
}
void LayerTreeHostImpl::ActivateStateForImages() {
@@ -3414,7 +3431,7 @@ void LayerTreeHostImpl::OnMemoryPressure(
if (!base::SysInfo::IsLowEndDevice())
return;
- if (level != base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL)
+ if (!ImageDecodeCacheUtils::ShouldEvictCaches(level))
return;
// TODO(crbug.com/1189208): Unlocking decoded-image-tracker images causes
@@ -3432,14 +3449,15 @@ void LayerTreeHostImpl::OnMemoryPressure(
recycle_tree_->OnPurgeMemory();
EvictAllUIResources();
- if (image_decode_cache_) {
- image_decode_cache_->SetShouldAggressivelyFreeResources(true);
- image_decode_cache_->SetShouldAggressivelyFreeResources(false);
- }
if (resource_pool_)
resource_pool_->OnMemoryPressure(level);
tile_manager_.decoded_image_tracker().UnlockAllImages();
+
+ // There is no need to notify the |image_decode_cache| about the memory
+ // pressure as it (the gpu one as the software one doesn't keep outstanding
+ // images pinned) listens to memory pressure events and purges memory base on
+ // the ImageDecodeCacheUtils::ShouldEvictCaches' return value.
}
void LayerTreeHostImpl::SetVisible(bool visible) {
@@ -3552,7 +3570,7 @@ void LayerTreeHostImpl::CreateTileManagerResources() {
viz::ResourceFormatToClosestSkColorType(/*gpu_compositing=*/true,
tile_format),
settings_.decoded_image_working_set_budget_bytes, max_texture_size_,
- paint_image_generator_client_id_, dark_mode_filter_);
+ dark_mode_filter_);
pending_raster_queries_ = std::make_unique<RasterQueryQueue>(
layer_tree_frame_sink_->worker_context_provider());
@@ -3561,8 +3579,7 @@ void LayerTreeHostImpl::CreateTileManagerResources() {
bool gpu_compositing = !!layer_tree_frame_sink_->context_provider();
image_decode_cache_ = std::make_unique<SoftwareImageDecodeCache>(
viz::ResourceFormatToClosestSkColorType(gpu_compositing, tile_format),
- settings_.decoded_image_working_set_budget_bytes,
- paint_image_generator_client_id_);
+ settings_.decoded_image_working_set_budget_bytes);
}
raster_buffer_provider_ = CreateRasterBufferProvider();
@@ -4103,8 +4120,12 @@ void LayerTreeHostImpl::CollectScrollbarUpdatesForCommit(
CompositorCommitData* commit_data) const {
commit_data->scrollbars.reserve(scrollbar_animation_controllers_.size());
for (auto& pair : scrollbar_animation_controllers_) {
- commit_data->scrollbars.push_back(
- {pair.first, pair.second->ScrollbarsHidden()});
+ if (pair.second->visibility_changed() ||
+ !settings_.enable_scroll_update_optimizations) {
+ commit_data->scrollbars.push_back(
+ {pair.first, pair.second->ScrollbarsHidden()});
+ pair.second->ClearVisibilityChanged();
+ }
}
}
diff --git a/chromium/cc/trees/layer_tree_host_impl.h b/chromium/cc/trees/layer_tree_host_impl.h
index 1b985be80c6..c2176e110cd 100644
--- a/chromium/cc/trees/layer_tree_host_impl.h
+++ b/chromium/cc/trees/layer_tree_host_impl.h
@@ -20,6 +20,7 @@
#include "base/containers/lru_cache.h"
#include "base/memory/memory_pressure_listener.h"
#include "base/memory/shared_memory_mapping.h"
+#include "base/rand_util.h"
#include "base/task/sequenced_task_runner.h"
#include "base/time/time.h"
#include "cc/benchmarks/micro_benchmark_controller_impl.h"
@@ -28,7 +29,6 @@
#include "cc/input/browser_controls_offset_manager_client.h"
#include "cc/input/input_handler.h"
#include "cc/input/scrollbar_animation_controller.h"
-#include "cc/input/threaded_input_handler.h"
#include "cc/layers/layer_collections.h"
#include "cc/metrics/average_lag_tracking_manager.h"
#include "cc/metrics/dropped_frame_counter.h"
@@ -278,8 +278,8 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient,
// TODO(bokan): This getter is an escape-hatch for code that hasn't yet been
// cleaned up to decouple input from graphics. Callers should be cleaned up
// to avoid calling it and it should be removed.
- ThreadedInputHandler& GetInputHandler();
- const ThreadedInputHandler& GetInputHandler() const;
+ InputHandler& GetInputHandler();
+ const InputHandler& GetInputHandler() const;
void StartPageScaleAnimation(const gfx::Point& target_offset,
bool anchor_point,
@@ -350,7 +350,7 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient,
void SetFullViewportDamage();
void SetViewportDamage(const gfx::Rect& damage_rect);
- // Interface for ThreadedInputHandler
+ // Interface for InputHandler
void BindToInputHandler(
std::unique_ptr<InputDelegateForCompositor> delegate) override;
ScrollTree& GetScrollTree() const override;
@@ -672,7 +672,7 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient,
// TODO(bokan): These input-related methods shouldn't be part of
// LayerTreeHostImpl's interface.
bool IsPinchGestureActive() const;
- // See comment in equivalent ThreadedInputHandler method for what this means.
+ // See comment in equivalent InputHandler method for what this means.
ActivelyScrollingType GetActivelyScrollingType() const;
bool ScrollAffectsScrollHandler() const;
bool CurrentScrollCheckerboardsDueToNoRecording() const {
@@ -899,6 +899,10 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient,
void RequestImplSideInvalidationForRerasterTiling();
+ void SetDownsampleMetricsForTesting(bool value) {
+ downsample_metrics_ = value;
+ }
+
protected:
LayerTreeHostImpl(
const LayerTreeSettings& settings,
@@ -930,9 +934,6 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient,
BeginFrameTracker current_begin_frame_tracker_;
- std::unique_ptr<CompositorFrameReportingController>
- compositor_frame_reporting_controller_;
-
private:
viz::CompositorFrame GenerateCompositorFrame(FrameData* frame);
@@ -1127,8 +1128,12 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient,
std::unique_ptr<PageScaleAnimation> page_scale_animation_;
- DroppedFrameCounter dropped_frame_counter_;
+ base::WritableSharedMemoryMapping ukm_smoothness_mapping_;
+
TotalFrameCounter total_frame_counter_;
+ // `dropped_frame_counter_` holds a pointer `to ukm_smoothness_mapping_` so
+ // it must be declared last and deleted first;
+ DroppedFrameCounter dropped_frame_counter_;
std::unique_ptr<MemoryHistory> memory_history_;
std::unique_ptr<DebugRectHistory> debug_rect_history_;
@@ -1239,8 +1244,10 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient,
PresentationTimeCallbackBuffer presentation_time_callbacks_;
- const PaintImage::GeneratorClientId paint_image_generator_client_id_;
-
+ // `compositor_frame_reporting_controller_` has a dependency on
+ // `dropped_frame_counter_` so it must be declared last and deleted first;
+ std::unique_ptr<CompositorFrameReportingController>
+ compositor_frame_reporting_controller_;
FrameSequenceTrackerCollection frame_trackers_;
// PaintWorklet painting is controlled from the LayerTreeHostImpl, dispatched
@@ -1291,8 +1298,6 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient,
// DroppedFrameCounter. Currently true when first contentful paint is done.
bool is_measuring_smoothness_ = false;
- base::WritableSharedMemoryMapping ukm_smoothness_mapping_;
-
// Cache for the results of calls to gfx::ColorSpace::Contains() on sRGB. This
// computation is deterministic for a given color space, can be called
// multiple times per frame, and incurs a non-trivial cost.
@@ -1305,6 +1310,9 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient,
std::vector<uint32_t> finished_transition_request_sequence_ids_;
+ bool downsample_metrics_ = true;
+ base::MetricsSubSampler metrics_subsampler_;
+
// Must be the last member to ensure this is destroyed first in the
// destruction order and invalidates all weak pointers.
base::WeakPtrFactory<LayerTreeHostImpl> weak_factory_{this};
diff --git a/chromium/cc/trees/layer_tree_host_impl_unittest.cc b/chromium/cc/trees/layer_tree_host_impl_unittest.cc
index 3b1e8aa5ed6..213f1231961 100644
--- a/chromium/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/chromium/cc/trees/layer_tree_host_impl_unittest.cc
@@ -28,11 +28,11 @@
#include "cc/base/histograms.h"
#include "cc/document_transition/document_transition_request.h"
#include "cc/input/browser_controls_offset_manager.h"
+#include "cc/input/input_handler.h"
#include "cc/input/main_thread_scrolling_reason.h"
#include "cc/input/page_scale_animation.h"
#include "cc/input/scroll_utils.h"
#include "cc/input/scrollbar_controller.h"
-#include "cc/input/threaded_input_handler.h"
#include "cc/layers/append_quads_data.h"
#include "cc/layers/layer_impl.h"
#include "cc/layers/painted_overlay_scrollbar_layer_impl.h"
@@ -138,6 +138,11 @@ struct TestFrameData : public LayerTreeHostImpl::FrameData {
}
};
+void ClearMainThreadDeltasForTesting(LayerTreeHostImpl* host) {
+ host->active_tree()->ApplySentScrollAndScaleDeltasFromAbortedCommit(
+ /*main_frame_applied_deltas=*/false);
+}
+
} // namespace
class LayerTreeHostImplTest : public testing::Test,
@@ -360,6 +365,21 @@ class LayerTreeHostImplTest : public testing::Test,
size, host_impl_->active_tree()->device_scale_factor());
}
+ void PushScrollOffsetsToPendingTree(
+ const base::flat_map<ElementId, gfx::PointF>& offsets) {
+ PropertyTrees property_trees(*host_impl_);
+ for (auto& entry : offsets) {
+ property_trees.scroll_tree_mutable().SetBaseScrollOffset(entry.first,
+ entry.second);
+ }
+ host_impl_->sync_tree()
+ ->property_trees()
+ ->scroll_tree_mutable()
+ .PushScrollUpdatesFromMainThread(
+ property_trees, host_impl_->sync_tree(),
+ host_impl_->settings().commit_fractional_scroll_deltas);
+ }
+
static void ExpectClearedScrollDeltasRecursive(LayerImpl* root) {
for (auto* layer : *root->layer_tree_impl())
ASSERT_EQ(ScrollDelta(layer), gfx::Vector2d());
@@ -831,9 +851,7 @@ class LayerTreeHostImplTest : public testing::Test,
}
}
- ThreadedInputHandler& GetInputHandler() {
- return host_impl_->GetInputHandler();
- }
+ InputHandler& GetInputHandler() { return host_impl_->GetInputHandler(); }
FakeImplTaskRunnerProvider task_runner_provider_;
DebugScopedSetMainThreadBlocked always_main_thread_blocked_;
@@ -1097,8 +1115,6 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, ScrollDeltaTreeButNoChanges) {
TEST_P(ScrollUnifiedLayerTreeHostImplTest, ScrollDeltaRepeatedScrolls) {
gfx::PointF scroll_offset(20, 30);
- gfx::Vector2dF scroll_delta(11, -15);
-
auto* root = SetupDefaultRootLayer(gfx::Size(110, 110));
root->SetHitTestable(true);
CreateScrollNode(root, gfx::Size(10, 10));
@@ -1108,31 +1124,128 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, ScrollDeltaRepeatedScrolls) {
.UpdateScrollOffsetBaseForTesting(root->element_id(), scroll_offset);
UpdateDrawProperties(host_impl_->active_tree());
- std::unique_ptr<CompositorCommitData> commit_data;
-
+ gfx::Vector2dF scroll_delta(11, -15);
+ std::unique_ptr<CompositorCommitData> commit_data1;
root->ScrollBy(scroll_delta);
- commit_data = host_impl_->ProcessCompositorDeltas();
- ASSERT_EQ(commit_data->scrolls.size(), 1u);
+ commit_data1 = host_impl_->ProcessCompositorDeltas();
+ ASSERT_EQ(commit_data1->scrolls.size(), 1u);
EXPECT_TRUE(
- ScrollInfoContains(*commit_data, root->element_id(), scroll_delta));
+ ScrollInfoContains(*commit_data1, root->element_id(), scroll_delta));
+ std::unique_ptr<CompositorCommitData> commit_data2;
gfx::Vector2dF scroll_delta2(-5, 27);
root->ScrollBy(scroll_delta2);
- commit_data = host_impl_->ProcessCompositorDeltas();
- ASSERT_EQ(commit_data->scrolls.size(), 1u);
- EXPECT_TRUE(ScrollInfoContains(*commit_data, root->element_id(),
- scroll_delta + scroll_delta2));
+ commit_data2 = host_impl_->ProcessCompositorDeltas();
+ ASSERT_EQ(commit_data2->scrolls.size(), 1u);
+ EXPECT_TRUE(
+ ScrollInfoContains(*commit_data2, root->element_id(), scroll_delta2));
+
+ // Simulate first commit by pushing base scroll offsets to pending tree
+ PushScrollOffsetsToPendingTree(
+ {{root->element_id(), gfx::PointAtOffsetFromOrigin(scroll_delta)}});
+ EXPECT_EQ(host_impl_->sync_tree()
+ ->property_trees()
+ ->scroll_tree()
+ .GetScrollOffsetDeltaForTesting(root->element_id()),
+ scroll_delta2);
+
+ // Simulate second commit by pushing base scroll offsets to pending tree
+ PushScrollOffsetsToPendingTree(
+ {{root->element_id(), gfx::PointAtOffsetFromOrigin(scroll_delta2)}});
+ EXPECT_EQ(host_impl_->sync_tree()
+ ->property_trees()
+ ->scroll_tree()
+ .GetScrollOffsetDeltaForTesting(root->element_id()),
+ gfx::Vector2dF(0, 0));
+}
+
+TEST_P(ScrollUnifiedLayerTreeHostImplTest, SyncedScrollAbortedCommit) {
+ LayerTreeSettings settings = DefaultSettings();
+ settings.commit_to_active_tree = false;
+ CreateHostImpl(settings, CreateLayerTreeFrameSink());
+ CreatePendingTree();
+ gfx::PointF scroll_offset(20, 30);
+ auto* root = SetupDefaultRootLayer(gfx::Size(110, 110));
+ auto& scroll_tree =
+ root->layer_tree_impl()->property_trees()->scroll_tree_mutable();
+ root->SetHitTestable(true);
- root->ScrollBy(gfx::Vector2d());
- commit_data = host_impl_->ProcessCompositorDeltas();
- EXPECT_TRUE(ScrollInfoContains(*commit_data, root->element_id(),
- scroll_delta + scroll_delta2));
+ // SyncedProperty should be created on the pending tree and then pushed to the
+ // active tree, to avoid bifurcation. Simulate commit by pushing base scroll
+ // offsets to pending tree.
+ PushScrollOffsetsToPendingTree({{root->element_id(), gfx::PointF(0, 0)}});
+ host_impl_->active_tree()
+ ->property_trees()
+ ->scroll_tree_mutable()
+ .PushScrollUpdatesFromPendingTree(
+ host_impl_->pending_tree()->property_trees(),
+ host_impl_->active_tree());
+
+ CreateScrollNode(root, gfx::Size(10, 10));
+ auto* synced_scroll = scroll_tree.GetSyncedScrollOffset(root->element_id());
+ ASSERT_TRUE(synced_scroll);
+ scroll_tree.UpdateScrollOffsetBaseForTesting(root->element_id(),
+ scroll_offset);
+ UpdateDrawProperties(host_impl_->active_tree());
+
+ gfx::Vector2dF scroll_delta(11, -15);
+ root->ScrollBy(scroll_delta);
+ EXPECT_EQ(scroll_delta, synced_scroll->UnsentDelta());
+ host_impl_->ProcessCompositorDeltas();
+ EXPECT_TRUE(synced_scroll->reflected_delta_in_main_tree().has_value());
+ EXPECT_FALSE(synced_scroll->next_reflected_delta_in_main_tree().has_value());
+ EXPECT_EQ(scroll_delta,
+ synced_scroll->reflected_delta_in_main_tree().value());
+
+ gfx::Vector2dF scroll_delta2(-5, 27);
+ root->ScrollBy(scroll_delta2);
+ EXPECT_EQ(scroll_delta2, synced_scroll->UnsentDelta());
+ host_impl_->ProcessCompositorDeltas();
+ EXPECT_TRUE(synced_scroll->reflected_delta_in_main_tree().has_value());
+ EXPECT_TRUE(synced_scroll->next_reflected_delta_in_main_tree().has_value());
+ EXPECT_EQ(scroll_delta,
+ synced_scroll->reflected_delta_in_main_tree().value());
+ EXPECT_EQ(scroll_delta2,
+ synced_scroll->next_reflected_delta_in_main_tree().value());
+
+ // Simulate aborting the second main frame. Scroll deltas applied by the
+ // second frame should be combined with delta from first frame.
+ root->layer_tree_impl()->ApplySentScrollAndScaleDeltasFromAbortedCommit(
+ /*main_frame_applied_deltas=*/true);
+ EXPECT_TRUE(synced_scroll->reflected_delta_in_main_tree().has_value());
+ EXPECT_FALSE(synced_scroll->next_reflected_delta_in_main_tree().has_value());
+ EXPECT_EQ(scroll_delta + scroll_delta2,
+ synced_scroll->reflected_delta_in_main_tree().value());
+
+ // Send a third main frame, pipelined behind the first.
+ gfx::Vector2dF scroll_delta3(-2, -13);
+ root->ScrollBy(scroll_delta3);
+ EXPECT_EQ(scroll_delta3, synced_scroll->UnsentDelta());
+ host_impl_->ProcessCompositorDeltas();
+ EXPECT_TRUE(synced_scroll->reflected_delta_in_main_tree().has_value());
+ EXPECT_TRUE(synced_scroll->next_reflected_delta_in_main_tree().has_value());
+ EXPECT_EQ(scroll_delta + scroll_delta2,
+ synced_scroll->reflected_delta_in_main_tree().value());
+ EXPECT_EQ(scroll_delta3,
+ synced_scroll->next_reflected_delta_in_main_tree().value());
+
+ // Simulate commit of the first frame
+ PushScrollOffsetsToPendingTree(
+ {{root->element_id(), scroll_offset + scroll_delta + scroll_delta2}});
+ EXPECT_EQ(scroll_offset + scroll_delta + scroll_delta2,
+ synced_scroll->PendingBase());
+ EXPECT_EQ(scroll_delta3, synced_scroll->PendingDelta());
+ EXPECT_TRUE(synced_scroll->reflected_delta_in_main_tree().has_value());
+ EXPECT_FALSE(synced_scroll->next_reflected_delta_in_main_tree().has_value());
+ EXPECT_EQ(scroll_delta3,
+ synced_scroll->reflected_delta_in_main_tree().value());
}
TEST_F(CommitToPendingTreeLayerTreeHostImplTest,
GPUMemoryForSmallLayerHistogramTest) {
base::HistogramTester histogram_tester;
SetClientNameForMetrics("Renderer");
+ host_impl_->SetDownsampleMetricsForTesting(false);
// With default tile size being set to 256 * 256, the following layer needs
// one tile only which costs 256 * 256 * 4 / 1024 = 256KB memory.
TestGPUMemoryForTilings(gfx::Size(200, 200));
@@ -1146,6 +1259,7 @@ TEST_F(CommitToPendingTreeLayerTreeHostImplTest,
GPUMemoryForLargeLayerHistogramTest) {
base::HistogramTester histogram_tester;
SetClientNameForMetrics("Renderer");
+ host_impl_->SetDownsampleMetricsForTesting(false);
// With default tile size being set to 256 * 256, the following layer needs
// 4 tiles which cost 256 * 256 * 4 * 4 / 1024 = 1024KB memory.
TestGPUMemoryForTilings(gfx::Size(500, 500));
@@ -3602,6 +3716,7 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, ImplPinchZoom) {
EXPECT_EQ(commit_data->page_scale_delta, page_scale_delta);
EXPECT_EQ(gfx::PointF(75.0, 75.0), MaxScrollOffset(scroll_layer));
+ ClearMainThreadDeltasForTesting(host_impl_.get());
}
// Scrolling after a pinch gesture should always be in local space. The
@@ -4193,6 +4308,7 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, PinchGesture) {
std::unique_ptr<CompositorCommitData> commit_data =
host_impl_->ProcessCompositorDeltas();
EXPECT_EQ(commit_data->page_scale_delta, page_scale_delta);
+ ClearMainThreadDeltasForTesting(host_impl_.get());
}
// Zoom-in clamping
@@ -4216,6 +4332,7 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, PinchGesture) {
std::unique_ptr<CompositorCommitData> commit_data =
host_impl_->ProcessCompositorDeltas();
EXPECT_EQ(commit_data->page_scale_delta, max_page_scale);
+ ClearMainThreadDeltasForTesting(host_impl_.get());
}
// Zoom-out clamping
@@ -4227,6 +4344,7 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, PinchGesture) {
->property_trees()
->scroll_tree_mutable()
.CollectScrollDeltasForTesting();
+ ClearMainThreadDeltasForTesting(host_impl_.get());
scroll_layer->layer_tree_impl()
->property_trees()
->scroll_tree_mutable()
@@ -4249,6 +4367,7 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, PinchGesture) {
EXPECT_EQ(commit_data->page_scale_delta, min_page_scale);
EXPECT_TRUE(commit_data->scrolls.empty());
+ ClearMainThreadDeltasForTesting(host_impl_.get());
}
// Two-finger panning should not happen based on pinch events only
@@ -4260,6 +4379,7 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, PinchGesture) {
->property_trees()
->scroll_tree_mutable()
.CollectScrollDeltasForTesting();
+ ClearMainThreadDeltasForTesting(host_impl_.get());
scroll_layer->layer_tree_impl()
->property_trees()
->scroll_tree_mutable()
@@ -4283,6 +4403,7 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, PinchGesture) {
host_impl_->ProcessCompositorDeltas();
EXPECT_EQ(commit_data->page_scale_delta, page_scale_delta);
EXPECT_TRUE(commit_data->scrolls.empty());
+ ClearMainThreadDeltasForTesting(host_impl_.get());
}
// Two-finger panning should work with interleaved scroll events
@@ -4294,6 +4415,7 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, PinchGesture) {
->property_trees()
->scroll_tree_mutable()
.CollectScrollDeltasForTesting();
+ ClearMainThreadDeltasForTesting(host_impl_.get());
scroll_layer->layer_tree_impl()
->property_trees()
->scroll_tree_mutable()
@@ -4322,6 +4444,7 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, PinchGesture) {
EXPECT_EQ(commit_data->page_scale_delta, page_scale_delta);
EXPECT_TRUE(ScrollInfoContains(*commit_data, scroll_layer->element_id(),
gfx::Vector2dF(-10, -10)));
+ ClearMainThreadDeltasForTesting(host_impl_.get());
}
// Two-finger panning should work when starting fully zoomed out.
@@ -4332,6 +4455,7 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, PinchGesture) {
->property_trees()
->scroll_tree_mutable()
.CollectScrollDeltasForTesting();
+ ClearMainThreadDeltasForTesting(host_impl_.get());
scroll_layer->layer_tree_impl()
->property_trees()
->scroll_tree_mutable()
@@ -4383,6 +4507,7 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, SyncSubpixelScrollDelta) {
->property_trees()
->scroll_tree_mutable()
.CollectScrollDeltasForTesting();
+ ClearMainThreadDeltasForTesting(host_impl_.get());
scroll_layer->layer_tree_impl()
->property_trees()
->scroll_tree_mutable()
@@ -4435,6 +4560,7 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest,
->property_trees()
->scroll_tree_mutable()
.CollectScrollDeltasForTesting();
+ ClearMainThreadDeltasForTesting(host_impl_.get());
scroll_layer->layer_tree_impl()
->property_trees()
->scroll_tree_mutable()
@@ -4530,6 +4656,7 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest,
std::unique_ptr<CompositorCommitData> commit_data =
host_impl_->ProcessCompositorDeltas();
EXPECT_EQ(commit_data->page_scale_delta, 1);
+ ClearMainThreadDeltasForTesting(host_impl_.get());
}
start_time += base::Seconds(10);
@@ -4661,6 +4788,7 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, PageScaleAnimation) {
EXPECT_EQ(commit_data->page_scale_delta, 2);
EXPECT_TRUE(ScrollInfoContains(*commit_data, scroll_layer->element_id(),
gfx::Vector2dF(-50, -50)));
+ ClearMainThreadDeltasForTesting(host_impl_.get());
}
start_time += base::Seconds(10);
@@ -5657,6 +5785,7 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest,
settings.scrollbar_animator = LayerTreeSettings::AURA_OVERLAY;
settings.scrollbar_fade_delay = base::Milliseconds(20);
settings.scrollbar_fade_duration = base::Milliseconds(20);
+ settings.enable_scroll_update_optimizations = true;
gfx::Size viewport_size(50, 50);
gfx::Size content_size(100, 100);
@@ -5680,6 +5809,14 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest,
// Scrollbars will flash shown but we should have a fade out animation
// queued. Run it and fade out the scrollbars.
+ ASSERT_FALSE(scrollbar_controller->ScrollbarsHidden());
+ EXPECT_TRUE(scrollbar_controller->visibility_changed());
+ ClearMainThreadDeltasForTesting(host_impl_.get());
+ auto commit_data = host_impl_->ProcessCompositorDeltas();
+ using ScrollbarsInfo = CompositorCommitData::ScrollbarsUpdateInfo;
+ EXPECT_THAT(commit_data->scrollbars, testing::ElementsAre(ScrollbarsInfo{
+ scroll->element_id(), false}));
+ EXPECT_FALSE(scrollbar_controller->visibility_changed());
{
ASSERT_FALSE(animation_task_.is_null());
ASSERT_FALSE(animation_task_.IsCancelled());
@@ -5691,6 +5828,11 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest,
scrollbar_controller->Animate(fake_now);
ASSERT_TRUE(scrollbar_controller->ScrollbarsHidden());
+ ClearMainThreadDeltasForTesting(host_impl_.get());
+ commit_data = host_impl_->ProcessCompositorDeltas();
+ EXPECT_THAT(commit_data->scrollbars, testing::ElementsAre(ScrollbarsInfo{
+ scroll->element_id(), true}));
+ EXPECT_FALSE(scrollbar_controller->visibility_changed());
}
// Move the mouse over the scrollbar region. This should post a delayed fade
@@ -5708,6 +5850,10 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest,
did_request_redraw_ = false;
did_request_commit_ = false;
ASSERT_TRUE(scrollbar_controller->ScrollbarsHidden());
+ EXPECT_FALSE(scrollbar_controller->visibility_changed());
+ ClearMainThreadDeltasForTesting(host_impl_.get());
+ commit_data = host_impl_->ProcessCompositorDeltas();
+ EXPECT_TRUE(commit_data->scrollbars.empty());
std::move(animation_task_).Run();
base::TimeTicks fake_now = base::TimeTicks::Now();
@@ -5716,6 +5862,12 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest,
scrollbar_controller->Animate(fake_now);
ASSERT_FALSE(scrollbar_controller->ScrollbarsHidden());
+ EXPECT_TRUE(scrollbar_controller->visibility_changed());
+ ClearMainThreadDeltasForTesting(host_impl_.get());
+ commit_data = host_impl_->ProcessCompositorDeltas();
+ EXPECT_THAT(commit_data->scrollbars, testing::ElementsAre(ScrollbarsInfo{
+ scroll->element_id(), false}));
+ EXPECT_FALSE(scrollbar_controller->visibility_changed());
EXPECT_TRUE(did_request_redraw_);
EXPECT_TRUE(did_request_commit_);
}
@@ -5869,8 +6021,9 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, ScrollBeforeMouseMove) {
const float kDistanceToTriggerThumb =
vert_scrollbar->ComputeThumbQuadRect().height() +
- SingleScrollbarAnimationControllerThinning::
- kMouseMoveDistanceToTriggerExpand;
+ scrollbar_controller
+ ->GetScrollbarAnimationController(ScrollbarOrientation::VERTICAL)
+ .MouseMoveDistanceToTriggerExpand();
// Move the mouse near the thumb while its at the viewport top.
auto near_thumb_at_top = gfx::Point(295, kDistanceToTriggerThumb - 1);
@@ -5924,9 +6077,10 @@ void LayerTreeHostImplTest::SetupMouseMoveAtWithDeviceScale(
settings.scrollbar_fade_duration = base::Milliseconds(300);
settings.scrollbar_animator = LayerTreeSettings::AURA_OVERLAY;
+ const int thumb_thickness = 15;
gfx::Size viewport_size(300, 200);
gfx::Size content_size(1000, 1000);
- gfx::Size scrollbar_size(gfx::Size(15, viewport_size.height()));
+ gfx::Size scrollbar_size(gfx::Size(thumb_thickness, viewport_size.height()));
CreateHostImpl(settings, CreateLayerTreeFrameSink());
host_impl_->active_tree()->SetDeviceScaleFactor(device_scale_factor);
@@ -5934,7 +6088,8 @@ void LayerTreeHostImplTest::SetupMouseMoveAtWithDeviceScale(
LayerImpl* root_scroll = OuterViewportScrollLayer();
// The scrollbar is on the left side.
auto* scrollbar = AddLayer<SolidColorScrollbarLayerImpl>(
- host_impl_->active_tree(), ScrollbarOrientation::VERTICAL, 15, 0, true);
+ host_impl_->active_tree(), ScrollbarOrientation::VERTICAL,
+ thumb_thickness, 0, true);
SetupScrollbarLayer(root_scroll, scrollbar);
scrollbar->SetBounds(scrollbar_size);
TouchActionRegion touch_action_region;
@@ -5949,28 +6104,31 @@ void LayerTreeHostImplTest::SetupMouseMoveAtWithDeviceScale(
root_scroll->element_id());
const float kMouseMoveDistanceToTriggerFadeIn =
- ScrollbarAnimationController::kMouseMoveDistanceToTriggerFadeIn;
+ scrollbar_animation_controller
+ ->GetScrollbarAnimationController(ScrollbarOrientation::VERTICAL)
+ .MouseMoveDistanceToTriggerFadeIn();
const float kMouseMoveDistanceToTriggerExpand =
- SingleScrollbarAnimationControllerThinning::
- kMouseMoveDistanceToTriggerExpand;
+ scrollbar_animation_controller
+ ->GetScrollbarAnimationController(ScrollbarOrientation::VERTICAL)
+ .MouseMoveDistanceToTriggerExpand();
GetInputHandler().MouseMoveAt(
- gfx::Point(15 + kMouseMoveDistanceToTriggerFadeIn, 1));
+ gfx::Point(thumb_thickness + kMouseMoveDistanceToTriggerFadeIn + 1, 1));
EXPECT_FALSE(scrollbar_animation_controller->MouseIsNearScrollbar(
ScrollbarOrientation::VERTICAL));
EXPECT_FALSE(scrollbar_animation_controller->MouseIsNearScrollbarThumb(
ScrollbarOrientation::VERTICAL));
GetInputHandler().MouseMoveAt(
- gfx::Point(15 + kMouseMoveDistanceToTriggerExpand - 1, 10));
+ gfx::Point(thumb_thickness + kMouseMoveDistanceToTriggerExpand, 10));
EXPECT_TRUE(scrollbar_animation_controller->MouseIsNearScrollbar(
ScrollbarOrientation::VERTICAL));
EXPECT_TRUE(scrollbar_animation_controller->MouseIsNearScrollbarThumb(
ScrollbarOrientation::VERTICAL));
GetInputHandler().MouseMoveAt(
- gfx::Point(15 + kMouseMoveDistanceToTriggerFadeIn, 100));
+ gfx::Point(thumb_thickness + kMouseMoveDistanceToTriggerFadeIn + 1, 100));
EXPECT_FALSE(scrollbar_animation_controller->MouseIsNearScrollbar(
ScrollbarOrientation::VERTICAL));
EXPECT_FALSE(scrollbar_animation_controller->MouseIsNearScrollbarThumb(
@@ -6283,7 +6441,8 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest,
// The background is default to transparent. If the background is opaque, we
// would fill the frame with background colour when no layers are contributing
// quads. This means we would end up with 0 quad.
- EXPECT_EQ(host_impl_->active_tree()->background_color(), SK_ColorTRANSPARENT);
+ EXPECT_EQ(host_impl_->active_tree()->background_color(),
+ SkColors::kTransparent);
{
TestFrameData frame;
@@ -8417,16 +8576,19 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, ScrollWithoutBubbling) {
UpdateDrawProperties(host_impl_->active_tree());
host_impl_->active_tree()->DidBecomeActive();
+ gfx::PointF grand_child_base(0, 2);
+ gfx::Vector2dF grand_child_delta;
grand_child_layer->layer_tree_impl()
->property_trees()
->scroll_tree_mutable()
.UpdateScrollOffsetBaseForTesting(grand_child_layer->element_id(),
- gfx::PointF(0, 2));
+ grand_child_base);
+ gfx::PointF child_base(0, 3);
+ gfx::Vector2dF child_delta;
child_layer->layer_tree_impl()
->property_trees()
->scroll_tree_mutable()
- .UpdateScrollOffsetBaseForTesting(child_layer->element_id(),
- gfx::PointF(0, 3));
+ .UpdateScrollOffsetBaseForTesting(child_layer->element_id(), child_base);
DrawFrame();
{
@@ -8448,13 +8610,20 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, ScrollWithoutBubbling) {
host_impl_->ProcessCompositorDeltas();
// The grand child should have scrolled up to its limit.
+ grand_child_delta = gfx::Vector2dF(0, -2);
EXPECT_TRUE(ScrollInfoContains(*commit_data.get(),
grand_child_layer->element_id(),
- gfx::Vector2dF(0, -2)));
+ grand_child_delta));
// The child should not have scrolled.
ExpectNone(*commit_data.get(), child_layer->element_id());
+ grand_child_base += grand_child_delta;
+ child_base += child_delta;
+ PushScrollOffsetsToPendingTree(
+ {{child_layer->element_id(), child_base},
+ {grand_child_layer->element_id(), grand_child_base}});
+
// The next time we scroll we should only scroll the parent.
scroll_delta = gfx::Vector2d(0, -3);
EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD,
@@ -8474,16 +8643,23 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, ScrollWithoutBubbling) {
child_layer->scroll_tree_index());
GetInputHandler().ScrollEnd();
+ ClearMainThreadDeltasForTesting(host_impl_.get());
commit_data = host_impl_->ProcessCompositorDeltas();
// The child should have scrolled up to its limit.
- EXPECT_TRUE(ScrollInfoContains(
- *commit_data.get(), child_layer->element_id(), gfx::Vector2dF(0, -3)));
+ child_delta = gfx::Vector2dF(0, -3);
+ EXPECT_TRUE(ScrollInfoContains(*commit_data.get(),
+ child_layer->element_id(), child_delta));
// The grand child should not have scrolled.
- EXPECT_TRUE(ScrollInfoContains(*commit_data.get(),
- grand_child_layer->element_id(),
- gfx::Vector2dF(0, -2)));
+ grand_child_delta = gfx::Vector2dF();
+ ExpectNone(*commit_data.get(), grand_child_layer->element_id());
+
+ child_base += child_delta;
+ grand_child_base += grand_child_delta;
+ PushScrollOffsetsToPendingTree(
+ {{grand_child_layer->element_id(), grand_child_base},
+ {child_layer->element_id(), child_base}});
// After scrolling the parent, another scroll on the opposite direction
// should still scroll the child.
@@ -8505,16 +8681,24 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, ScrollWithoutBubbling) {
grand_child_layer->scroll_tree_index());
GetInputHandler().ScrollEnd();
+ ClearMainThreadDeltasForTesting(host_impl_.get());
commit_data = host_impl_->ProcessCompositorDeltas();
// The grand child should have scrolled.
+ grand_child_delta = gfx::Vector2dF(0, 7);
EXPECT_TRUE(ScrollInfoContains(*commit_data.get(),
grand_child_layer->element_id(),
- gfx::Vector2dF(0, 5)));
+ grand_child_delta));
// The child should not have scrolled.
- EXPECT_TRUE(ScrollInfoContains(
- *commit_data.get(), child_layer->element_id(), gfx::Vector2dF(0, -3)));
+ child_delta = gfx::Vector2dF();
+ ExpectNone(*commit_data.get(), child_layer->element_id());
+
+ grand_child_base += grand_child_delta;
+ child_base += child_delta;
+ PushScrollOffsetsToPendingTree(
+ {{grand_child_layer->element_id(), grand_child_base},
+ {child_layer->element_id(), child_base}});
// Scrolling should be adjusted from viewport space.
host_impl_->active_tree()->PushPageScaleFromMainThread(2, 2, 2);
@@ -8536,12 +8720,13 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, ScrollWithoutBubbling) {
.get());
GetInputHandler().ScrollEnd();
+ ClearMainThreadDeltasForTesting(host_impl_.get());
commit_data = host_impl_->ProcessCompositorDeltas();
- // Should have scrolled by half the amount in layer space (5 - 2/2)
+ // Should have scrolled by half the amount in layer space (-2/2)
EXPECT_TRUE(ScrollInfoContains(*commit_data.get(),
grand_child_layer->element_id(),
- gfx::Vector2dF(0, 4)));
+ gfx::Vector2dF(0, -1)));
}
}
@@ -8684,6 +8869,10 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, ScrollAxisAlignedRotatedLayer) {
EXPECT_TRUE(ScrollInfoContains(*commit_data.get(), scroll_layer->element_id(),
gfx::Vector2dF(0, gesture_scroll_delta.x())));
+ // Push scrolls to pending tree
+ PushScrollOffsetsToPendingTree(
+ {{scroll_layer->element_id(), gfx::PointF(10, 0)}});
+
// Reset and scroll down with the wheel.
SetScrollOffsetDelta(scroll_layer, gfx::Vector2dF());
gfx::Vector2dF wheel_scroll_delta(0, 10);
@@ -8766,6 +8955,10 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, ScrollNonAxisAlignedRotatedLayer) {
// The root scroll layer should not have scrolled, because the input delta
// was close to the layer's axis of movement.
EXPECT_EQ(commit_data->scrolls.size(), 1u);
+
+ PushScrollOffsetsToPendingTree(
+ {{child_scroll_id,
+ gfx::PointAtOffsetFromOrigin(expected_scroll_delta)}});
}
{
// Now reset and scroll the same amount horizontally.
@@ -8797,6 +8990,10 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, ScrollNonAxisAlignedRotatedLayer) {
// The root scroll layer shouldn't have scrolled.
ExpectNone(*commit_data.get(), scroll_layer->element_id());
+
+ PushScrollOffsetsToPendingTree(
+ {{child_scroll_id,
+ gfx::PointAtOffsetFromOrigin(expected_scroll_delta)}});
}
}
@@ -8876,6 +9073,11 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, ScrollPerspectiveTransformedLayer) {
// The root scroll layer should not have scrolled, because the input delta
// was close to the layer's axis of movement.
EXPECT_EQ(commit_data->scrolls.size(), 1u);
+
+ PushScrollOffsetsToPendingTree(
+ {{child->element_id(),
+ gfx::PointAtOffsetFromOrigin(expected_scroll_deltas[i])}});
+ ClearMainThreadDeltasForTesting(host_impl_.get());
}
}
@@ -8911,6 +9113,9 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, ScrollScaledLayer) {
host_impl_->ProcessCompositorDeltas();
EXPECT_TRUE(ScrollInfoContains(*commit_data.get(), scroll_layer->element_id(),
gfx::Vector2dF(0, scroll_delta.y() / scale)));
+ PushScrollOffsetsToPendingTree(
+ {{scroll_layer->element_id(), gfx::PointAtOffsetFromOrigin(gfx::Vector2dF(
+ 0, scroll_delta.y() / scale))}});
// Reset and scroll down with the wheel.
SetScrollOffsetDelta(scroll_layer, gfx::Vector2dF());
@@ -10726,7 +10931,7 @@ class LayerTreeHostImplViewportCoveredTest : public LayerTreeHostImplTest {
}
void SetupActiveTreeLayers() {
- host_impl_->active_tree()->set_background_color(SK_ColorGRAY);
+ host_impl_->active_tree()->set_background_color(SkColors::kGray);
LayerImpl* root = SetupDefaultRootLayer(viewport_size_);
child_ = AddLayer<BlendStateCheckLayer>(host_impl_->active_tree(),
host_impl_->resource_provider());
@@ -11098,7 +11303,7 @@ class FakeLayerWithQuads : public LayerImpl {
render_pass->CreateAndAppendSharedQuadState();
PopulateSharedQuadState(shared_quad_state, contents_opaque());
- SkColor gray = SkColorSetRGB(100, 100, 100);
+ SkColor4f gray = SkColors::kGray;
gfx::Rect quad_rect(bounds());
gfx::Rect visible_quad_rect(quad_rect);
auto* my_quad =
@@ -11148,7 +11353,7 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, LayersFreeTextures) {
TEST_P(ScrollUnifiedLayerTreeHostImplTest, HasTransparentBackground) {
SetupDefaultRootLayer(gfx::Size(10, 10));
- host_impl_->active_tree()->set_background_color(SK_ColorWHITE);
+ host_impl_->active_tree()->set_background_color(SkColors::kWhite);
UpdateDrawProperties(host_impl_->active_tree());
// Verify one quad is drawn when transparent background set is not set.
@@ -11172,7 +11377,7 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, HasTransparentBackground) {
host_impl_->SetFullViewportDamage();
// Verify no quads are drawn when transparent background is set.
- host_impl_->active_tree()->set_background_color(SK_ColorTRANSPARENT);
+ host_impl_->active_tree()->set_background_color(SkColors::kTransparent);
host_impl_->SetFullViewportDamage();
args = viz::CreateBeginFrameArgsForTesting(
BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1,
@@ -11191,7 +11396,7 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, HasTransparentBackground) {
host_impl_->SetFullViewportDamage();
// Verify no quads are drawn when semi-transparent background is set.
- host_impl_->active_tree()->set_background_color(SkColorSetARGB(5, 255, 0, 0));
+ host_impl_->active_tree()->set_background_color({1.0f, 0.0f, 0.0f, 0.1f});
host_impl_->SetFullViewportDamage();
host_impl_->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting(
BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1,
@@ -14812,7 +15017,13 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest,
// Verify no jump.
float y = CurrentScrollOffset(scrolling_layer).y();
- EXPECT_TRUE(y > 1 && y < 49);
+ if (features::IsImpulseScrollAnimationEnabled()) {
+ // Impulse scroll animation is faster than non-impulse, which results in a
+ // traveled distance larger than the original 50px.
+ EXPECT_TRUE(y > 50 && y < 100);
+ } else {
+ EXPECT_TRUE(y > 1 && y < 49);
+ }
}
TEST_P(ScrollUnifiedLayerTreeHostImplTest, ScrollAnimatedWithDelay) {
@@ -15914,11 +16125,14 @@ void LayerTreeHostImplTest::SetupMouseMoveAtTestScrollbarStates(
settings.scrollbar_fade_duration = base::Milliseconds(300);
settings.scrollbar_animator = LayerTreeSettings::AURA_OVERLAY;
+ const int thumb_thickness = 15;
gfx::Size viewport_size(300, 200);
gfx::Size content_size(1000, 1000);
gfx::Size child_layer_size(250, 150);
- gfx::Size scrollbar_size_1(gfx::Size(15, viewport_size.height()));
- gfx::Size scrollbar_size_2(gfx::Size(15, child_layer_size.height()));
+ gfx::Size scrollbar_size_1(
+ gfx::Size(thumb_thickness, viewport_size.height()));
+ gfx::Size scrollbar_size_2(
+ gfx::Size(thumb_thickness, child_layer_size.height()));
CreateHostImpl(settings, CreateLayerTreeFrameSink());
host_impl_->active_tree()->SetDeviceScaleFactor(1);
@@ -15932,7 +16146,8 @@ void LayerTreeHostImplTest::SetupMouseMoveAtTestScrollbarStates(
// scrollbar_1 on root scroll.
auto* scrollbar_1 = AddLayer<SolidColorScrollbarLayerImpl>(
- host_impl_->active_tree(), ScrollbarOrientation::VERTICAL, 15, 0, true);
+ host_impl_->active_tree(), ScrollbarOrientation::VERTICAL,
+ thumb_thickness, 0, true);
SetupScrollbarLayer(root_scroll, scrollbar_1);
scrollbar_1->SetBounds(scrollbar_size_1);
TouchActionRegion touch_action_region;
@@ -15950,16 +16165,19 @@ void LayerTreeHostImplTest::SetupMouseMoveAtTestScrollbarStates(
EXPECT_TRUE(scrollbar_1_animation_controller);
const float kMouseMoveDistanceToTriggerFadeIn =
- ScrollbarAnimationController::kMouseMoveDistanceToTriggerFadeIn;
+ scrollbar_1_animation_controller
+ ->GetScrollbarAnimationController(ScrollbarOrientation::VERTICAL)
+ .MouseMoveDistanceToTriggerFadeIn();
const float kMouseMoveDistanceToTriggerExpand =
- SingleScrollbarAnimationControllerThinning::
- kMouseMoveDistanceToTriggerExpand;
+ scrollbar_1_animation_controller
+ ->GetScrollbarAnimationController(ScrollbarOrientation::VERTICAL)
+ .MouseMoveDistanceToTriggerExpand();
// Mouse moves close to the scrollbar, goes over the scrollbar, and
// moves back to where it was.
GetInputHandler().MouseMoveAt(
- gfx::Point(15 + kMouseMoveDistanceToTriggerFadeIn, 0));
+ gfx::Point(thumb_thickness + kMouseMoveDistanceToTriggerFadeIn + 1, 0));
EXPECT_FALSE(scrollbar_1_animation_controller->MouseIsNearScrollbar(
ScrollbarOrientation::VERTICAL));
EXPECT_FALSE(scrollbar_1_animation_controller->MouseIsNearScrollbarThumb(
@@ -15968,7 +16186,7 @@ void LayerTreeHostImplTest::SetupMouseMoveAtTestScrollbarStates(
ScrollbarOrientation::VERTICAL));
GetInputHandler().MouseMoveAt(
- gfx::Point(15 + kMouseMoveDistanceToTriggerExpand, 0));
+ gfx::Point(thumb_thickness + kMouseMoveDistanceToTriggerExpand + 1, 0));
EXPECT_TRUE(scrollbar_1_animation_controller->MouseIsNearScrollbar(
ScrollbarOrientation::VERTICAL));
EXPECT_FALSE(scrollbar_1_animation_controller->MouseIsNearScrollbarThumb(
@@ -15977,7 +16195,7 @@ void LayerTreeHostImplTest::SetupMouseMoveAtTestScrollbarStates(
ScrollbarOrientation::VERTICAL));
GetInputHandler().MouseMoveAt(
- gfx::Point(14 + kMouseMoveDistanceToTriggerExpand, 0));
+ gfx::Point(thumb_thickness + kMouseMoveDistanceToTriggerExpand, 0));
EXPECT_TRUE(scrollbar_1_animation_controller->MouseIsNearScrollbar(
ScrollbarOrientation::VERTICAL));
EXPECT_TRUE(scrollbar_1_animation_controller->MouseIsNearScrollbarThumb(
@@ -15994,7 +16212,7 @@ void LayerTreeHostImplTest::SetupMouseMoveAtTestScrollbarStates(
ScrollbarOrientation::VERTICAL));
GetInputHandler().MouseMoveAt(
- gfx::Point(14 + kMouseMoveDistanceToTriggerExpand, 0));
+ gfx::Point(thumb_thickness + kMouseMoveDistanceToTriggerExpand, 0));
EXPECT_TRUE(scrollbar_1_animation_controller->MouseIsNearScrollbar(
ScrollbarOrientation::VERTICAL));
EXPECT_TRUE(scrollbar_1_animation_controller->MouseIsNearScrollbarThumb(
@@ -16003,7 +16221,7 @@ void LayerTreeHostImplTest::SetupMouseMoveAtTestScrollbarStates(
ScrollbarOrientation::VERTICAL));
GetInputHandler().MouseMoveAt(
- gfx::Point(15 + kMouseMoveDistanceToTriggerExpand, 0));
+ gfx::Point(thumb_thickness + kMouseMoveDistanceToTriggerExpand + 1, 0));
EXPECT_TRUE(scrollbar_1_animation_controller->MouseIsNearScrollbar(
ScrollbarOrientation::VERTICAL));
EXPECT_FALSE(scrollbar_1_animation_controller->MouseIsNearScrollbarThumb(
@@ -16012,7 +16230,7 @@ void LayerTreeHostImplTest::SetupMouseMoveAtTestScrollbarStates(
ScrollbarOrientation::VERTICAL));
GetInputHandler().MouseMoveAt(
- gfx::Point(15 + kMouseMoveDistanceToTriggerFadeIn, 0));
+ gfx::Point(thumb_thickness + kMouseMoveDistanceToTriggerFadeIn + 1, 0));
EXPECT_FALSE(scrollbar_1_animation_controller->MouseIsNearScrollbar(
ScrollbarOrientation::VERTICAL));
EXPECT_FALSE(scrollbar_1_animation_controller->MouseIsNearScrollbarThumb(
@@ -16022,7 +16240,8 @@ void LayerTreeHostImplTest::SetupMouseMoveAtTestScrollbarStates(
// scrollbar_2 on child.
auto* scrollbar_2 = AddLayer<SolidColorScrollbarLayerImpl>(
- host_impl_->active_tree(), ScrollbarOrientation::VERTICAL, 15, 0, true);
+ host_impl_->active_tree(), ScrollbarOrientation::VERTICAL,
+ thumb_thickness, 0, true);
LayerImpl* child =
AddScrollableLayer(root_scroll, gfx::Size(100, 100), child_layer_size);
child->SetOffsetToTransformParent(gfx::Vector2dF(50, 50));
@@ -16060,7 +16279,7 @@ void LayerTreeHostImplTest::SetupMouseMoveAtTestScrollbarStates(
ScrollbarOrientation::VERTICAL));
GetInputHandler().MouseMoveAt(
- gfx::Point(64 + kMouseMoveDistanceToTriggerExpand, 50));
+ gfx::Point(50 + thumb_thickness + kMouseMoveDistanceToTriggerExpand, 50));
EXPECT_FALSE(scrollbar_1_animation_controller->MouseIsNearScrollbar(
ScrollbarOrientation::VERTICAL));
EXPECT_FALSE(scrollbar_1_animation_controller->MouseIsNearScrollbarThumb(
@@ -16074,7 +16293,7 @@ void LayerTreeHostImplTest::SetupMouseMoveAtTestScrollbarStates(
EXPECT_FALSE(scrollbar_2_animation_controller->MouseIsOverScrollbarThumb(
ScrollbarOrientation::VERTICAL));
GetInputHandler().MouseMoveAt(
- gfx::Point(14 + kMouseMoveDistanceToTriggerExpand, 0));
+ gfx::Point(thumb_thickness + kMouseMoveDistanceToTriggerExpand, 0));
EXPECT_TRUE(scrollbar_1_animation_controller->MouseIsNearScrollbar(
ScrollbarOrientation::VERTICAL));
EXPECT_TRUE(scrollbar_1_animation_controller->MouseIsNearScrollbarThumb(
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc b/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc
index e4b55f0fee0..4bd1a342b88 100644
--- a/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc
@@ -898,7 +898,7 @@ TEST_P(LayerTreeHostFiltersPixelTest, RotatedDropShadowFilter) {
child->SetTransform(transform);
FilterOperations filters;
filters.Append(FilterOperation::CreateDropShadowFilter(
- gfx::Point(10.0f, 10.0f), 0.0f, SK_ColorBLACK));
+ gfx::Point(10.0f, 10.0f), 0.0f, SkColors::kBlack));
child->SetFilters(filters);
background->AddChild(child);
diff --git a/chromium/cc/trees/layer_tree_host_unittest.cc b/chromium/cc/trees/layer_tree_host_unittest.cc
index c66f51e04c6..fca6e54e486 100644
--- a/chromium/cc/trees/layer_tree_host_unittest.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest.cc
@@ -389,7 +389,7 @@ class LayerTreeHostTestReadyToActivateEmpty : public LayerTreeHostTest {
size_t required_for_activation_count_;
};
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestReadyToActivateEmpty);
+MULTI_THREAD_TEST_F(LayerTreeHostTestReadyToActivateEmpty);
// Test if the LTHI receives ReadyToActivate notifications from the TileManager
// when some raster tasks flagged as REQUIRED_FOR_ACTIVATION got scheduled.
@@ -461,7 +461,7 @@ class LayerTreeHostTestReadyToDrawEmpty : public LayerTreeHostTest {
size_t required_for_draw_count_;
};
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestReadyToDrawEmpty);
+SINGLE_THREAD_TEST_F(LayerTreeHostTestReadyToDrawEmpty);
// Test if the LTHI receives ReadyToDraw notifications from the TileManager when
// some raster tasks flagged as REQUIRED_FOR_DRAW got scheduled.
@@ -544,14 +544,28 @@ class LayerTreeHostTestReadyToDrawVisibility : public LayerTreeHostTest {
void DidFinishImplFrameOnThread(LayerTreeHostImpl* host_impl) override {
if (!host_impl->visible()) {
- {
- DebugScopedSetMainThread main(task_runner_provider());
- layer_tree_host()->SetVisible(true);
- }
- EXPECT_TRUE(host_impl->visible());
+ // DidFinishImplFrameOnThread is called from Scheduler::FinishImplFrame()
+ // with inside_scheduled_action_ being true, so if SetVisible is called
+ // directly here without PostTask, ProcessScheduledActions() triggered by
+ // SetVisible() is ignored, so no more action will be executed.
+ // Therefore, this TC will be succeed only if there is another events like
+ // - RasterTaskImpl's OnTaskCompleted : this is flaky depending on tile
+ // task threads when SetVisible(false) is called.
+ // - NotifyReadytoActivate : this is not called in single threaded
+ // To remove flaky, PostTask is required here.
+ ImplThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&LayerTreeHostTestReadyToDrawVisibility::SetVisible,
+ base::Unretained(this), host_impl));
}
}
+ void SetVisible(LayerTreeHostImpl* host_impl) {
+ DebugScopedSetMainThread main(task_runner_provider());
+ layer_tree_host()->SetVisible(true);
+ EXPECT_TRUE(host_impl->visible());
+ }
+
void AfterTest() override {
EXPECT_TRUE(did_notify_ready_to_draw_);
EXPECT_TRUE(did_draw_);
@@ -1573,7 +1587,8 @@ class LayerTreeHostTestNoDamageCausesNoInvalidate : public LayerTreeHostTest {
// This behavior is specific to Android WebView, which only uses
// multi-threaded compositor.
-MULTI_THREAD_TEST_F(LayerTreeHostTestNoDamageCausesNoInvalidate);
+// TODO(https://crbug.com/1345000): Flaky.
+// MULTI_THREAD_TEST_F(LayerTreeHostTestNoDamageCausesNoInvalidate);
// When settings->enable_early_damage_check is true, verify that the early
// damage check is turned off after |settings->damaged_frame_limit| frames
@@ -3194,7 +3209,7 @@ class LayerTreeHostTestCommit : public LayerTreeHostTest {
void BeginTest() override {
layer_tree_host()->SetViewportRectAndScale(gfx::Rect(20, 20), 1.f,
viz::LocalSurfaceId());
- layer_tree_host()->set_background_color(SK_ColorGRAY);
+ layer_tree_host()->set_background_color(SkColors::kGray);
layer_tree_host()->SetEventListenerProperties(
EventListenerClass::kMouseWheel, EventListenerProperties::kPassive);
layer_tree_host()->SetEventListenerProperties(
@@ -3210,7 +3225,7 @@ class LayerTreeHostTestCommit : public LayerTreeHostTest {
void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override {
EXPECT_EQ(gfx::Rect(20, 20), impl->active_tree()->GetDeviceViewport());
- EXPECT_EQ(SK_ColorGRAY, impl->active_tree()->background_color());
+ EXPECT_EQ(SkColors::kGray, impl->active_tree()->background_color());
EXPECT_EQ(EventListenerProperties::kPassive,
impl->active_tree()->event_listener_properties(
EventListenerClass::kMouseWheel));
@@ -3240,7 +3255,7 @@ class LayerTreeHostTestFrameTimeUpdatesAfterActivationFails
void BeginTest() override {
layer_tree_host()->SetViewportRectAndScale(gfx::Rect(20, 20), 1.f,
viz::LocalSurfaceId());
- layer_tree_host()->set_background_color(SK_ColorGRAY);
+ layer_tree_host()->set_background_color(SkColors::kGray);
PostSetNeedsCommitToMainThread();
}
@@ -3293,7 +3308,7 @@ class LayerTreeHostTestFrameTimeUpdatesAfterDraw : public LayerTreeHostTest {
void BeginTest() override {
layer_tree_host()->SetViewportRectAndScale(gfx::Rect(20, 20), 1.f,
viz::LocalSurfaceId());
- layer_tree_host()->set_background_color(SK_ColorGRAY);
+ layer_tree_host()->set_background_color(SkColors::kGray);
PostSetNeedsCommitToMainThread();
}
@@ -7605,31 +7620,12 @@ class LayerTreeHostTestContinuousDrawWhenCreatingVisibleTiles
}
break;
case 4:
- ++step_;
- break;
- case 5:
- // Waiting for NotifyReadyToDraw.
- break;
- case 6:
- // NotifyReadyToDraw happened.
- ++step_;
+ // NotifyReadyToDrawOnThread() is not called in multi threaded mode
+ EndTest();
break;
}
}
- void NotifyReadyToDrawOnThread(LayerTreeHostImpl* host_impl) override {
- if (step_ == 5) {
- ++step_;
- // NotifyReadyToDraw has happened, we may draw once more, but should not
- // get any more draws after that. End the test after a timeout to watch
- // for any extraneous draws.
- // TODO(brianderson): We could remove this delay and instead wait until
- // the viz::BeginFrameSource decides it doesn't need to send frames
- // anymore, or test that it already doesn't here.
- EndTestAfterDelayMs(16 * 4);
- }
- }
-
void NotifyTileStateChangedOnThread(LayerTreeHostImpl* host_impl,
const Tile* tile) override {
// On step_ == 2, we are preventing texture uploads from completing,
@@ -7705,7 +7701,7 @@ class LayerTreeHostTestOneActivatePerPrepareTiles : public LayerTreeHostTest {
size_t scheduled_prepare_tiles_count_;
};
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestOneActivatePerPrepareTiles);
+MULTI_THREAD_TEST_F(LayerTreeHostTestOneActivatePerPrepareTiles);
class LayerTreeHostTestActivationCausesPrepareTiles : public LayerTreeHostTest {
public:
@@ -10334,5 +10330,155 @@ class LayerTreeHostTestInvalidateImplSideForRerasterTiling
scoped_refptr<FakePictureLayer> layer_on_main_;
};
MULTI_THREAD_TEST_F(LayerTreeHostTestInvalidateImplSideForRerasterTiling);
+
+class LayerTreeHostTestNeedsNotifyReadyToDrawAndActivate
+ : public LayerTreeHostTest {
+ public:
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ void DidCommitAndDrawFrame() override { EndTest(); }
+
+ void NotifyReadyToDrawOnThread(LayerTreeHostImpl* host_impl) override {
+ // called if needs_notify_ready_to_draw_ is true
+ EXPECT_TRUE(needs_notify_ready_to_draw_);
+ }
+
+ void NotifyReadyToActivateOnThread(LayerTreeHostImpl* host_impl) override {
+ // called if needs_notify_ready_to_activate_ is true
+ EXPECT_TRUE(needs_notify_ready_to_activate_);
+ }
+
+ protected:
+ bool needs_notify_ready_to_draw_ = true;
+ bool needs_notify_ready_to_activate_ = true;
+};
+
+class LayerTreeHostTestNeedsNotifyReadyToDrawOnly
+ : public LayerTreeHostTestNeedsNotifyReadyToDrawAndActivate {
+ public:
+ LayerTreeHostTestNeedsNotifyReadyToDrawOnly() {
+ // expectation for Single Threaded LayerTreeHost
+ needs_notify_ready_to_draw_ = true;
+ needs_notify_ready_to_activate_ = false;
+ }
+};
+SINGLE_THREAD_TEST_F(LayerTreeHostTestNeedsNotifyReadyToDrawOnly);
+
+class LayerTreeHostTestNeedsNotifyReadyToActivateOnly
+ : public LayerTreeHostTestNeedsNotifyReadyToDrawAndActivate {
+ public:
+ LayerTreeHostTestNeedsNotifyReadyToActivateOnly() {
+ // expectation for threaded LayerTreeHost
+ needs_notify_ready_to_draw_ = false;
+ needs_notify_ready_to_activate_ = true;
+ }
+};
+MULTI_THREAD_TEST_F(LayerTreeHostTestNeedsNotifyReadyToActivateOnly);
+
+class LayerTreeHostTestDidCommitAndDrawFrame : public LayerTreeHostTest {
+ public:
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ void DidCommitAndDrawFrame() override { EXPECT_EQ(0, num_draws_); }
+
+ void DidReceiveCompositorFrameAck() override {
+ ++num_draws_;
+ if (num_draws_ == 2) {
+ EndTest();
+ }
+ }
+
+ void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
+ EXPECT_EQ(0, host_impl->active_tree()->source_frame_number());
+ }
+
+ void DidReceiveCompositorFrameAckOnThread(
+ LayerTreeHostImpl* host_impl) override {
+ host_impl->SetViewportDamage(gfx::Rect(1, 1));
+ host_impl->RequestImplSideInvalidationForRerasterTiling();
+ }
+
+ protected:
+ int num_draws_ = 0;
+};
+
+MULTI_THREAD_TEST_F(LayerTreeHostTestDidCommitAndDrawFrame);
+
+class LayerTreeHostTestBeginFramePausedChanged : public LayerTreeHostTest {
+ protected:
+ void SetupTree() override {
+ scoped_refptr<Layer> root = Layer::Create();
+ root->SetBounds(gfx::Size(10, 10));
+ layer_tree_host()->SetRootLayer(std::move(root));
+ LayerTreeHostTest::SetupTree();
+ }
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ void ReadyToCommitOnThread(LayerTreeHostImpl* host_impl) override {
+ switch (host_impl->active_tree()->source_frame_number()) {
+ // frame 1 is ready in main thread and main thread is waiting until
+ // commit complete in impl thread
+ case 0:
+ // this should trigger OnBeginFramePausedChanged(true) callback, so that
+ // scheduler can abort the pending commit job
+ layer_tree_frame_sink_->UnregisterBeginFrameSource();
+ break;
+ }
+ }
+
+ void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
+ switch (host_impl->pending_tree()->source_frame_number()) {
+ case 1:
+ // Scheduler abort the pending commit job successfully
+ EndTest();
+ break;
+ }
+ }
+
+ void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
+ switch (host_impl->active_tree()->source_frame_number()) {
+ case 0:
+ // Block activation of pedning tree which is created by implside
+ // invalidation. This is for making ShouldCommit() return false.
+ host_impl->BlockNotifyReadyToActivateForTesting(true);
+ // next commit can start only if pending tree was created by implside
+ // invalidation.
+ host_impl->RequestImplSideInvalidationForRerasterTiling();
+ break;
+ }
+ }
+
+ void DidInvalidateContentOnImplSide(LayerTreeHostImpl* host_impl) override {
+ switch (host_impl->active_tree()->source_frame_number()) {
+ case 0:
+ // has_pending_tree_ is true now, so we can request next frame which
+ // will be stuck in main thread because has_pending_tree_ == true block
+ // commit process.
+ PostSetNeedsCommitToMainThread();
+ break;
+ }
+ }
+
+ std::unique_ptr<TestLayerTreeFrameSink> CreateLayerTreeFrameSink(
+ const viz::RendererSettings& renderer_settings,
+ double refresh_rate,
+ scoped_refptr<viz::ContextProvider> compositor_context_provider,
+ scoped_refptr<viz::RasterContextProvider> worker_context_provider)
+ override {
+ std::unique_ptr<TestLayerTreeFrameSink> frame_sink =
+ LayerTreeHostTest::CreateLayerTreeFrameSink(
+ renderer_settings, refresh_rate,
+ std::move(compositor_context_provider),
+ std::move(worker_context_provider));
+ layer_tree_frame_sink_ = frame_sink.get();
+ return frame_sink;
+ }
+
+ private:
+ TestLayerTreeFrameSink* layer_tree_frame_sink_;
+};
+MULTI_THREAD_TEST_F(LayerTreeHostTestBeginFramePausedChanged);
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_unittest_scroll.cc b/chromium/cc/trees/layer_tree_host_unittest_scroll.cc
index e5b26bd899b..053b3fef26b 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_scroll.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_scroll.cc
@@ -2922,5 +2922,125 @@ class LayerTreeHostScrollTestViewportAbortedCommit
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostScrollTestViewportAbortedCommit);
+class PreventRecreatingTilingDuringScroll : public LayerTreeHostScrollTest {
+ public:
+ PreventRecreatingTilingDuringScroll()
+ : initial_scale_(2.0f, 1.0f), new_scale_(2.0f, 2.0f) {}
+
+ void SetupTree() override {
+ LayerTreeHostScrollTest::SetupTree();
+
+ Layer* root_layer = layer_tree_host()->root_layer();
+ Layer* root_scroll_layer =
+ layer_tree_host()->OuterViewportScrollLayerForTesting();
+
+ child_layer_ = FakePictureLayer::Create(&client_);
+ child_layer_->SetElementId(
+ LayerIdToElementIdForTesting(child_layer_->id()));
+
+ child_layer_->SetIsDrawable(true);
+ child_layer_->SetHitTestable(true);
+ child_layer_->SetElementId(
+ LayerIdToElementIdForTesting(child_layer_->id()));
+ child_layer_->SetBounds(root_scroll_layer->bounds());
+ root_layer->AddChild(child_layer_);
+
+ CopyProperties(root_scroll_layer, child_layer_.get());
+ CreateTransformNode(child_layer_.get());
+ CreateScrollNode(child_layer_.get(), root_layer->bounds());
+ client_.set_bounds(root_scroll_layer->bounds());
+ client_.set_fill_with_nonsolid_color(true);
+ client_.set_has_draw_text_op();
+ child_layer_id_ = child_layer_->id();
+ }
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ void WillCommit(const CommitState&) override {
+ TransformTree& transform_tree =
+ layer_tree_host()->property_trees()->transform_tree_mutable();
+
+ gfx::Transform transform;
+ switch (layer_tree_host()->SourceFrameNumber()) {
+ case 0:
+ transform.Scale(initial_scale_.x(), initial_scale_.y());
+ transform_tree.OnTransformAnimated(child_layer_->element_id(),
+ transform);
+ break;
+ case 1:
+ transform.Scale(new_scale_.x(), new_scale_.y());
+ transform_tree.OnTransformAnimated(child_layer_->element_id(),
+ transform);
+ break;
+ }
+ }
+
+ void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
+ if (host_impl->active_tree()->source_frame_number() == 1) {
+ FakePictureLayerImpl* target_layer = static_cast<FakePictureLayerImpl*>(
+ host_impl->active_tree()->LayerById(child_layer_id_));
+ gfx::AxisTransform2d tiling_transform =
+ target_layer->HighResTiling()->raster_transform();
+
+ if (host_impl->GetActivelyScrollingType() !=
+ ActivelyScrollingType::kNone) {
+ // In active tree, recreating the delayed tiling should not happen
+ ASSERT_EQ(tiling_transform.scale(), initial_scale_);
+
+ // stop scroll to check if recreating tiling happen in active tree
+ scroll_check_pending_ = false;
+ host_impl->GetInputHandler().ScrollEnd();
+ // make sure redraw happen
+ host_impl->active_tree()->set_needs_update_draw_properties();
+ host_impl->SetNeedsRedraw();
+ }
+ }
+ }
+
+ void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
+ FakePictureLayerImpl* target_layer = static_cast<FakePictureLayerImpl*>(
+ host_impl->active_tree()->LayerById(child_layer_id_));
+ gfx::AxisTransform2d tiling_transform =
+ target_layer->HighResTiling()->raster_transform();
+
+ switch (host_impl->active_tree()->source_frame_number()) {
+ case 0:
+ // start scroll
+ host_impl->GetInputHandler().ScrollBegin(
+ BeginState(gfx::Point(0, 0), gfx::Vector2dF(0, 10)).get(),
+ ui::ScrollInputType::kTouchscreen);
+ host_impl->GetInputHandler().ScrollUpdate(
+ UpdateState(gfx::Point(), gfx::Vector2dF(0, 10)).get());
+ scroll_check_pending_ = true;
+ PostSetNeedsCommitToMainThread();
+ break;
+
+ case 1:
+ if (host_impl->GetActivelyScrollingType() !=
+ ActivelyScrollingType::kNone) {
+ // In pending tree, recreating tiling should delayed during scroll
+ ASSERT_TRUE(scroll_check_pending_);
+ ASSERT_EQ(tiling_transform.scale(), initial_scale_);
+ host_impl->SetNeedsRedraw();
+ } else {
+ // recreating tiling should happen after scroll finish
+ ASSERT_FALSE(scroll_check_pending_);
+ ASSERT_EQ(tiling_transform.scale(), new_scale_);
+ EndTest();
+ }
+ break;
+ }
+ }
+
+ private:
+ scoped_refptr<FakePictureLayer> child_layer_;
+ int child_layer_id_;
+ FakeContentLayerClient client_;
+ bool scroll_check_pending_ = true;
+ const gfx::Vector2dF initial_scale_;
+ const gfx::Vector2dF new_scale_;
+};
+
+MULTI_THREAD_TEST_F(PreventRecreatingTilingDuringScroll);
} // namespace
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_impl.cc b/chromium/cc/trees/layer_tree_impl.cc
index 13788d94cba..fcc078f346d 100644
--- a/chromium/cc/trees/layer_tree_impl.cc
+++ b/chromium/cc/trees/layer_tree_impl.cc
@@ -152,7 +152,7 @@ LayerTreeImpl::LayerTreeImpl(
is_first_frame_after_commit_tracker_(-1),
hud_layer_(nullptr),
property_trees_(host_impl),
- background_color_(0),
+ background_color_(SkColors::kTransparent),
last_scrolled_scroll_node_index_(kInvalidPropertyNodeId),
page_scale_factor_(page_scale_factor),
min_page_scale_factor_(0),
@@ -1483,19 +1483,21 @@ gfx::Rect LayerTreeImpl::RootScrollLayerDeviceViewportBounds() const {
gfx::Rect(root_scroll_node->bounds));
}
-void LayerTreeImpl::ApplySentScrollAndScaleDeltasFromAbortedCommit() {
+void LayerTreeImpl::ApplySentScrollAndScaleDeltasFromAbortedCommit(
+ bool main_frame_applied_deltas) {
DCHECK(IsActiveTree());
- page_scale_factor()->AbortCommit();
- top_controls_shown_ratio()->AbortCommit();
- elastic_overscroll()->AbortCommit();
+ page_scale_factor()->AbortCommit(main_frame_applied_deltas);
+ top_controls_shown_ratio()->AbortCommit(main_frame_applied_deltas);
+ bottom_controls_shown_ratio()->AbortCommit(main_frame_applied_deltas);
+ elastic_overscroll()->AbortCommit(main_frame_applied_deltas);
if (layer_list_.empty())
return;
property_trees()
->scroll_tree_mutable()
- .ApplySentScrollDeltasFromAbortedCommit();
+ .ApplySentScrollDeltasFromAbortedCommit(main_frame_applied_deltas);
}
void LayerTreeImpl::SetViewportPropertyIds(const ViewportPropertyIds& ids) {
@@ -2302,7 +2304,7 @@ static bool PointIsClippedByAncestorClipNode(
for (const ClipNode* clip_node = clip_tree.Node(layer->clip_tree_index());
clip_node->id > kViewportPropertyNodeId;
clip_node = clip_tree.parent(clip_node)) {
- if (clip_node->clip_type == ClipNode::ClipType::APPLIES_LOCAL_CLIP) {
+ if (clip_node->AppliesLocalClip()) {
clip = gfx::ToEnclosingRect(clip_node->clip);
gfx::Transform screen_space_transform =
@@ -2549,7 +2551,7 @@ LayerTreeImpl::FindAllLayersUpToAndIncludingFirstScrollable(
if (!layer->HitTestable())
continue;
- if (first_hit &&
+ if (first_hit && layer->Is3dSorted() &&
layer->GetSortingContextId() != first_hit->GetSortingContextId())
continue;
@@ -2568,7 +2570,7 @@ LayerTreeImpl::FindAllLayersUpToAndIncludingFirstScrollable(
if (!first_hit)
first_hit = layer;
- if (first_hit->Is3dSorted()) {
+ if (first_hit->Is3dSorted() && layer->Is3dSorted()) {
layers_3d.emplace_back(
std::pair<const LayerImpl*, float>(layer, distance_to_intersection));
} else {
@@ -2585,7 +2587,7 @@ LayerTreeImpl::FindAllLayersUpToAndIncludingFirstScrollable(
}
if (first_hit->Is3dSorted()) {
- DCHECK(layers.empty());
+ std::vector<const LayerImpl*> result;
DCHECK(!layers_3d.empty());
// Since we hit a layer in a rendering context, we need to sort the layers
@@ -2600,10 +2602,13 @@ LayerTreeImpl::FindAllLayersUpToAndIncludingFirstScrollable(
for (const auto& pair : layers_3d) {
const LayerImpl* layer = pair.first;
- layers.push_back(layer);
+ result.push_back(layer);
if (layer->IsScrollerOrScrollbar())
- break;
+ return result;
}
+ // Append 2D layers if none of the 3D layers were scrollable.
+ result.insert(result.end(), layers.begin(), layers.end());
+ return result;
} else {
DCHECK(!layers.empty());
DCHECK(layers_3d.empty());
diff --git a/chromium/cc/trees/layer_tree_impl.h b/chromium/cc/trees/layer_tree_impl.h
index 172bcc07769..f1d2b0bb7c8 100644
--- a/chromium/cc/trees/layer_tree_impl.h
+++ b/chromium/cc/trees/layer_tree_impl.h
@@ -360,10 +360,11 @@ class CC_EXPORT LayerTreeImpl {
void SetCurrentlyScrollingNode(const ScrollNode* node);
void ClearCurrentlyScrollingNode();
- void ApplySentScrollAndScaleDeltasFromAbortedCommit();
+ void ApplySentScrollAndScaleDeltasFromAbortedCommit(
+ bool main_frame_applied_deltas);
- SkColor background_color() const { return background_color_; }
- void set_background_color(SkColor color) { background_color_ = color; }
+ SkColor4f background_color() const { return background_color_; }
+ void set_background_color(SkColor4f color) { background_color_ = color; }
gfx::OverlayTransform display_transform_hint() const {
return display_transform_hint_;
@@ -835,7 +836,7 @@ class CC_EXPORT LayerTreeImpl {
int is_first_frame_after_commit_tracker_;
raw_ptr<HeadsUpDisplayLayerImpl> hud_layer_;
PropertyTrees property_trees_;
- SkColor background_color_;
+ SkColor4f background_color_;
int last_scrolled_scroll_node_index_;
diff --git a/chromium/cc/trees/layer_tree_settings.cc b/chromium/cc/trees/layer_tree_settings.cc
index b8168bd5b9e..43709401e46 100644
--- a/chromium/cc/trees/layer_tree_settings.cc
+++ b/chromium/cc/trees/layer_tree_settings.cc
@@ -36,6 +36,8 @@ TileManagerSettings LayerTreeSettings::ToTileManagerSettings() const {
tile_manager_settings.use_partial_raster = use_partial_raster;
tile_manager_settings.enable_checker_imaging = enable_checker_imaging;
tile_manager_settings.min_image_bytes_to_checker = min_image_bytes_to_checker;
+ tile_manager_settings.needs_notify_ready_to_draw =
+ commit_to_active_tree | wait_for_all_pipeline_stages_before_draw;
return tile_manager_settings;
}
diff --git a/chromium/cc/trees/layer_tree_settings.h b/chromium/cc/trees/layer_tree_settings.h
index 8dfe968b631..809fb46cc34 100644
--- a/chromium/cc/trees/layer_tree_settings.h
+++ b/chromium/cc/trees/layer_tree_settings.h
@@ -55,7 +55,7 @@ class CC_EXPORT LayerTreeSettings {
base::TimeDelta scrollbar_fade_duration;
base::TimeDelta scrollbar_thinning_duration;
bool scrollbar_flash_after_any_scroll_update = false;
- SkColor solid_color_scrollbar_color = SK_ColorWHITE;
+ SkColor4f solid_color_scrollbar_color = SkColors::kWhite;
base::TimeDelta scroll_animation_duration_for_testing;
bool timeout_and_draw_when_animation_checkerboards = true;
bool layers_always_allowed_lcd_text = false;
@@ -212,6 +212,9 @@ class CC_EXPORT LayerTreeSettings {
// Whether Fluent scrollbar is enabled. Please check https://crbug.com/1292117
// to find the link to the Fluent Scrollbar spec and related CLs.
bool enable_fluent_scrollbar = false;
+
+ // This corresponds to the ScrollUpdateOptimizations feature.
+ bool enable_scroll_update_optimizations = false;
};
class CC_EXPORT LayerListSettings : public LayerTreeSettings {
diff --git a/chromium/cc/trees/occlusion_tracker_unittest.cc b/chromium/cc/trees/occlusion_tracker_unittest.cc
index 6fd08a276d2..58ffd40cba5 100644
--- a/chromium/cc/trees/occlusion_tracker_unittest.cc
+++ b/chromium/cc/trees/occlusion_tracker_unittest.cc
@@ -1459,8 +1459,8 @@ class OcclusionTrackerTestPixelsNeededForDropShadowBackdropFilter
scale_by_half.Scale(0.5, 0.5);
FilterOperations filters;
- filters.Append(FilterOperation::CreateDropShadowFilter(gfx::Point(10, 10),
- 5, SK_ColorBLACK));
+ filters.Append(FilterOperation::CreateDropShadowFilter(
+ gfx::Point(10, 10), 5, SkColors::kBlack));
enum Direction {
LEFT,
diff --git a/chromium/cc/trees/property_tree.cc b/chromium/cc/trees/property_tree.cc
index 7a3bb079487..c631c494fde 100644
--- a/chromium/cc/trees/property_tree.cc
+++ b/chromium/cc/trees/property_tree.cc
@@ -181,6 +181,7 @@ void TransformTree::UpdateTransforms(
DCHECK(parent_node);
// TODO(flackr): Only dirty when scroll offset changes.
if (node->sticky_position_constraint_id >= 0 ||
+ node->anchor_scroll_containers_data_id >= 0 ||
node->needs_local_transform_update || ShouldUndoOverscroll(node)) {
UpdateLocalTransform(node, viewport_property_ids);
} else {
@@ -455,6 +456,47 @@ gfx::Vector2dF TransformTree::StickyPositionOffset(TransformNode* node) {
return gfx::ToRoundedVector2d(sticky_offset);
}
+AnchorScrollContainersData& TransformTree::EnsureAnchorScrollContainersData(
+ int node_id) {
+ TransformNode* node = Node(node_id);
+ if (node->anchor_scroll_containers_data_id == -1) {
+ node->anchor_scroll_containers_data_id =
+ anchor_scroll_containers_data_.size();
+ anchor_scroll_containers_data_.push_back(AnchorScrollContainersData());
+ }
+ return anchor_scroll_containers_data_[node->anchor_scroll_containers_data_id];
+}
+
+const AnchorScrollContainersData* TransformTree::GetAnchorScrollContainersData(
+ int node_id) const {
+ const TransformNode* node = Node(node_id);
+ if (node->anchor_scroll_containers_data_id == -1)
+ return nullptr;
+ return &anchor_scroll_containers_data_
+ [node->anchor_scroll_containers_data_id];
+}
+
+gfx::Vector2dF TransformTree::AnchorScrollOffset(TransformNode* node) {
+ const AnchorScrollContainersData* data =
+ GetAnchorScrollContainersData(node->id);
+ if (!data)
+ return gfx::Vector2dF();
+ gfx::Vector2dF accumulated_scroll_offset(0, 0);
+ for (int scroller_id = data->inner_most_scroll_container_id;
+ scroller_id != kInvalidPropertyNodeId;) {
+ const ScrollNode* scroll_node =
+ property_trees()->scroll_tree().Node(scroller_id);
+ const TransformNode* transform_node = Node(scroll_node->transform_id);
+ accumulated_scroll_offset +=
+ transform_node->scroll_offset.OffsetFromOrigin();
+
+ if (scroller_id == data->outer_most_scroll_container_id)
+ break;
+ scroller_id = scroll_node->parent_id;
+ }
+ return data->accumulated_scroll_origin - accumulated_scroll_offset;
+}
+
bool TransformTree::ShouldUndoOverscroll(const TransformNode* node) const {
return fixed_elements_dont_overscroll_ && node && node->is_fixed_to_viewport;
}
@@ -517,6 +559,7 @@ void TransformTree::UpdateLocalTransform(
transform.Translate(fixed_position_adjustment -
node->scroll_offset.OffsetFromOrigin());
transform.Translate(StickyPositionOffset(node));
+ transform.Translate(AnchorScrollOffset(node));
transform.PreconcatTransform(node->local);
transform.Translate3d(gfx::Point3F() - node->origin);
@@ -1363,7 +1406,15 @@ bool ScrollTree::IsComposited(const ScrollNode& node) const {
}
bool ScrollTree::CanRealizeScrollsOnCompositor(const ScrollNode& node) const {
- return node.is_composited && !node.main_thread_scrolling_reasons;
+ return GetMainThreadRepaintReasons(node) ==
+ MainThreadScrollingReason::kNotScrollingOnMain;
+}
+
+uint32_t ScrollTree::GetMainThreadRepaintReasons(const ScrollNode& node) const {
+ uint32_t reasons = node.main_thread_scrolling_reasons;
+ if (!node.is_composited)
+ reasons |= MainThreadScrollingReason::kNoScrollingLayer;
+ return reasons;
}
void ScrollTree::clear() {
@@ -1653,10 +1704,15 @@ void ScrollTree::PushScrollUpdatesFromMainThread(
for (auto map_entry = synced_scroll_offset_map_.begin();
map_entry != synced_scroll_offset_map_.end();) {
ElementId id = map_entry->first;
- if (main_scroll_offset_map.find(id) == main_scroll_offset_map.end())
+ if (main_scroll_offset_map.find(id) == main_scroll_offset_map.end()) {
+ // This SyncedScrollOffset might still be used to send a delta from the
+ // active tree to the main thread, so we need to clear out the delta that
+ // was sent to the main thread for this commit.
+ map_entry->second->PushMainToPending(map_entry->second->Current(true));
map_entry = synced_scroll_offset_map_.erase(map_entry);
- else
+ } else {
map_entry++;
+ }
}
for (auto map_entry : main_scroll_offset_map) {
@@ -1712,10 +1768,11 @@ void ScrollTree::PushScrollUpdatesFromPendingTree(
}
}
-void ScrollTree::ApplySentScrollDeltasFromAbortedCommit() {
+void ScrollTree::ApplySentScrollDeltasFromAbortedCommit(
+ bool main_frame_applied_deltas) {
DCHECK(property_trees()->is_active());
for (auto& map_entry : synced_scroll_offset_map_)
- map_entry.second->AbortCommit();
+ map_entry.second->AbortCommit(main_frame_applied_deltas);
}
void ScrollTree::SetBaseScrollOffset(ElementId id,
diff --git a/chromium/cc/trees/property_tree.h b/chromium/cc/trees/property_tree.h
index 78f52a32cbc..5880323fb67 100644
--- a/chromium/cc/trees/property_tree.h
+++ b/chromium/cc/trees/property_tree.h
@@ -157,6 +157,7 @@ class CC_EXPORT PropertyTree {
base::flat_map<ElementId, int> element_id_to_node_index_;
};
+struct AnchorScrollContainersData;
struct StickyPositionNodeData;
class CC_EXPORT TransformTree final : public PropertyTree<TransformNode> {
@@ -258,6 +259,10 @@ class CC_EXPORT TransformTree final : public PropertyTree<TransformNode> {
}
StickyPositionNodeData& EnsureStickyPositionData(int node_id);
+ const AnchorScrollContainersData* GetAnchorScrollContainersData(
+ int node_id) const;
+ AnchorScrollContainersData& EnsureAnchorScrollContainersData(int node_id);
+
// Computes the combined transform between |source_id| and |dest_id|. These
// two nodes must be on the same ancestor chain.
void CombineTransformsBetween(int source_id,
@@ -278,6 +283,7 @@ class CC_EXPORT TransformTree final : public PropertyTree<TransformNode> {
StickyPositionNodeData* MutableStickyPositionData(int node_id);
gfx::Vector2dF StickyPositionOffset(TransformNode* node);
+ gfx::Vector2dF AnchorScrollOffset(TransformNode* node);
void UpdateLocalTransform(TransformNode* node,
const ViewportPropertyIds* viewport_property_ids);
void UpdateScreenSpaceTransform(TransformNode* node,
@@ -300,6 +306,13 @@ class CC_EXPORT TransformTree final : public PropertyTree<TransformNode> {
std::vector<int> nodes_affected_by_outer_viewport_bounds_delta_;
std::vector<TransformCachedNodeData> cached_data_;
std::vector<StickyPositionNodeData> sticky_position_data_;
+ std::vector<AnchorScrollContainersData> anchor_scroll_containers_data_;
+};
+
+struct AnchorScrollContainersData {
+ int inner_most_scroll_container_id = kInvalidPropertyNodeId;
+ int outer_most_scroll_container_id = kInvalidPropertyNodeId;
+ gfx::Vector2d accumulated_scroll_origin;
};
struct StickyPositionNodeData {
@@ -390,11 +403,11 @@ class CC_EXPORT EffectTree final : public PropertyTree<EffectNode> {
int LowestCommonAncestorWithRenderSurface(int id_1, int id_2) const;
RenderSurfaceImpl* GetRenderSurface(int id) {
- return render_surfaces_[id].get();
+ return render_surfaces_[static_cast<size_t>(id)].get();
}
const RenderSurfaceImpl* GetRenderSurface(int id) const {
- return render_surfaces_[id].get();
+ return render_surfaces_[static_cast<size_t>(id)].get();
}
void ClearTransitionPseudoElementEffectNodes();
@@ -526,7 +539,7 @@ class CC_EXPORT ScrollTree final : public PropertyTree<ScrollNode> {
// Applies deltas sent in the previous main frame onto the impl thread state.
// Should only be called on the impl thread side PropertyTrees.
- void ApplySentScrollDeltasFromAbortedCommit();
+ void ApplySentScrollDeltasFromAbortedCommit(bool main_frame_applied_deltas);
// Pushes scroll updates from the ScrollTree on the main thread onto the
// impl thread associated state.
@@ -583,6 +596,11 @@ class CC_EXPORT ScrollTree final : public PropertyTree<ScrollNode> {
// main-thread scrolling reasons (see main_thread_scrolling_reason.h).
bool CanRealizeScrollsOnCompositor(const ScrollNode& node) const;
+ // Reports reasons for blocking scroll updates on main-thread repaint. For use
+ // only with scroll unification enabled. Returns bitfield of values from
+ // MainThreadScrollingReason.
+ uint32_t GetMainThreadRepaintReasons(const ScrollNode& node) const;
+
private:
// ScrollTree doesn't use the needs_update flag.
using PropertyTree::needs_update;
diff --git a/chromium/cc/trees/property_tree_builder.cc b/chromium/cc/trees/property_tree_builder.cc
index 00eb3a85b00..eb6da2827e6 100644
--- a/chromium/cc/trees/property_tree_builder.cc
+++ b/chromium/cc/trees/property_tree_builder.cc
@@ -43,7 +43,7 @@ struct DataForRecursion {
int closest_ancestor_with_cached_render_surface;
int closest_ancestor_with_copy_request;
int closest_ancestor_being_captured;
- SkColor safe_opaque_background_color;
+ SkColor4f safe_opaque_background_color;
bool animation_axis_aligned_since_render_target;
bool not_axis_aligned_since_last_clip;
gfx::Transform compound_transform_since_render_target;
@@ -215,21 +215,17 @@ void PropertyTreeBuilderContext::AddClipNodeIfNeeded(
data_for_children->clip_tree_parent = parent_id;
} else {
ClipNode node;
- node.clip = layer->EffectiveClipRect();
-
- // Move the clip bounds so that it is relative to the transform parent.
- node.clip += layer->offset_to_transform_parent();
-
- node.transform_id = created_transform_node
- ? data_for_children->transform_tree_parent
- : data_from_ancestor.transform_tree_parent;
if (layer_clips_subtree) {
- node.clip_type = ClipNode::ClipType::APPLIES_LOCAL_CLIP;
+ node.clip = layer->EffectiveClipRect();
+ // Move the clip bounds so that it is relative to the transform parent.
+ node.clip += layer->offset_to_transform_parent();
} else {
DCHECK(layer->filters().HasFilterThatMovesPixels());
- node.clip_type = ClipNode::ClipType::EXPANDS_CLIP;
- node.clip_expander = ClipExpander(layer->effect_tree_index());
+ node.pixel_moving_filter_id = layer->effect_tree_index();
}
+ node.transform_id = created_transform_node
+ ? data_for_children->transform_tree_parent
+ : data_from_ancestor.transform_tree_parent;
data_for_children->clip_tree_parent = clip_tree_.Insert(node, parent_id);
}
@@ -716,15 +712,13 @@ void PropertyTreeBuilderContext::AddScrollNodeIfNeeded(
void SetSafeOpaqueBackgroundColor(const DataForRecursion& data_from_ancestor,
Layer* layer,
DataForRecursion* data_for_children) {
- // TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
- SkColor background_color = layer->background_color().toSkColor();
+ SkColor4f background_color = layer->background_color();
data_for_children->safe_opaque_background_color =
- SkColorGetA(background_color) == 255
+ background_color.isOpaque()
? background_color
: data_from_ancestor.safe_opaque_background_color;
- // TODO(crbug/1308932): Remove FromColor and make all SkColor4f.
layer->SetSafeOpaqueBackgroundColor(
- SkColor4f::FromColor(data_for_children->safe_opaque_background_color));
+ data_for_children->safe_opaque_background_color);
}
void PropertyTreeBuilderContext::BuildPropertyTreesInternal(
@@ -806,16 +800,15 @@ void PropertyTreeBuilderContext::BuildPropertyTrees() {
data_for_recursion.animation_axis_aligned_since_render_target = true;
data_for_recursion.not_axis_aligned_since_last_clip = false;
- SkColor root_background_color = layer_tree_host_->background_color();
- if (SkColorGetA(root_background_color) != 255)
- root_background_color = SkColorSetA(root_background_color, 255);
- data_for_recursion.safe_opaque_background_color = root_background_color;
+ data_for_recursion.safe_opaque_background_color =
+ layer_tree_host_->background_color().isOpaque()
+ ? layer_tree_host_->background_color()
+ : layer_tree_host_->background_color().makeOpaque();
property_trees_.clear();
transform_tree_.set_device_scale_factor(
layer_tree_host_->device_scale_factor());
ClipNode root_clip;
- root_clip.clip_type = ClipNode::ClipType::APPLIES_LOCAL_CLIP;
root_clip.clip = gfx::RectF(layer_tree_host_->device_viewport_rect());
root_clip.transform_id = kRootPropertyNodeId;
data_for_recursion.clip_tree_parent =
diff --git a/chromium/cc/trees/property_tree_builder_unittest.cc b/chromium/cc/trees/property_tree_builder_unittest.cc
index 5b5f96f4476..b3a537c7f46 100644
--- a/chromium/cc/trees/property_tree_builder_unittest.cc
+++ b/chromium/cc/trees/property_tree_builder_unittest.cc
@@ -764,7 +764,7 @@ TEST_F(PropertyTreeBuilderTest, GradientMask) {
child1->SetIsDrawable(true);
gfx::LinearGradient gradient_mask(45);
- gradient_mask.AddStep(50, 0x50);
+ gradient_mask.AddStep(.5, 0x50);
child1->SetGradientMask(gradient_mask);
// Without render surface.
@@ -807,12 +807,12 @@ TEST_F(PropertyTreeBuilderTest, GradientMask) {
EXPECT_EQ(gfx::RectF(10, 10, 300, 200),
layer_impl1->draw_properties().mask_filter_info.bounds());
// |angle| is updated by the scale transform.
- EXPECT_EQ(33, layer_impl1->draw_properties()
+ EXPECT_EQ(34, layer_impl1->draw_properties()
.mask_filter_info.gradient_mask()
- .angle());
+ ->angle());
EXPECT_EQ(gradient_mask.steps(), layer_impl1->draw_properties()
.mask_filter_info.gradient_mask()
- .steps());
+ ->steps());
}
// Rotate transform eliminates gradient mask.
@@ -878,10 +878,11 @@ TEST_F(PropertyTreeBuilderTest, GradientMask) {
EXPECT_EQ(gfx::RectF(10, 10, 300, 200),
render_surface_impl1->mask_filter_info().bounds());
// |angle| is updated by the scale transform.
- EXPECT_EQ(33,
- render_surface_impl1->mask_filter_info().gradient_mask().angle());
- EXPECT_EQ(gradient_mask.steps(),
- render_surface_impl1->mask_filter_info().gradient_mask().steps());
+ EXPECT_EQ(
+ 34, render_surface_impl1->mask_filter_info().gradient_mask()->angle());
+ EXPECT_EQ(
+ gradient_mask.steps(),
+ render_surface_impl1->mask_filter_info().gradient_mask()->steps());
}
// Rotate transform eliminates gradient mask.
@@ -914,12 +915,12 @@ TEST_F(PropertyTreeBuilderTest, NestedGradientMask) {
grand_child1->SetIsDrawable(true);
gfx::LinearGradient gradient_mask1(30);
- gradient_mask1.AddStep(50, 0x50);
+ gradient_mask1.AddStep(.5, 0x50);
child1->SetGradientMask(gradient_mask1);
gfx::LinearGradient gradient_mask2(45);
gradient_mask2.AddStep(0, 0xFF);
- gradient_mask2.AddStep(100, 0x0);
+ gradient_mask2.AddStep(1, 0x0);
grand_child1->SetGradientMask(gradient_mask2);
CommitAndActivate();
@@ -960,11 +961,12 @@ TEST_F(PropertyTreeBuilderTest, NestedGradientMask) {
// |mask_info| coordinates are in the target space of the render surface's
// layer.
auto* render_surface_impl1 = GetRenderSurfaceImpl(child1);
- EXPECT_EQ(gradient_mask1.steps(),
- render_surface_impl1->mask_filter_info().gradient_mask().steps());
+ EXPECT_EQ(
+ gradient_mask1.steps(),
+ render_surface_impl1->mask_filter_info().gradient_mask()->steps());
// |angle| is updated by the scale transform.
- EXPECT_EQ(21,
- render_surface_impl1->mask_filter_info().gradient_mask().angle());
+ EXPECT_EQ(
+ 21, render_surface_impl1->mask_filter_info().gradient_mask()->angle());
// |mask_info| is in the coordinate space of the transform node associated
// with this effect node.
@@ -979,9 +981,9 @@ TEST_F(PropertyTreeBuilderTest, NestedGradientMask) {
EXPECT_EQ(gfx::RectF(30, 10, 300, 150),
draw_properties2.mask_filter_info.bounds());
// |angle| is updated by the scale transform.
- EXPECT_EQ(26, draw_properties2.mask_filter_info.gradient_mask().angle());
+ EXPECT_EQ(27, draw_properties2.mask_filter_info.gradient_mask()->angle());
EXPECT_EQ(gradient_mask2.steps(),
- draw_properties2.mask_filter_info.gradient_mask().steps());
+ draw_properties2.mask_filter_info.gradient_mask()->steps());
}
gfx::Transform rotate_transform;
diff --git a/chromium/cc/trees/proxy.h b/chromium/cc/trees/proxy.h
index 6c879ed922d..9e865842342 100644
--- a/chromium/cc/trees/proxy.h
+++ b/chromium/cc/trees/proxy.h
@@ -101,9 +101,9 @@ class CC_EXPORT Proxy {
virtual void SetRenderFrameObserver(
std::unique_ptr<RenderFrameMetadataObserver> observer) = 0;
- // Returns a percentage representing average throughput of last X seconds.
+ // Returns a percentage of dropped frames of the last second.
// Only implemenented for single threaded proxy.
- virtual uint32_t GetAverageThroughput() const = 0;
+ virtual double GetPercentDroppedFrames() const = 0;
};
} // namespace cc
diff --git a/chromium/cc/trees/proxy_impl.cc b/chromium/cc/trees/proxy_impl.cc
index e253b21d1ba..298b13f3c57 100644
--- a/chromium/cc/trees/proxy_impl.cc
+++ b/chromium/cc/trees/proxy_impl.cc
@@ -64,7 +64,7 @@ class ScopedCommitCompletionEvent {
proxy_main_weak_ptr_(proxy_main_weak_ptr) {}
ScopedCommitCompletionEvent(const ScopedCommitCompletionEvent&) = delete;
~ScopedCommitCompletionEvent() {
- event_->Signal();
+ event_.ExtractAsDangling()->Signal();
main_thread_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&ProxyMain::DidCompleteCommit,
proxy_main_weak_ptr_, commit_timestamps_));
@@ -77,7 +77,7 @@ class ScopedCommitCompletionEvent {
}
private:
- const raw_ptr<CompletionEvent> event_;
+ raw_ptr<CompletionEvent> event_;
CommitTimestamps commit_timestamps_;
raw_ptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
base::WeakPtr<ProxyMain> proxy_main_weak_ptr_;
@@ -797,8 +797,6 @@ void ProxyImpl::ScheduledActionPostCommit() {
// This is run as a separate step from commit because it can be time-consuming
// and ought not delay sending the next BeginMainFrame.
host_impl_->CommitComplete();
- // TODO(szager): This should be set at activation time. crbug.com/1323906
- next_frame_is_newly_committed_frame_ = true;
}
void ProxyImpl::ScheduledActionActivateSyncTree() {
@@ -809,6 +807,7 @@ void ProxyImpl::ScheduledActionActivateSyncTree() {
"viz,benchmark", "MainFrame.Activate",
TRACE_ID_LOCAL(host_impl_->sync_tree()->trace_id()),
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
+ next_frame_is_newly_committed_frame_ = true;
}
DCHECK(IsImplThread());
host_impl_->ActivateSyncTree();
diff --git a/chromium/cc/trees/proxy_main.cc b/chromium/cc/trees/proxy_main.cc
index 4bd1151680d..e56b02a53b8 100644
--- a/chromium/cc/trees/proxy_main.cc
+++ b/chromium/cc/trees/proxy_main.cc
@@ -606,7 +606,7 @@ bool ProxyMain::StartDeferringCommits(base::TimeDelta timeout,
commits_restart_time_ = base::TimeTicks::Now() + timeout;
// Notify dependent systems that the deferral status has changed.
- layer_tree_host_->OnDeferCommitsChanged(true, reason);
+ layer_tree_host_->OnDeferCommitsChanged(true, reason, absl::nullopt);
return true;
}
@@ -621,7 +621,7 @@ void ProxyMain::StopDeferringCommits(PaintHoldingCommitTrigger trigger) {
TRACE_ID_LOCAL(this));
// Notify depended systems that the deferral status has changed.
- layer_tree_host_->OnDeferCommitsChanged(false, reason);
+ layer_tree_host_->OnDeferCommitsChanged(false, reason, trigger);
}
bool ProxyMain::IsDeferringCommits() const {
@@ -803,9 +803,9 @@ void ProxyMain::SetRenderFrameObserver(
base::Unretained(proxy_impl_.get()), std::move(observer)));
}
-uint32_t ProxyMain::GetAverageThroughput() const {
+double ProxyMain::GetPercentDroppedFrames() const {
NOTIMPLEMENTED();
- return 0u;
+ return 0.0;
}
} // namespace cc
diff --git a/chromium/cc/trees/proxy_main.h b/chromium/cc/trees/proxy_main.h
index 1f0be862d15..bea1deee75c 100644
--- a/chromium/cc/trees/proxy_main.h
+++ b/chromium/cc/trees/proxy_main.h
@@ -120,7 +120,7 @@ class CC_EXPORT ProxyMain : public Proxy {
base::WritableSharedMemoryMapping ukm_smoothness_data) override;
void SetRenderFrameObserver(
std::unique_ptr<RenderFrameMetadataObserver> observer) override;
- uint32_t GetAverageThroughput() const override;
+ double GetPercentDroppedFrames() const override;
// Returns |true| if the request was actually sent, |false| if one was
// already outstanding.
diff --git a/chromium/cc/trees/render_frame_metadata.h b/chromium/cc/trees/render_frame_metadata.h
index 0c0395e5eb5..25e1daef871 100644
--- a/chromium/cc/trees/render_frame_metadata.h
+++ b/chromium/cc/trees/render_frame_metadata.h
@@ -64,7 +64,7 @@ class CC_EXPORT RenderFrameMetadata {
// The background color of a CompositorFrame. It can be used for filling the
// content area if the primary surface is unavailable and fallback is not
// specified.
- SkColor root_background_color = SK_ColorWHITE;
+ SkColor4f root_background_color = SkColors::kWhite;
// Scroll offset of the root layer.
absl::optional<gfx::PointF> root_scroll_offset;
diff --git a/chromium/cc/trees/single_thread_proxy.cc b/chromium/cc/trees/single_thread_proxy.cc
index 0066ee64b58..8df4049f4fa 100644
--- a/chromium/cc/trees/single_thread_proxy.cc
+++ b/chromium/cc/trees/single_thread_proxy.cc
@@ -366,7 +366,7 @@ bool SingleThreadProxy::StartDeferringCommits(base::TimeDelta timeout,
commits_restart_time_ = base::TimeTicks::Now() + timeout;
// Notify dependent systems that the deferral status has changed.
- layer_tree_host_->OnDeferCommitsChanged(true, reason);
+ layer_tree_host_->OnDeferCommitsChanged(true, reason, absl::nullopt);
return true;
}
@@ -383,7 +383,7 @@ void SingleThreadProxy::StopDeferringCommits(
TRACE_ID_LOCAL(this));
// Notify dependent systems that the deferral status has changed.
- layer_tree_host_->OnDeferCommitsChanged(false, reason);
+ layer_tree_host_->OnDeferCommitsChanged(false, reason, trigger);
}
bool SingleThreadProxy::IsDeferringCommits() const {
@@ -909,9 +909,10 @@ void SingleThreadProxy::SetRenderFrameObserver(
host_impl_->SetRenderFrameObserver(std::move(observer));
}
-uint32_t SingleThreadProxy::GetAverageThroughput() const {
+double SingleThreadProxy::GetPercentDroppedFrames() const {
DebugScopedSetImplThread impl(task_runner_provider_);
- return host_impl_->dropped_frame_counter()->GetAverageThroughput();
+ return host_impl_->dropped_frame_counter()
+ ->sliding_window_current_percent_dropped();
}
void SingleThreadProxy::UpdateBrowserControlsState(
@@ -1063,7 +1064,7 @@ void SingleThreadProxy::DoBeginMainFrame(
layer_tree_host_->BeginMainFrame(begin_frame_args);
layer_tree_host_->AnimateLayers(begin_frame_args.frame_time);
-#if BUILDFLAG(IS_CHROMEOS_ASH)
+#if BUILDFLAG(IS_CHROMEOS)
const bool record_metrics =
layer_tree_host_->GetSettings().is_layer_tree_for_ui;
#else
diff --git a/chromium/cc/trees/single_thread_proxy.h b/chromium/cc/trees/single_thread_proxy.h
index fef5133be31..96ddc04576d 100644
--- a/chromium/cc/trees/single_thread_proxy.h
+++ b/chromium/cc/trees/single_thread_proxy.h
@@ -76,7 +76,7 @@ class CC_EXPORT SingleThreadProxy : public Proxy,
base::WritableSharedMemoryMapping ukm_smoothness_data) override;
void SetRenderFrameObserver(
std::unique_ptr<RenderFrameMetadataObserver> observer) override;
- uint32_t GetAverageThroughput() const override;
+ double GetPercentDroppedFrames() const override;
void UpdateBrowserControlsState(BrowserControlsState constraints,
BrowserControlsState current,
diff --git a/chromium/cc/trees/transform_node.cc b/chromium/cc/trees/transform_node.cc
index a09615e1fae..d964b3ef628 100644
--- a/chromium/cc/trees/transform_node.cc
+++ b/chromium/cc/trees/transform_node.cc
@@ -17,6 +17,7 @@ TransformNode::TransformNode()
parent_id(kInvalidPropertyNodeId),
parent_frame_id(kInvalidPropertyNodeId),
sticky_position_constraint_id(-1),
+ anchor_scroll_containers_data_id(-1),
sorting_context_id(0),
needs_local_transform_update(true),
node_and_ancestors_are_animated_or_invertible(true),
diff --git a/chromium/cc/trees/transform_node.h b/chromium/cc/trees/transform_node.h
index e3e7ca9f0d7..95220aa2a7a 100644
--- a/chromium/cc/trees/transform_node.h
+++ b/chromium/cc/trees/transform_node.h
@@ -51,6 +51,10 @@ struct CC_EXPORT TransformNode {
// transform node. -1 indicates there are no sticky position constraints.
int sticky_position_constraint_id;
+ // This is the data of the scroll container of the anchor node specified by
+ // the `anchor-scroll` property. -1 indicates there is no such node.
+ int anchor_scroll_containers_data_id;
+
// This id determines which 3d rendering context the node is in. 0 is a
// special value and indicates that the node is not in any 3d rendering
// context.
diff --git a/chromium/cc/trees/tree_synchronizer_unittest.cc b/chromium/cc/trees/tree_synchronizer_unittest.cc
index 99a90139da0..7cfeade91bb 100644
--- a/chromium/cc/trees/tree_synchronizer_unittest.cc
+++ b/chromium/cc/trees/tree_synchronizer_unittest.cc
@@ -802,7 +802,7 @@ TEST_F(TreeSynchronizerTest, RoundedScrollDeltasOnCommit) {
// Since this test simulates a scroll it needs an input handler.
// TODO(bokan): Required because scroll commit is part of InputHandler - that
- // shouldn't be. See comment in ThreadedInputHandler::ProcessCommitDeltas.
+ // shouldn't be. See comment in InputHandler::ProcessCommitDeltas.
InputHandler::Create(static_cast<CompositorDelegateForInput&>(*host_impl));
scoped_refptr<Layer> scroll_layer = SetupScrollLayer();
@@ -828,7 +828,7 @@ TEST_F(TreeSynchronizerTest, PreserveFractionalScrollDeltasOnCommit) {
// Since this test simulates a scroll it needs an input handler.
// TODO(bokan): Required because scroll commit is part of InputHandler - that
- // shouldn't be. See comment in ThreadedInputHandler::ProcessCommitDeltas.
+ // shouldn't be. See comment in InputHandler::ProcessCommitDeltas.
InputHandler::Create(static_cast<CompositorDelegateForInput&>(*host_impl));
scoped_refptr<Layer> scroll_layer = SetupScrollLayer();