summaryrefslogtreecommitdiffstats
path: root/chromium/cc
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2021-05-20 09:47:09 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2021-06-07 11:15:42 +0000
commit189d4fd8fad9e3c776873be51938cd31a42b6177 (patch)
tree6497caeff5e383937996768766ab3bb2081a40b2 /chromium/cc
parent8bc75099d364490b22f43a7ce366b366c08f4164 (diff)
BASELINE: Update Chromium to 90.0.4430.221
Change-Id: Iff4d9d18d2fcf1a576f3b1f453010f744a232920 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/cc')
-rw-r--r--chromium/cc/BUILD.gn46
-rw-r--r--chromium/cc/OWNERS6
-rw-r--r--chromium/cc/animation/BUILD.gn14
-rw-r--r--chromium/cc/animation/animation.cc3
-rw-r--r--chromium/cc/animation/animation.h5
-rw-r--r--chromium/cc/animation/animation_curve.cc69
-rw-r--r--chromium/cc/animation/animation_curve.h122
-rw-r--r--chromium/cc/animation/animation_delegate.h8
-rw-r--r--chromium/cc/animation/animation_events.h4
-rw-r--r--chromium/cc/animation/animation_host.cc55
-rw-r--r--chromium/cc/animation/animation_host.h14
-rw-r--r--chromium/cc/animation/animation_target.h52
-rw-r--r--chromium/cc/animation/animation_unittest.cc39
-rw-r--r--chromium/cc/animation/element_animations.cc222
-rw-r--r--chromium/cc/animation/element_animations.h105
-rw-r--r--chromium/cc/animation/element_animations_unittest.cc674
-rw-r--r--chromium/cc/animation/filter_animation_curve.cc206
-rw-r--r--chromium/cc/animation/filter_animation_curve.h83
-rw-r--r--chromium/cc/animation/filter_animation_curve_unittest.cc127
-rw-r--r--chromium/cc/animation/keyframe_effect.cc310
-rw-r--r--chromium/cc/animation/keyframe_effect.h30
-rw-r--r--chromium/cc/animation/keyframe_model.cc342
-rw-r--r--chromium/cc/animation/keyframe_model.h223
-rw-r--r--chromium/cc/animation/keyframe_model_unittest.cc34
-rw-r--r--chromium/cc/animation/keyframed_animation_curve.cc548
-rw-r--r--chromium/cc/animation/keyframed_animation_curve.h349
-rw-r--r--chromium/cc/animation/keyframed_animation_curve_unittest.cc1093
-rw-r--r--chromium/cc/animation/scroll_offset_animation_curve.cc76
-rw-r--r--chromium/cc/animation/scroll_offset_animation_curve.h46
-rw-r--r--chromium/cc/animation/scroll_offset_animation_curve_factory.cc6
-rw-r--r--chromium/cc/animation/scroll_offset_animation_curve_unittest.cc68
-rw-r--r--chromium/cc/animation/scroll_offset_animations_impl.cc19
-rw-r--r--chromium/cc/animation/scroll_offset_animations_impl.h14
-rw-r--r--chromium/cc/animation/scroll_timeline.h19
-rw-r--r--chromium/cc/animation/scroll_timeline_unittest.cc45
-rw-r--r--chromium/cc/animation/timing_function.cc182
-rw-r--r--chromium/cc/animation/timing_function.h140
-rw-r--r--chromium/cc/animation/transform_operation.cc514
-rw-r--r--chromium/cc/animation/transform_operation.h82
-rw-r--r--chromium/cc/animation/transform_operations.cc387
-rw-r--r--chromium/cc/animation/transform_operations.h142
-rw-r--r--chromium/cc/animation/transform_operations_unittest.cc1831
-rw-r--r--chromium/cc/base/features.cc20
-rw-r--r--chromium/cc/base/features.h8
-rw-r--r--chromium/cc/base/math_util.cc71
-rw-r--r--chromium/cc/base/math_util.h14
-rw-r--r--chromium/cc/debug/layer_tree_debug_state.cc72
-rw-r--r--chromium/cc/debug/layer_tree_debug_state.h58
-rw-r--r--chromium/cc/document_transition/README.md5
-rw-r--r--chromium/cc/document_transition/document_transition_request.cc114
-rw-r--r--chromium/cc/document_transition/document_transition_request.h73
-rw-r--r--chromium/cc/document_transition/document_transition_request_unittest.cc73
-rw-r--r--chromium/cc/input/browser_controls_state.h9
-rw-r--r--chromium/cc/input/compositor_input_interfaces.h2
-rw-r--r--chromium/cc/input/input_handler.h13
-rw-r--r--chromium/cc/input/main_thread_scrolling_reason.cc10
-rw-r--r--chromium/cc/input/main_thread_scrolling_reason.h70
-rw-r--r--chromium/cc/input/main_thread_scrolling_reason_unittest.cc5
-rw-r--r--chromium/cc/input/scrollbar_controller.cc48
-rw-r--r--chromium/cc/input/scrollbar_controller.h13
-rw-r--r--chromium/cc/input/snap_selection_strategy.cc8
-rw-r--r--chromium/cc/input/threaded_input_handler.cc61
-rw-r--r--chromium/cc/input/threaded_input_handler.h4
-rw-r--r--chromium/cc/ipc/cc_param_traits_macros.h4
-rw-r--r--chromium/cc/layers/content_layer_client.h2
-rw-r--r--chromium/cc/layers/heads_up_display_layer.cc29
-rw-r--r--chromium/cc/layers/heads_up_display_layer.h6
-rw-r--r--chromium/cc/layers/heads_up_display_layer_impl.cc238
-rw-r--r--chromium/cc/layers/heads_up_display_layer_impl.h39
-rw-r--r--chromium/cc/layers/heads_up_display_unittest.cc20
-rw-r--r--chromium/cc/layers/layer.cc72
-rw-r--r--chromium/cc/layers/layer.h67
-rw-r--r--chromium/cc/layers/layer_impl.cc21
-rw-r--r--chromium/cc/layers/layer_impl.h9
-rw-r--r--chromium/cc/layers/layer_impl_unittest.cc1
-rw-r--r--chromium/cc/layers/layer_unittest.cc6
-rw-r--r--chromium/cc/layers/mirror_layer_impl.cc2
-rw-r--r--chromium/cc/layers/painted_scrollbar_layer.cc5
-rw-r--r--chromium/cc/layers/painted_scrollbar_layer_impl.cc9
-rw-r--r--chromium/cc/layers/painted_scrollbar_layer_impl.h5
-rw-r--r--chromium/cc/layers/painted_scrollbar_layer_impl_unittest.cc13
-rw-r--r--chromium/cc/layers/picture_layer_impl.cc97
-rw-r--r--chromium/cc/layers/picture_layer_impl.h4
-rw-r--r--chromium/cc/layers/picture_layer_impl_unittest.cc1016
-rw-r--r--chromium/cc/layers/picture_layer_unittest.cc3
-rw-r--r--chromium/cc/layers/render_surface_impl.cc29
-rw-r--r--chromium/cc/layers/render_surface_impl.h20
-rw-r--r--chromium/cc/layers/render_surface_impl_unittest.cc4
-rw-r--r--chromium/cc/layers/render_surface_unittest.cc5
-rw-r--r--chromium/cc/layers/texture_layer_impl.cc6
-rw-r--r--chromium/cc/layers/texture_layer_impl.h4
-rw-r--r--chromium/cc/layers/texture_layer_unittest.cc1
-rw-r--r--chromium/cc/layers/ui_resource_layer_impl.cc4
-rw-r--r--chromium/cc/layers/video_layer_impl_unittest.cc4
-rw-r--r--chromium/cc/metrics/OWNERS2
-rw-r--r--chromium/cc/metrics/compositor_frame_reporter.cc827
-rw-r--r--chromium/cc/metrics/compositor_frame_reporter.h159
-rw-r--r--chromium/cc/metrics/compositor_frame_reporter_unittest.cc301
-rw-r--r--chromium/cc/metrics/compositor_frame_reporting_controller.cc103
-rw-r--r--chromium/cc/metrics/compositor_frame_reporting_controller.h21
-rw-r--r--chromium/cc/metrics/compositor_frame_reporting_controller_unittest.cc446
-rw-r--r--chromium/cc/metrics/compositor_timing_history.cc40
-rw-r--r--chromium/cc/metrics/compositor_timing_history.h3
-rw-r--r--chromium/cc/metrics/dropped_frame_counter.cc258
-rw-r--r--chromium/cc/metrics/dropped_frame_counter.h73
-rw-r--r--chromium/cc/metrics/dropped_frame_counter_unittest.cc249
-rw-r--r--chromium/cc/metrics/event_metrics.cc143
-rw-r--r--chromium/cc/metrics/event_metrics.h84
-rw-r--r--chromium/cc/metrics/events_metrics_manager_unittest.cc80
-rw-r--r--chromium/cc/metrics/frame_sequence_metrics.cc3
-rw-r--r--chromium/cc/metrics/frame_sequence_tracker.cc20
-rw-r--r--chromium/cc/metrics/frame_sequence_tracker.h1
-rw-r--r--chromium/cc/metrics/frame_sequence_tracker_collection.cc2
-rw-r--r--chromium/cc/metrics/frame_sequence_tracker_collection.h2
-rw-r--r--chromium/cc/metrics/frame_sequence_tracker_unittest.cc85
-rw-r--r--chromium/cc/metrics/frame_sorter.cc2
-rw-r--r--chromium/cc/metrics/jank_injector.cc176
-rw-r--r--chromium/cc/metrics/jank_injector.h56
-rw-r--r--chromium/cc/metrics/jank_injector_unittest.cc61
-rw-r--r--chromium/cc/metrics/jank_metrics.cc8
-rw-r--r--chromium/cc/metrics/jank_metrics.h19
-rw-r--r--chromium/cc/metrics/jank_metrics_unittest.cc9
-rw-r--r--chromium/cc/metrics/latency_ukm_reporter.cc18
-rw-r--r--chromium/cc/metrics/latency_ukm_reporter.h11
-rw-r--r--chromium/cc/metrics/shared_metrics_buffer.h46
-rw-r--r--chromium/cc/metrics/ukm_smoothness_data.h10
-rw-r--r--chromium/cc/metrics/video_playback_roughness_reporter.cc4
-rw-r--r--chromium/cc/metrics/video_playback_roughness_reporter_unittest.cc2
-rw-r--r--chromium/cc/metrics/web_vital_metrics.cc13
-rw-r--r--chromium/cc/metrics/web_vital_metrics.h56
-rw-r--r--chromium/cc/mojo_embedder/BUILD.gn1
-rw-r--r--chromium/cc/mojo_embedder/DEPS1
-rw-r--r--chromium/cc/mojo_embedder/async_layer_tree_frame_sink.cc25
-rw-r--r--chromium/cc/mojo_embedder/async_layer_tree_frame_sink.h3
-rw-r--r--chromium/cc/mojom/BUILD.gn11
-rw-r--r--chromium/cc/mojom/browser_controls_state.mojom8
-rw-r--r--chromium/cc/mojom/render_frame_metadata.mojom22
-rw-r--r--chromium/cc/mojom/render_frame_metadata_mojom_traits.cc11
-rw-r--r--chromium/cc/mojom/render_frame_metadata_mojom_traits.h17
-rw-r--r--chromium/cc/paint/decoded_draw_image.cc22
-rw-r--r--chromium/cc/paint/decoded_draw_image.h8
-rw-r--r--chromium/cc/paint/discardable_image_map.cc11
-rw-r--r--chromium/cc/paint/discardable_image_map_unittest.cc121
-rw-r--r--chromium/cc/paint/display_item_list.cc30
-rw-r--r--chromium/cc/paint/display_item_list_unittest.cc12
-rw-r--r--chromium/cc/paint/filter_operation.cc2
-rw-r--r--chromium/cc/paint/filter_operation.h15
-rw-r--r--chromium/cc/paint/filter_operations_unittest.cc23
-rw-r--r--chromium/cc/paint/frame_metadata.h2
-rw-r--r--chromium/cc/paint/image_provider.h8
-rw-r--r--chromium/cc/paint/image_transfer_cache_entry.cc167
-rw-r--r--chromium/cc/paint/image_transfer_cache_entry.h23
-rw-r--r--chromium/cc/paint/image_transfer_cache_entry_unittest.cc92
-rw-r--r--chromium/cc/paint/oop_pixeltest.cc142
-rw-r--r--chromium/cc/paint/paint_canvas.h14
-rw-r--r--chromium/cc/paint/paint_filter.cc140
-rw-r--r--chromium/cc/paint/paint_filter.h53
-rw-r--r--chromium/cc/paint/paint_filter_unittest.cc21
-rw-r--r--chromium/cc/paint/paint_image.cc5
-rw-r--r--chromium/cc/paint/paint_image.h21
-rw-r--r--chromium/cc/paint/paint_image_builder.cc1
-rw-r--r--chromium/cc/paint/paint_image_unittest.cc3
-rw-r--r--chromium/cc/paint/paint_op_buffer.cc190
-rw-r--r--chromium/cc/paint/paint_op_buffer.h50
-rw-r--r--chromium/cc/paint/paint_op_buffer_fuzzer.cc2
-rw-r--r--chromium/cc/paint/paint_op_buffer_serializer.cc7
-rw-r--r--chromium/cc/paint/paint_op_buffer_unittest.cc274
-rw-r--r--chromium/cc/paint/paint_op_helper_unittest.cc18
-rw-r--r--chromium/cc/paint/paint_op_perftest.cc3
-rw-r--r--chromium/cc/paint/paint_op_reader.cc197
-rw-r--r--chromium/cc/paint/paint_op_reader.h63
-rw-r--r--chromium/cc/paint/paint_op_writer.cc66
-rw-r--r--chromium/cc/paint/paint_op_writer.h34
-rw-r--r--chromium/cc/paint/paint_shader_unittest.cc4
-rw-r--r--chromium/cc/paint/paint_worklet_input.cc46
-rw-r--r--chromium/cc/paint/paint_worklet_input.h37
-rw-r--r--chromium/cc/paint/paint_worklet_input_unittest.cc24
-rw-r--r--chromium/cc/paint/paint_worklet_job.h5
-rw-r--r--chromium/cc/paint/record_paint_canvas.cc18
-rw-r--r--chromium/cc/paint/record_paint_canvas.h6
-rw-r--r--chromium/cc/paint/render_surface_filters.cc9
-rw-r--r--chromium/cc/paint/scoped_raster_flags_unittest.cc10
-rw-r--r--chromium/cc/paint/skia_paint_canvas.cc21
-rw-r--r--chromium/cc/paint/skia_paint_canvas.h4
-rw-r--r--chromium/cc/paint/solid_color_analyzer.cc40
-rw-r--r--chromium/cc/paint/transfer_cache_deserialize_helper.h4
-rw-r--r--chromium/cc/paint/transfer_cache_entry.h4
-rw-r--r--chromium/cc/raster/bitmap_raster_buffer_provider.cc4
-rw-r--r--chromium/cc/raster/bitmap_raster_buffer_provider.h1
-rw-r--r--chromium/cc/raster/gpu_raster_buffer_provider.cc236
-rw-r--r--chromium/cc/raster/gpu_raster_buffer_provider.h32
-rw-r--r--chromium/cc/raster/one_copy_raster_buffer_provider.cc4
-rw-r--r--chromium/cc/raster/one_copy_raster_buffer_provider.h1
-rw-r--r--chromium/cc/raster/playback_image_provider.cc7
-rw-r--r--chromium/cc/raster/playback_image_provider_unittest.cc3
-rw-r--r--chromium/cc/raster/raster_buffer_provider.cc4
-rw-r--r--chromium/cc/raster/raster_buffer_provider.h8
-rw-r--r--chromium/cc/raster/raster_buffer_provider_perftest.cc8
-rw-r--r--chromium/cc/raster/raster_buffer_provider_unittest.cc15
-rw-r--r--chromium/cc/raster/raster_query_queue.cc145
-rw-r--r--chromium/cc/raster/raster_query_queue.h69
-rw-r--r--chromium/cc/raster/raster_source.cc7
-rw-r--r--chromium/cc/raster/raster_source.h4
-rw-r--r--chromium/cc/raster/task_graph_work_queue.cc2
-rw-r--r--chromium/cc/raster/zero_copy_raster_buffer_provider.cc4
-rw-r--r--chromium/cc/raster/zero_copy_raster_buffer_provider.h1
-rw-r--r--chromium/cc/resources/resource_pool.cc6
-rw-r--r--chromium/cc/resources/resource_pool.h3
-rw-r--r--chromium/cc/resources/ui_resource_bitmap.cc3
-rw-r--r--chromium/cc/scheduler/begin_frame_tracker.cc8
-rw-r--r--chromium/cc/scheduler/scheduler.cc11
-rw-r--r--chromium/cc/scheduler/scheduler_unittest.cc4
-rw-r--r--chromium/cc/tiles/gpu_image_decode_cache.cc325
-rw-r--r--chromium/cc/tiles/gpu_image_decode_cache.h24
-rw-r--r--chromium/cc/tiles/gpu_image_decode_cache_perftest.cc10
-rw-r--r--chromium/cc/tiles/gpu_image_decode_cache_unittest.cc27
-rw-r--r--chromium/cc/tiles/image_decode_cache_utils.cc5
-rw-r--r--chromium/cc/tiles/picture_layer_tiling.cc9
-rw-r--r--chromium/cc/tiles/picture_layer_tiling_set.cc1
-rw-r--r--chromium/cc/tiles/software_image_decode_cache.cc7
-rw-r--r--chromium/cc/tiles/software_image_decode_cache_utils.cc5
-rw-r--r--chromium/cc/tiles/tile_manager.cc25
-rw-r--r--chromium/cc/tiles/tile_manager.h10
-rw-r--r--chromium/cc/tiles/tile_manager_unittest.cc21
-rw-r--r--chromium/cc/trees/animated_paint_worklet_tracker.cc21
-rw-r--r--chromium/cc/trees/animated_paint_worklet_tracker.h7
-rw-r--r--chromium/cc/trees/compositor_commit_data.cc10
-rw-r--r--chromium/cc/trees/compositor_commit_data.h18
-rw-r--r--chromium/cc/trees/damage_tracker.cc99
-rw-r--r--chromium/cc/trees/damage_tracker.h21
-rw-r--r--chromium/cc/trees/damage_tracker_unittest.cc103
-rw-r--r--chromium/cc/trees/draw_properties_unittest.cc512
-rw-r--r--chromium/cc/trees/draw_property_utils.cc28
-rw-r--r--chromium/cc/trees/effect_node.cc15
-rw-r--r--chromium/cc/trees/effect_node.h5
-rw-r--r--chromium/cc/trees/image_animation_controller.cc185
-rw-r--r--chromium/cc/trees/image_animation_controller.h59
-rw-r--r--chromium/cc/trees/layer_tree_host.cc122
-rw-r--r--chromium/cc/trees/layer_tree_host.h69
-rw-r--r--chromium/cc/trees/layer_tree_host_client.cc15
-rw-r--r--chromium/cc/trees/layer_tree_host_client.h22
-rw-r--r--chromium/cc/trees/layer_tree_host_impl.cc183
-rw-r--r--chromium/cc/trees/layer_tree_host_impl.h52
-rw-r--r--chromium/cc/trees/layer_tree_host_impl_unittest.cc220
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_blending.cc5
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_filters.cc41
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_masks.cc16
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc18
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc13
-rw-r--r--chromium/cc/trees/layer_tree_host_single_thread_client.h8
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest.cc136
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_animation.cc70
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_capture.cc143
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_capture_content.cc3
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_checkerimaging.cc2
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_context.cc71
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_scroll.cc11
-rw-r--r--chromium/cc/trees/layer_tree_impl.cc37
-rw-r--r--chromium/cc/trees/layer_tree_impl.h21
-rw-r--r--chromium/cc/trees/layer_tree_impl_unittest.cc2
-rw-r--r--chromium/cc/trees/layer_tree_settings.h9
-rw-r--r--chromium/cc/trees/mutator_host.h28
-rw-r--r--chromium/cc/trees/mutator_host_client.h12
-rw-r--r--chromium/cc/trees/occlusion_tracker.cc4
-rw-r--r--chromium/cc/trees/property_animation_state.cc2
-rw-r--r--chromium/cc/trees/property_animation_state.h5
-rw-r--r--chromium/cc/trees/property_tree.cc234
-rw-r--r--chromium/cc/trees/property_tree.h80
-rw-r--r--chromium/cc/trees/property_tree_builder.cc26
-rw-r--r--chromium/cc/trees/property_tree_builder_unittest.cc8
-rw-r--r--chromium/cc/trees/proxy.h2
-rw-r--r--chromium/cc/trees/proxy_impl.cc26
-rw-r--r--chromium/cc/trees/proxy_impl.h12
-rw-r--r--chromium/cc/trees/proxy_main.cc4
-rw-r--r--chromium/cc/trees/proxy_main.h4
-rw-r--r--chromium/cc/trees/render_frame_metadata.cc1
-rw-r--r--chromium/cc/trees/render_frame_metadata.h35
-rw-r--r--chromium/cc/trees/single_thread_proxy.cc51
-rw-r--r--chromium/cc/trees/single_thread_proxy.h7
-rw-r--r--chromium/cc/trees/target_property.cc7
-rw-r--r--chromium/cc/trees/target_property.h10
-rw-r--r--chromium/cc/trees/throttle_decider.cc92
-rw-r--r--chromium/cc/trees/throttle_decider.h48
-rw-r--r--chromium/cc/trees/throttle_decider_unittest.cc111
-rw-r--r--chromium/cc/trees/transform_node.cc4
-rw-r--r--chromium/cc/trees/transform_node.h6
-rw-r--r--chromium/cc/trees/tree_synchronizer.cc2
-rw-r--r--chromium/cc/trees/tree_synchronizer_unittest.cc34
-rw-r--r--chromium/cc/trees/ukm_manager.cc304
-rw-r--r--chromium/cc/trees/ukm_manager.h11
-rw-r--r--chromium/cc/trees/ukm_manager_unittest.cc510
291 files changed, 10331 insertions, 11194 deletions
diff --git a/chromium/cc/BUILD.gn b/chromium/cc/BUILD.gn
index 3bb5e558302..3465bf70b6c 100644
--- a/chromium/cc/BUILD.gn
+++ b/chromium/cc/BUILD.gn
@@ -7,6 +7,10 @@ import("//skia/features.gni")
import("//cc/cc.gni")
+if (is_android) {
+ import("//build/config/android/rules.gni")
+}
+
cc_component("cc") {
sources = [
"benchmarks/benchmark_instrumentation.cc",
@@ -29,10 +33,13 @@ cc_component("cc") {
"benchmarks/unittest_only_benchmark.h",
"benchmarks/unittest_only_benchmark_impl.cc",
"benchmarks/unittest_only_benchmark_impl.h",
+ "document_transition/document_transition_request.cc",
+ "document_transition/document_transition_request.h",
"input/actively_scrolling_type.h",
"input/browser_controls_offset_manager.cc",
"input/browser_controls_offset_manager.h",
"input/browser_controls_offset_manager_client.h",
+ "input/browser_controls_state.h",
"input/compositor_input_interfaces.h",
"input/input_handler.h",
"input/layer_selection_bound.cc",
@@ -179,12 +186,15 @@ cc_component("cc") {
"metrics/frame_sequence_tracker_collection.h",
"metrics/frame_sorter.cc",
"metrics/frame_sorter.h",
+ "metrics/jank_injector.cc",
+ "metrics/jank_injector.h",
"metrics/jank_metrics.cc",
"metrics/jank_metrics.h",
"metrics/latency_ukm_reporter.cc",
"metrics/latency_ukm_reporter.h",
"metrics/lcd_text_metrics_reporter.cc",
"metrics/lcd_text_metrics_reporter.h",
+ "metrics/shared_metrics_buffer.h",
"metrics/throughput_ukm_reporter.cc",
"metrics/throughput_ukm_reporter.h",
"metrics/total_frame_counter.cc",
@@ -192,6 +202,8 @@ cc_component("cc") {
"metrics/ukm_smoothness_data.h",
"metrics/video_playback_roughness_reporter.cc",
"metrics/video_playback_roughness_reporter.h",
+ "metrics/web_vital_metrics.cc",
+ "metrics/web_vital_metrics.h",
"raster/bitmap_raster_buffer_provider.cc",
"raster/bitmap_raster_buffer_provider.h",
"raster/gpu_raster_buffer_provider.cc",
@@ -208,6 +220,8 @@ cc_component("cc") {
"raster/raster_buffer.h",
"raster/raster_buffer_provider.cc",
"raster/raster_buffer_provider.h",
+ "raster/raster_query_queue.cc",
+ "raster/raster_query_queue.h",
"raster/raster_source.cc",
"raster/raster_source.h",
"raster/scoped_gpu_raster.cc",
@@ -398,6 +412,8 @@ cc_component("cc") {
"trees/target_property.h",
"trees/task_runner_provider.cc",
"trees/task_runner_provider.h",
+ "trees/throttle_decider.cc",
+ "trees/throttle_decider.h",
"trees/transform_node.cc",
"trees/transform_node.h",
"trees/tree_synchronizer.cc",
@@ -432,6 +448,7 @@ cc_component("cc") {
"//services/tracing/public/cpp:cpp",
"//ui/events:events_base",
"//ui/gfx",
+ "//ui/gfx/animation/keyframe",
"//ui/gfx/geometry",
"//ui/gl",
"//ui/latency",
@@ -482,6 +499,8 @@ cc_test_static_library("test_support") {
"test/fake_proxy.h",
"test/fake_raster_buffer_provider.cc",
"test/fake_raster_buffer_provider.h",
+ "test/fake_raster_query_queue.cc",
+ "test/fake_raster_query_queue.h",
"test/fake_raster_source.cc",
"test/fake_raster_source.h",
"test/fake_recording_source.cc",
@@ -501,7 +520,6 @@ cc_test_static_library("test_support") {
"test/fake_ui_resource_layer_tree_host_impl.h",
"test/fake_video_frame_provider.cc",
"test/fake_video_frame_provider.h",
- "test/geometry_test_utils.cc",
"test/geometry_test_utils.h",
"test/layer_test_common.cc",
"test/layer_test_common.h",
@@ -612,6 +630,7 @@ cc_test_static_library("test_support") {
"//ui/base:features",
"//ui/gfx",
"//ui/gfx:test_support",
+ "//ui/gfx/animation/keyframe",
"//ui/gfx/geometry",
"//ui/gl",
"//ui/gl:test_support",
@@ -644,6 +663,7 @@ cc_test("cc_unittests") {
"base/unique_notifier_unittest.cc",
"benchmarks/micro_benchmark_controller_unittest.cc",
"debug/rendering_stats_unittest.cc",
+ "document_transition/document_transition_request_unittest.cc",
"input/browser_controls_offset_manager_unittest.cc",
"input/main_thread_scrolling_reason_unittest.cc",
"input/scroll_snap_data_unittest.cc",
@@ -693,6 +713,7 @@ cc_test("cc_unittests") {
"metrics/frame_sequence_metrics_unittest.cc",
"metrics/frame_sequence_tracker_unittest.cc",
"metrics/frame_sorter_unittest.cc",
+ "metrics/jank_injector_unittest.cc",
"metrics/jank_metrics_unittest.cc",
"metrics/total_frame_counter_unittest.cc",
"metrics/video_playback_roughness_reporter_unittest.cc",
@@ -709,6 +730,7 @@ cc_test("cc_unittests") {
"paint/paint_op_buffer_unittest.cc",
"paint/paint_op_helper_unittest.cc",
"paint/paint_shader_unittest.cc",
+ "paint/paint_worklet_input_unittest.cc",
"paint/scoped_raster_flags_unittest.cc",
"paint/skia_paint_canvas_unittest.cc",
"paint/solid_color_analyzer_unittest.cc",
@@ -752,6 +774,7 @@ cc_test("cc_unittests") {
"trees/layer_tree_host_pixeltest_tiles.cc",
"trees/layer_tree_host_unittest.cc",
"trees/layer_tree_host_unittest_animation.cc",
+ "trees/layer_tree_host_unittest_capture.cc",
"trees/layer_tree_host_unittest_capture_content.cc",
"trees/layer_tree_host_unittest_checkerimaging.cc",
"trees/layer_tree_host_unittest_context.cc",
@@ -771,6 +794,7 @@ cc_test("cc_unittests") {
"trees/property_tree_builder_unittest.cc",
"trees/property_tree_unittest.cc",
"trees/swap_promise_manager_unittest.cc",
+ "trees/throttle_decider_unittest.cc",
"trees/tree_synchronizer_unittest.cc",
"trees/ukm_manager_unittest.cc",
@@ -779,11 +803,10 @@ cc_test("cc_unittests") {
"animation/animation_timeline_unittest.cc",
"animation/animation_unittest.cc",
"animation/element_animations_unittest.cc",
+ "animation/filter_animation_curve_unittest.cc",
"animation/keyframe_model_unittest.cc",
- "animation/keyframed_animation_curve_unittest.cc",
"animation/scroll_offset_animation_curve_unittest.cc",
"animation/scroll_timeline_unittest.cc",
- "animation/transform_operations_unittest.cc",
"animation/worklet_animation_unittest.cc",
# Setup.
@@ -826,6 +849,7 @@ cc_test("cc_unittests") {
"//ui/events:events_base",
"//ui/gfx",
"//ui/gfx:test_support",
+ "//ui/gfx/animation/keyframe",
"//ui/gfx/geometry",
"//ui/gl",
"//ui/gl:test_support",
@@ -906,3 +930,19 @@ cc_test("cc_perftests") {
"//testing:run_perf_test",
]
}
+
+if (is_android) {
+ java_cpp_enum("cc_android_java_enums_srcjar") {
+ sources = [ "//cc/input/browser_controls_state.h" ]
+ }
+
+ android_library("cc_java") {
+ # Right now, this only includes the Java switches. But if we need more Java
+ # files, they should be added here as necessary.
+ srcjar_deps = [ ":cc_android_java_enums_srcjar" ]
+ deps = [
+ "//base:base_java",
+ "//third_party/androidx:androidx_annotation_annotation_java",
+ ]
+ }
+}
diff --git a/chromium/cc/OWNERS b/chromium/cc/OWNERS
index 2f29787e102..6b427ed86d7 100644
--- a/chromium/cc/OWNERS
+++ b/chromium/cc/OWNERS
@@ -5,6 +5,7 @@
# Folks listed as unofficial can't do OWNERS approvals but are good people to
# ask for informal reviews.
+set noparent
# layers
danakj@chromium.org
pdr@chromium.org
@@ -36,7 +37,6 @@ flackr@chromium.org
smcgruer@chromium.org
# images
-khushalsagar@chromium.org
vmpstr@chromium.org
# surfaces
@@ -52,6 +52,10 @@ majidvp@chromium.org
# metrics
sadrul@chromium.org
+# paint
+sunnyps@chromium.org
+vasilyt@chromium.org
+
# general
danakj@chromium.org
vmpstr@chromium.org
diff --git a/chromium/cc/animation/BUILD.gn b/chromium/cc/animation/BUILD.gn
index 5bd47e62e5d..466d3f125da 100644
--- a/chromium/cc/animation/BUILD.gn
+++ b/chromium/cc/animation/BUILD.gn
@@ -9,8 +9,6 @@ cc_component("animation") {
sources = [
"animation.cc",
"animation.h",
- "animation_curve.cc",
- "animation_curve.h",
"animation_delegate.h",
"animation_events.cc",
"animation_events.h",
@@ -19,17 +17,16 @@ cc_component("animation") {
"animation_host.h",
"animation_id_provider.cc",
"animation_id_provider.h",
- "animation_target.h",
"animation_timeline.cc",
"animation_timeline.h",
"element_animations.cc",
"element_animations.h",
+ "filter_animation_curve.cc",
+ "filter_animation_curve.h",
"keyframe_effect.cc",
"keyframe_effect.h",
"keyframe_model.cc",
"keyframe_model.h",
- "keyframed_animation_curve.cc",
- "keyframed_animation_curve.h",
"scroll_offset_animation_curve.cc",
"scroll_offset_animation_curve.h",
"scroll_offset_animation_curve_factory.cc",
@@ -40,12 +37,6 @@ cc_component("animation") {
"scroll_offset_animations_impl.h",
"scroll_timeline.cc",
"scroll_timeline.h",
- "timing_function.cc",
- "timing_function.h",
- "transform_operation.cc",
- "transform_operation.h",
- "transform_operations.cc",
- "transform_operations.h",
"worklet_animation.cc",
"worklet_animation.h",
]
@@ -57,6 +48,7 @@ cc_component("animation") {
"//cc",
"//cc/paint",
"//ui/gfx",
+ "//ui/gfx/animation/keyframe",
"//ui/gfx/geometry",
]
}
diff --git a/chromium/cc/animation/animation.cc b/chromium/cc/animation/animation.cc
index 718e1f7f670..0b8d96cd812 100644
--- a/chromium/cc/animation/animation.cc
+++ b/chromium/cc/animation/animation.cc
@@ -6,6 +6,8 @@
#include <inttypes.h>
#include <algorithm>
+#include <string>
+#include <utility>
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
@@ -16,7 +18,6 @@
#include "cc/animation/keyframe_effect.h"
#include "cc/animation/scroll_offset_animation_curve.h"
#include "cc/animation/scroll_timeline.h"
-#include "cc/animation/transform_operations.h"
#include "cc/trees/property_animation_state.h"
namespace cc {
diff --git a/chromium/cc/animation/animation.h b/chromium/cc/animation/animation.h
index 8eba000f62e..90ade7a56a1 100644
--- a/chromium/cc/animation/animation.h
+++ b/chromium/cc/animation/animation.h
@@ -5,16 +5,17 @@
#ifndef CC_ANIMATION_ANIMATION_H_
#define CC_ANIMATION_ANIMATION_H_
+#include <memory>
+#include <string>
#include <vector>
-#include <memory>
#include "base/memory/ref_counted.h"
#include "base/time/time.h"
-#include "cc/animation/animation_curve.h"
#include "cc/animation/animation_export.h"
#include "cc/animation/element_animations.h"
#include "cc/animation/keyframe_model.h"
#include "cc/paint/element_id.h"
+#include "ui/gfx/animation/keyframe/animation_curve.h"
namespace cc {
diff --git a/chromium/cc/animation/animation_curve.cc b/chromium/cc/animation/animation_curve.cc
deleted file mode 100644
index 1a46580f534..00000000000
--- a/chromium/cc/animation/animation_curve.cc
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2012 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/animation/animation_curve.h"
-
-#include "base/check.h"
-#include "cc/animation/scroll_offset_animation_curve.h"
-
-namespace cc {
-
-const ColorAnimationCurve* AnimationCurve::ToColorAnimationCurve() const {
- DCHECK(Type() == AnimationCurve::COLOR);
- return static_cast<const ColorAnimationCurve*>(this);
-}
-
-AnimationCurve::CurveType ColorAnimationCurve::Type() const {
- return COLOR;
-}
-
-const FloatAnimationCurve* AnimationCurve::ToFloatAnimationCurve() const {
- DCHECK(Type() == AnimationCurve::FLOAT);
- return static_cast<const FloatAnimationCurve*>(this);
-}
-
-AnimationCurve::CurveType FloatAnimationCurve::Type() const {
- return FLOAT;
-}
-
-const TransformAnimationCurve* AnimationCurve::ToTransformAnimationCurve()
- const {
- DCHECK(Type() == AnimationCurve::TRANSFORM);
- return static_cast<const TransformAnimationCurve*>(this);
-}
-
-AnimationCurve::CurveType TransformAnimationCurve::Type() const {
- return TRANSFORM;
-}
-
-const FilterAnimationCurve* AnimationCurve::ToFilterAnimationCurve() const {
- DCHECK(Type() == AnimationCurve::FILTER);
- return static_cast<const FilterAnimationCurve*>(this);
-}
-
-AnimationCurve::CurveType FilterAnimationCurve::Type() const {
- return FILTER;
-}
-
-const ScrollOffsetAnimationCurve* AnimationCurve::ToScrollOffsetAnimationCurve()
- const {
- DCHECK(Type() == AnimationCurve::SCROLL_OFFSET);
- return static_cast<const ScrollOffsetAnimationCurve*>(this);
-}
-
-ScrollOffsetAnimationCurve* AnimationCurve::ToScrollOffsetAnimationCurve() {
- DCHECK(Type() == AnimationCurve::SCROLL_OFFSET);
- return static_cast<ScrollOffsetAnimationCurve*>(this);
-}
-
-const SizeAnimationCurve* AnimationCurve::ToSizeAnimationCurve() const {
- DCHECK(Type() == AnimationCurve::SIZE);
- return static_cast<const SizeAnimationCurve*>(this);
-}
-
-AnimationCurve::CurveType SizeAnimationCurve::Type() const {
- return SIZE;
-}
-
-} // namespace cc
diff --git a/chromium/cc/animation/animation_curve.h b/chromium/cc/animation/animation_curve.h
deleted file mode 100644
index 34979f7b57c..00000000000
--- a/chromium/cc/animation/animation_curve.h
+++ /dev/null
@@ -1,122 +0,0 @@
-// Copyright 2012 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_ANIMATION_ANIMATION_CURVE_H_
-#define CC_ANIMATION_ANIMATION_CURVE_H_
-
-#include <memory>
-
-#include "base/time/time.h"
-#include "cc/animation/animation_export.h"
-#include "cc/paint/filter_operations.h"
-#include "ui/gfx/geometry/size_f.h"
-#include "ui/gfx/transform.h"
-
-namespace cc {
-
-class ColorAnimationCurve;
-class FilterAnimationCurve;
-class FloatAnimationCurve;
-class ScrollOffsetAnimationCurve;
-class SizeAnimationCurve;
-class TransformAnimationCurve;
-class TransformOperations;
-
-// An animation curve is a function that returns a value given a time.
-class CC_ANIMATION_EXPORT AnimationCurve {
- public:
- enum CurveType {
- COLOR = 0,
- FLOAT,
- TRANSFORM,
- FILTER,
- SCROLL_OFFSET,
- SIZE,
- // This must be last
- LAST_CURVE_TYPE = SIZE,
- };
-
- virtual ~AnimationCurve() {}
-
- virtual base::TimeDelta Duration() const = 0;
- virtual CurveType Type() const = 0;
- virtual std::unique_ptr<AnimationCurve> Clone() const = 0;
-
- const ColorAnimationCurve* ToColorAnimationCurve() const;
- const FloatAnimationCurve* ToFloatAnimationCurve() const;
- const TransformAnimationCurve* ToTransformAnimationCurve() const;
- const FilterAnimationCurve* ToFilterAnimationCurve() const;
- const ScrollOffsetAnimationCurve* ToScrollOffsetAnimationCurve() const;
- const SizeAnimationCurve* ToSizeAnimationCurve() const;
-
- ScrollOffsetAnimationCurve* ToScrollOffsetAnimationCurve();
-};
-
-class CC_ANIMATION_EXPORT ColorAnimationCurve : public AnimationCurve {
- public:
- ~ColorAnimationCurve() override {}
-
- virtual SkColor GetValue(base::TimeDelta t) const = 0;
-
- CurveType Type() const override;
-};
-
-class CC_ANIMATION_EXPORT FloatAnimationCurve : public AnimationCurve {
- public:
- ~FloatAnimationCurve() override {}
-
- virtual float GetValue(base::TimeDelta t) const = 0;
-
- CurveType Type() const override;
-};
-
-class CC_ANIMATION_EXPORT TransformAnimationCurve : public AnimationCurve {
- public:
- ~TransformAnimationCurve() override {}
-
- virtual TransformOperations GetValue(base::TimeDelta t) const = 0;
-
- // Returns true if this animation is a translation.
- virtual bool IsTranslation() const = 0;
-
- // Returns true if this animation preserves axis alignment.
- virtual bool PreservesAxisAlignment() const = 0;
-
- // Animation start scale
- virtual bool AnimationStartScale(bool forward_direction,
- float* start_scale) const = 0;
-
- // Set |max_scale| to the maximum scale along any dimension at the end of
- // intermediate animation target points (eg keyframe end points). When
- // |forward_direction| is true, the animation curve assumes it plays from
- // the first keyframe to the last, otherwise it assumes the opposite. Returns
- // false if the maximum scale cannot be computed.
- virtual bool MaximumTargetScale(bool forward_direction,
- float* max_scale) const = 0;
-
- CurveType Type() const override;
-};
-
-class CC_ANIMATION_EXPORT FilterAnimationCurve : public AnimationCurve {
- public:
- ~FilterAnimationCurve() override {}
-
- virtual FilterOperations GetValue(base::TimeDelta t) const = 0;
- virtual bool HasFilterThatMovesPixels() const = 0;
-
- CurveType Type() const override;
-};
-
-class CC_ANIMATION_EXPORT SizeAnimationCurve : public AnimationCurve {
- public:
- ~SizeAnimationCurve() override {}
-
- virtual gfx::SizeF GetValue(base::TimeDelta t) const = 0;
-
- CurveType Type() const override;
-};
-
-} // namespace cc
-
-#endif // CC_ANIMATION_ANIMATION_CURVE_H_
diff --git a/chromium/cc/animation/animation_delegate.h b/chromium/cc/animation/animation_delegate.h
index 6931c8b0d18..0fea0dfeead 100644
--- a/chromium/cc/animation/animation_delegate.h
+++ b/chromium/cc/animation/animation_delegate.h
@@ -5,9 +5,11 @@
#ifndef CC_ANIMATION_ANIMATION_DELEGATE_H_
#define CC_ANIMATION_ANIMATION_DELEGATE_H_
+#include <memory>
+
#include "base/time/time.h"
-#include "cc/animation/animation_curve.h"
-#include "cc/animation/keyframe_model.h"
+#include "cc/animation/animation_export.h"
+#include "ui/gfx/animation/keyframe/animation_curve.h"
namespace cc {
@@ -28,7 +30,7 @@ class CC_ANIMATION_EXPORT AnimationDelegate {
base::TimeTicks monotonic_time,
int target_property,
base::TimeTicks animation_start_time,
- std::unique_ptr<AnimationCurve> curve) = 0;
+ std::unique_ptr<gfx::AnimationCurve> curve) = 0;
virtual void NotifyLocalTimeUpdated(
base::Optional<base::TimeDelta> local_time) = 0;
diff --git a/chromium/cc/animation/animation_events.h b/chromium/cc/animation/animation_events.h
index 3c060e275eb..7fc3703307b 100644
--- a/chromium/cc/animation/animation_events.h
+++ b/chromium/cc/animation/animation_events.h
@@ -8,9 +8,9 @@
#include <memory>
#include <vector>
-#include "cc/animation/animation_curve.h"
#include "cc/animation/animation_export.h"
#include "cc/trees/mutator_host.h"
+#include "ui/gfx/animation/keyframe/animation_curve.h"
namespace cc {
@@ -51,7 +51,7 @@ struct CC_ANIMATION_EXPORT AnimationEvent {
// For continuing a scroll offset animation on the main thread.
base::TimeTicks animation_start_time;
- std::unique_ptr<AnimationCurve> curve;
+ std::unique_ptr<gfx::AnimationCurve> curve;
// Set for TIME_UPDATED events.
base::Optional<base::TimeDelta> local_time;
diff --git a/chromium/cc/animation/animation_host.cc b/chromium/cc/animation/animation_host.cc
index 137ee986394..d1daa0ef2d2 100644
--- a/chromium/cc/animation/animation_host.cc
+++ b/chromium/cc/animation/animation_host.cc
@@ -10,8 +10,8 @@
#include "base/bind.h"
#include "base/callback.h"
+#include "base/containers/contains.h"
#include "base/memory/ptr_util.h"
-#include "base/stl_util.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/traced_value.h"
#include "cc/animation/animation.h"
@@ -20,12 +20,13 @@
#include "cc/animation/animation_id_provider.h"
#include "cc/animation/animation_timeline.h"
#include "cc/animation/element_animations.h"
+#include "cc/animation/keyframe_effect.h"
#include "cc/animation/scroll_offset_animation_curve.h"
#include "cc/animation/scroll_offset_animations.h"
#include "cc/animation/scroll_offset_animations_impl.h"
#include "cc/animation/scroll_timeline.h"
-#include "cc/animation/timing_function.h"
#include "cc/animation/worklet_animation.h"
+#include "ui/gfx/animation/keyframe/timing_function.h"
#include "ui/gfx/geometry/box_f.h"
#include "ui/gfx/geometry/scroll_offset.h"
@@ -57,16 +58,12 @@ std::unique_ptr<AnimationHost> AnimationHost::CreateForTesting(
ThreadInstance thread_instance) {
auto animation_host = base::WrapUnique(new AnimationHost(thread_instance));
- if (thread_instance == ThreadInstance::IMPL)
- animation_host->SetSupportsScrollAnimations(true);
-
return animation_host;
}
AnimationHost::AnimationHost(ThreadInstance thread_instance)
: mutator_host_client_(nullptr),
thread_instance_(thread_instance),
- supports_scroll_animations_(false),
needs_push_properties_(false),
mutator_(nullptr) {
if (thread_instance_ == ThreadInstance::IMPL) {
@@ -85,13 +82,10 @@ AnimationHost::~AnimationHost() {
DCHECK(element_to_animations_map_.empty());
}
-std::unique_ptr<MutatorHost> AnimationHost::CreateImplInstance(
- bool supports_impl_scrolling) const {
+std::unique_ptr<MutatorHost> AnimationHost::CreateImplInstance() const {
DCHECK_EQ(thread_instance_, ThreadInstance::MAIN);
-
auto mutator_host_impl =
base::WrapUnique<MutatorHost>(new AnimationHost(ThreadInstance::IMPL));
- mutator_host_impl->SetSupportsScrollAnimations(supports_impl_scrolling);
return mutator_host_impl;
}
@@ -106,6 +100,20 @@ void AnimationHost::ClearMutators() {
id_to_timeline_map_.clear();
}
+base::TimeDelta AnimationHost::MinimumTickInterval() const {
+ base::TimeDelta min_interval = base::TimeDelta::Max();
+ for (const auto& animation : ticking_animations_) {
+ DCHECK(animation->keyframe_effect());
+ base::TimeDelta interval =
+ animation->keyframe_effect()->MinimumTickInterval();
+ if (interval.is_zero())
+ return interval;
+ if (interval < min_interval)
+ min_interval = interval;
+ }
+ return min_interval;
+}
+
void AnimationHost::EraseTimeline(scoped_refptr<AnimationTimeline> timeline) {
timeline->ClearAnimations();
timeline->SetAnimationHost(nullptr);
@@ -146,7 +154,7 @@ void AnimationHost::SetHasInlineStyleMutation(bool has_inline_style_mutation) {
void AnimationHost::UpdateRegisteredElementIds(ElementListType changed_list) {
for (auto map_entry : element_to_animations_map_) {
- // kReservedElementId is reserved for an paint worklet element that animates
+ // kReservedElementId is reserved for a paint worklet element that animates
// a custom property. This element is assumed to always be present as no
// element is needed to tick this animation.
if (mutator_host_client()->IsElementInPropertyTrees(map_entry.first,
@@ -339,20 +347,11 @@ AnimationHost::GetElementAnimationsForElementId(ElementId element_id) const {
return iter == element_to_animations_map_.end() ? nullptr : iter->second;
}
-void AnimationHost::SetSupportsScrollAnimations(
- bool supports_scroll_animations) {
- supports_scroll_animations_ = supports_scroll_animations;
-}
-
void AnimationHost::SetScrollAnimationDurationForTesting(
base::TimeDelta duration) {
ScrollOffsetAnimationCurve::SetAnimationDurationForTesting(duration);
}
-bool AnimationHost::SupportsScrollAnimations() const {
- return supports_scroll_animations_;
-}
-
bool AnimationHost::NeedsTickAnimations() const {
return !ticking_animations_.empty();
}
@@ -646,17 +645,11 @@ bool AnimationHost::AnimationsPreserveAxisAlignment(
: true;
}
-void AnimationHost::GetAnimationScales(ElementId element_id,
- ElementListType list_type,
- float* maximum_scale,
- float* starting_scale) const {
- if (auto element_animations = GetElementAnimationsForElementId(element_id)) {
- element_animations->GetAnimationScales(list_type, maximum_scale,
- starting_scale);
- return;
- }
- *maximum_scale = kNotScaled;
- *starting_scale = kNotScaled;
+float AnimationHost::MaximumScale(ElementId element_id,
+ ElementListType list_type) const {
+ if (auto element_animations = GetElementAnimationsForElementId(element_id))
+ return element_animations->MaximumScale(list_type);
+ return kInvalidScale;
}
bool AnimationHost::IsElementAnimating(ElementId element_id) const {
diff --git a/chromium/cc/animation/animation_host.h b/chromium/cc/animation/animation_host.h
index feb5e947b0a..e9a7e098bd6 100644
--- a/chromium/cc/animation/animation_host.h
+++ b/chromium/cc/animation/animation_host.h
@@ -82,12 +82,10 @@ class CC_ANIMATION_EXPORT AnimationHost : public MutatorHost,
void SetNeedsPushProperties();
bool needs_push_properties() const { return needs_push_properties_; }
- bool SupportsScrollAnimations() const;
-
// MutatorHost implementation.
- std::unique_ptr<MutatorHost> CreateImplInstance(
- bool supports_impl_scrolling) const override;
+ std::unique_ptr<MutatorHost> CreateImplInstance() const override;
void ClearMutators() override;
+ base::TimeDelta MinimumTickInterval() const override;
// Processes the current |element_to_animations_map_|, registering animations
// which can now be animated and unregistering those that can't based on the
@@ -106,7 +104,6 @@ class CC_ANIMATION_EXPORT AnimationHost : public MutatorHost,
void PushPropertiesTo(MutatorHost* host_impl) override;
- void SetSupportsScrollAnimations(bool supports_scroll_animations) override;
void SetScrollAnimationDurationForTesting(base::TimeDelta duration) override;
bool NeedsTickAnimations() const override;
@@ -158,10 +155,8 @@ class CC_ANIMATION_EXPORT AnimationHost : public MutatorHost,
bool AnimationsPreserveAxisAlignment(ElementId element_id) const override;
- void GetAnimationScales(ElementId element_id,
- ElementListType list_type,
- float* maximum_scale,
- float* starting_scale) const override;
+ float MaximumScale(ElementId element_id,
+ ElementListType list_type) const override;
bool IsElementAnimating(ElementId element_id) const override;
bool HasTickingKeyframeModelForTesting(ElementId element_id) const override;
@@ -269,7 +264,6 @@ class CC_ANIMATION_EXPORT AnimationHost : public MutatorHost,
const ThreadInstance thread_instance_;
- bool supports_scroll_animations_;
bool needs_push_properties_;
std::unique_ptr<LayerTreeMutator> mutator_;
diff --git a/chromium/cc/animation/animation_target.h b/chromium/cc/animation/animation_target.h
deleted file mode 100644
index 16e99e396b4..00000000000
--- a/chromium/cc/animation/animation_target.h
+++ /dev/null
@@ -1,52 +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_ANIMATION_ANIMATION_TARGET_H_
-#define CC_ANIMATION_ANIMATION_TARGET_H_
-
-#include "cc/animation/animation_export.h"
-#include "third_party/skia/include/core/SkColor.h"
-
-namespace gfx {
-class ScrollOffset;
-class SizeF;
-} // namespace gfx
-
-namespace cc {
-
-class FilterOperations;
-class KeyframeModel;
-class TransformOperations;
-
-// An AnimationTarget is an entity that can be affected by a ticking
-// cc:KeyframeModel. Any object that expects to have an opacity update, for
-// example, should derive from this class.
-class CC_ANIMATION_EXPORT AnimationTarget {
- public:
- virtual ~AnimationTarget() {}
- virtual void NotifyClientFloatAnimated(float value,
- int target_property_id,
- KeyframeModel* keyframe_model) = 0;
- virtual void NotifyClientFilterAnimated(const FilterOperations& filter,
- int target_property_id,
- KeyframeModel* keyframe_model) = 0;
- virtual void NotifyClientSizeAnimated(const gfx::SizeF& size,
- int target_property_id,
- KeyframeModel* keyframe_model) = 0;
- virtual void NotifyClientColorAnimated(SkColor color,
- int target_property_id,
- KeyframeModel* keyframe_model) = 0;
- virtual void NotifyClientTransformOperationsAnimated(
- const TransformOperations& operations,
- int target_property_id,
- KeyframeModel* keyframe_model) = 0;
- virtual void NotifyClientScrollOffsetAnimated(
- const gfx::ScrollOffset& scroll_offset,
- int target_property_id,
- KeyframeModel* keyframe_model) = 0;
-};
-
-} // namespace cc
-
-#endif // CC_ANIMATION_ANIMATION_TARGET_H_
diff --git a/chromium/cc/animation/animation_unittest.cc b/chromium/cc/animation/animation_unittest.cc
index 360400e4bb4..15fe8962b49 100644
--- a/chromium/cc/animation/animation_unittest.cc
+++ b/chromium/cc/animation/animation_unittest.cc
@@ -456,30 +456,33 @@ TEST_F(AnimationTest, ToString) {
animation_->id(), element_id_.ToString().c_str()),
animation_->ToString());
- animation_->AddKeyframeModel(
- KeyframeModel::Create(std::make_unique<FakeFloatAnimationCurve>(15), 42,
- 73, TargetProperty::OPACITY));
+ animation_->AddKeyframeModel(KeyframeModel::Create(
+ std::make_unique<FakeFloatAnimationCurve>(15), 42, 73,
+ KeyframeModel::TargetPropertyId(TargetProperty::OPACITY)));
EXPECT_EQ(
base::StringPrintf("Animation{id=%d, element_id=%s, "
"keyframe_models=[KeyframeModel{id=42, "
- "group=73, target_property_id=1, "
- "run_state=WAITING_FOR_TARGET_AVAILABILITY}]}",
+ "group=73, target_property_type=1, "
+ "custom_property_name=, native_property_type=1, "
+ "run_state=WAITING_FOR_TARGET_AVAILABILITY, "
+ "element_id=(0)}]}",
animation_->id(), element_id_.ToString().c_str()),
animation_->ToString());
- animation_->AddKeyframeModel(
- KeyframeModel::Create(std::make_unique<FakeFloatAnimationCurve>(18), 45,
- 76, TargetProperty::BOUNDS));
- EXPECT_EQ(
- base::StringPrintf(
- "Animation{id=%d, element_id=%s, "
- "keyframe_models=[KeyframeModel{id=42, "
- "group=73, target_property_id=1, "
- "run_state=WAITING_FOR_TARGET_AVAILABILITY}, KeyframeModel{id=45, "
- "group=76, "
- "target_property_id=5, run_state=WAITING_FOR_TARGET_AVAILABILITY}]}",
- animation_->id(), element_id_.ToString().c_str()),
- animation_->ToString());
+ animation_->AddKeyframeModel(KeyframeModel::Create(
+ std::make_unique<FakeFloatAnimationCurve>(18), 45, 76,
+ KeyframeModel::TargetPropertyId(TargetProperty::BOUNDS)));
+ EXPECT_EQ(base::StringPrintf(
+ "Animation{id=%d, element_id=%s, "
+ "keyframe_models=[KeyframeModel{id=42, "
+ "group=73, target_property_type=1, custom_property_name=, "
+ "native_property_type=1, "
+ "run_state=WAITING_FOR_TARGET_AVAILABILITY, element_id=(0)}, "
+ "KeyframeModel{id=45, group=76, target_property_type=5, "
+ "custom_property_name=, native_property_type=1, "
+ "run_state=WAITING_FOR_TARGET_AVAILABILITY, element_id=(0)}]}",
+ animation_->id(), element_id_.ToString().c_str()),
+ animation_->ToString());
}
} // namespace
diff --git a/chromium/cc/animation/element_animations.cc b/chromium/cc/animation/element_animations.cc
index 03996f2b245..c8e8637523c 100644
--- a/chromium/cc/animation/element_animations.cc
+++ b/chromium/cc/animation/element_animations.cc
@@ -7,17 +7,19 @@
#include <stddef.h>
#include <algorithm>
+#include <utility>
#include "base/numerics/ranges.h"
#include "cc/animation/animation_delegate.h"
#include "cc/animation/animation_events.h"
#include "cc/animation/animation_host.h"
#include "cc/animation/keyframe_effect.h"
-#include "cc/animation/keyframed_animation_curve.h"
-#include "cc/animation/transform_operations.h"
+#include "cc/animation/keyframe_model.h"
#include "cc/paint/filter_operations.h"
#include "cc/trees/mutator_host_client.h"
+#include "ui/gfx/animation/keyframe/keyframed_animation_curve.h"
#include "ui/gfx/geometry/box_f.h"
+#include "ui/gfx/transform_operations.h"
namespace cc {
@@ -29,12 +31,18 @@ namespace {
// TODO(flackr): Remove ElementId from ElementAnimations once all element
// tracking is done on the KeyframeModel - https://crbug.com/900241
ElementId CalculateTargetElementId(const ElementAnimations* element_animations,
- const KeyframeModel* keyframe_model) {
- if (LIKELY(keyframe_model->element_id()))
- return keyframe_model->element_id();
+ const gfx::KeyframeModel* keyframe_model) {
+ if (LIKELY(KeyframeModel::ToCcKeyframeModel(keyframe_model)->element_id()))
+ return KeyframeModel::ToCcKeyframeModel(keyframe_model)->element_id();
return element_animations->element_id();
}
+bool UsingPaintWorklet(int property_index) {
+ // The set of properties where its animation uses paint worklet infra.
+ return property_index == TargetProperty::CSS_CUSTOM_PROPERTY ||
+ property_index == TargetProperty::NATIVE_PROPERTY;
+}
+
} // namespace
scoped_refptr<ElementAnimations> ElementAnimations::Create(
@@ -51,10 +59,8 @@ ElementAnimations::ElementAnimations(AnimationHost* host, ElementId element_id)
has_element_in_active_list_(false),
has_element_in_pending_list_(false),
needs_push_properties_(false),
- active_maximum_scale_(kNotScaled),
- active_starting_scale_(kNotScaled),
- pending_maximum_scale_(kNotScaled),
- pending_starting_scale_(kNotScaled) {
+ active_maximum_scale_(kInvalidScale),
+ pending_maximum_scale_(kInvalidScale) {
InitAffectedElementTypes();
}
@@ -75,8 +81,8 @@ void ElementAnimations::InitAffectedElementTypes() {
}
}
-TargetProperties ElementAnimations::GetPropertiesMaskForAnimationState() {
- TargetProperties properties;
+gfx::TargetProperties ElementAnimations::GetPropertiesMaskForAnimationState() {
+ gfx::TargetProperties properties;
properties[TargetProperty::TRANSFORM] = true;
properties[TargetProperty::OPACITY] = true;
properties[TargetProperty::FILTER] = true;
@@ -88,7 +94,8 @@ void ElementAnimations::ClearAffectedElementTypes(
const PropertyToElementIdMap& element_id_map) {
DCHECK(animation_host_);
- TargetProperties disable_properties = GetPropertiesMaskForAnimationState();
+ gfx::TargetProperties disable_properties =
+ GetPropertiesMaskForAnimationState();
PropertyAnimationState disabled_state_mask, disabled_state;
disabled_state_mask.currently_running = disable_properties;
disabled_state_mask.potentially_animating = disable_properties;
@@ -147,7 +154,7 @@ void ElementAnimations::RemoveKeyframeEffect(KeyframeEffect* keyframe_effect) {
}
bool ElementAnimations::IsEmpty() const {
- return !keyframe_effects_list_.might_have_observers();
+ return keyframe_effects_list_.empty();
}
void ElementAnimations::SetNeedsPushProperties() {
@@ -183,25 +190,13 @@ bool ElementAnimations::AnimationsPreserveAxisAlignment() const {
return true;
}
-void ElementAnimations::GetAnimationScales(ElementListType list_type,
- float* maximum_scale,
- float* starting_scale) const {
- *maximum_scale = kNotScaled;
- *starting_scale = kNotScaled;
+float ElementAnimations::MaximumScale(ElementListType list_type) const {
+ float maximum_scale = kInvalidScale;
for (auto& keyframe_effect : keyframe_effects_list_) {
- float keyframe_effect_maximum_scale = kNotScaled;
- float keyframe_effect_starting_scale = kNotScaled;
- bool success = keyframe_effect.GetAnimationScales(
- list_type, &keyframe_effect_maximum_scale,
- &keyframe_effect_starting_scale);
- if (!success) {
- *maximum_scale = kNotScaled;
- *starting_scale = kNotScaled;
- return;
- }
- *maximum_scale = std::max(*maximum_scale, keyframe_effect_maximum_scale);
- *starting_scale = std::max(*starting_scale, keyframe_effect_starting_scale);
+ maximum_scale =
+ std::max(maximum_scale, keyframe_effect.MaximumScale(list_type));
}
+ return maximum_scale;
}
bool ElementAnimations::ScrollOffsetAnimationWasInterrupted() const {
@@ -212,19 +207,21 @@ bool ElementAnimations::ScrollOffsetAnimationWasInterrupted() const {
return false;
}
-void ElementAnimations::NotifyClientFloatAnimated(
- float value,
- int target_property_id,
- KeyframeModel* keyframe_model) {
- switch (keyframe_model->target_property_id()) {
+void ElementAnimations::OnFloatAnimated(const float& value,
+ int target_property_id,
+ gfx::KeyframeModel* keyframe_model) {
+ switch (keyframe_model->TargetProperty()) {
case TargetProperty::CSS_CUSTOM_PROPERTY:
+ case TargetProperty::NATIVE_PROPERTY:
// Custom properties are only tracked on the pending tree, where they may
// be used as inputs for PaintWorklets (which are only dispatched from the
// pending tree). As such, we don't need to notify in the case where a
// KeyframeModel only affects active elements.
if (KeyframeModelAffectsPendingElements(keyframe_model))
- OnCustomPropertyAnimated(PaintWorkletInput::PropertyValue(value),
- keyframe_model);
+ OnCustomPropertyAnimated(
+ PaintWorkletInput::PropertyValue(value),
+ KeyframeModel::ToCcKeyframeModel(keyframe_model),
+ target_property_id);
break;
case TargetProperty::OPACITY: {
float opacity = base::ClampToRange(value, 0.0f, 1.0f);
@@ -239,11 +236,10 @@ void ElementAnimations::NotifyClientFloatAnimated(
}
}
-void ElementAnimations::NotifyClientFilterAnimated(
- const FilterOperations& filters,
- int target_property_id,
- KeyframeModel* keyframe_model) {
- switch (keyframe_model->target_property_id()) {
+void ElementAnimations::OnFilterAnimated(const FilterOperations& filters,
+ int target_property_id,
+ gfx::KeyframeModel* keyframe_model) {
+ switch (keyframe_model->TargetProperty()) {
case TargetProperty::BACKDROP_FILTER:
if (KeyframeModelAffectsActiveElements(keyframe_model))
OnBackdropFilterAnimated(ElementListType::ACTIVE, filters,
@@ -263,20 +259,20 @@ void ElementAnimations::NotifyClientFilterAnimated(
}
}
-void ElementAnimations::NotifyClientColorAnimated(
- SkColor value,
- int target_property_id,
- KeyframeModel* keyframe_model) {
- DCHECK_EQ(keyframe_model->target_property_id(),
+void ElementAnimations::OnColorAnimated(const SkColor& value,
+ int target_property_id,
+ gfx::KeyframeModel* keyframe_model) {
+ DCHECK_EQ(keyframe_model->TargetProperty(),
TargetProperty::CSS_CUSTOM_PROPERTY);
OnCustomPropertyAnimated(PaintWorkletInput::PropertyValue(value),
- keyframe_model);
+ KeyframeModel::ToCcKeyframeModel(keyframe_model),
+ target_property_id);
}
-void ElementAnimations::NotifyClientTransformOperationsAnimated(
- const TransformOperations& operations,
+void ElementAnimations::OnTransformAnimated(
+ const gfx::TransformOperations& operations,
int target_property_id,
- KeyframeModel* keyframe_model) {
+ gfx::KeyframeModel* keyframe_model) {
gfx::Transform transform = operations.Apply();
if (KeyframeModelAffectsActiveElements(keyframe_model))
OnTransformAnimated(ElementListType::ACTIVE, transform, keyframe_model);
@@ -284,10 +280,10 @@ void ElementAnimations::NotifyClientTransformOperationsAnimated(
OnTransformAnimated(ElementListType::PENDING, transform, keyframe_model);
}
-void ElementAnimations::NotifyClientScrollOffsetAnimated(
+void ElementAnimations::OnScrollOffsetAnimated(
const gfx::ScrollOffset& scroll_offset,
int target_property_id,
- KeyframeModel* keyframe_model) {
+ gfx::KeyframeModel* keyframe_model) {
if (KeyframeModelAffectsActiveElements(keyframe_model))
OnScrollOffsetAnimated(ElementListType::ACTIVE, scroll_offset,
keyframe_model);
@@ -301,6 +297,8 @@ void ElementAnimations::InitClientAnimationState() {
// (instead of only changed) recalculated current states to the client.
pending_state_.Clear();
active_state_.Clear();
+ active_maximum_scale_ = kInvalidScale;
+ pending_maximum_scale_ = kInvalidScale;
UpdateClientAnimationState();
}
@@ -326,7 +324,8 @@ void ElementAnimations::UpdateClientAnimationState() {
active_state_ |= keyframe_effect_active_state;
}
- TargetProperties allowed_properties = GetPropertiesMaskForAnimationState();
+ gfx::TargetProperties allowed_properties =
+ GetPropertiesMaskForAnimationState();
PropertyAnimationState allowed_state;
allowed_state.currently_running = allowed_properties;
allowed_state.potentially_animating = allowed_properties;
@@ -347,19 +346,13 @@ void ElementAnimations::UpdateClientAnimationState() {
element_id_map, ElementListType::ACTIVE, diff_active, active_state_);
}
- float maximum_scale = kNotScaled;
- float starting_scale = kNotScaled;
- if (transform_element_id) {
- GetAnimationScales(ElementListType::ACTIVE, &maximum_scale,
- &starting_scale);
- }
- if (maximum_scale != active_maximum_scale_ ||
- starting_scale != active_starting_scale_) {
- animation_host_->mutator_host_client()->AnimationScalesChanged(
- transform_element_id, ElementListType::ACTIVE, maximum_scale,
- starting_scale);
+ float maximum_scale = transform_element_id
+ ? MaximumScale(ElementListType::ACTIVE)
+ : kInvalidScale;
+ if (maximum_scale != active_maximum_scale_) {
+ animation_host_->mutator_host_client()->MaximumScaleChanged(
+ transform_element_id, ElementListType::ACTIVE, maximum_scale);
active_maximum_scale_ = maximum_scale;
- active_starting_scale_ = starting_scale;
}
}
@@ -371,23 +364,42 @@ void ElementAnimations::UpdateClientAnimationState() {
pending_state_);
}
- float maximum_scale = kNotScaled;
- float starting_scale = kNotScaled;
- if (transform_element_id) {
- GetAnimationScales(ElementListType::PENDING, &maximum_scale,
- &starting_scale);
- }
- if (maximum_scale != pending_maximum_scale_ ||
- starting_scale != pending_starting_scale_) {
- animation_host_->mutator_host_client()->AnimationScalesChanged(
- transform_element_id, ElementListType::PENDING, maximum_scale,
- starting_scale);
+ float maximum_scale = transform_element_id
+ ? MaximumScale(ElementListType::PENDING)
+ : kInvalidScale;
+ if (maximum_scale != pending_maximum_scale_) {
+ animation_host_->mutator_host_client()->MaximumScaleChanged(
+ transform_element_id, ElementListType::PENDING, maximum_scale);
pending_maximum_scale_ = maximum_scale;
- pending_starting_scale_ = starting_scale;
}
}
}
+void ElementAnimations::AttachToCurve(gfx::AnimationCurve* c) {
+ switch (c->Type()) {
+ case gfx::AnimationCurve::COLOR:
+ gfx::ColorAnimationCurve::ToColorAnimationCurve(c)->set_target(this);
+ break;
+ case gfx::AnimationCurve::FLOAT:
+ gfx::FloatAnimationCurve::ToFloatAnimationCurve(c)->set_target(this);
+ break;
+ case gfx::AnimationCurve::TRANSFORM:
+ gfx::TransformAnimationCurve::ToTransformAnimationCurve(c)->set_target(
+ this);
+ break;
+ case gfx::AnimationCurve::FILTER:
+ FilterAnimationCurve::ToFilterAnimationCurve(c)->set_target(this);
+ break;
+ case gfx::AnimationCurve::SCROLL_OFFSET:
+ ScrollOffsetAnimationCurve::ToScrollOffsetAnimationCurve(c)->set_target(
+ this);
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+}
+
bool ElementAnimations::HasTickingKeyframeEffect() const {
for (auto& keyframe_effect : keyframe_effects_list_) {
if (keyframe_effect.HasTickingKeyframeModel())
@@ -441,7 +453,7 @@ bool ElementAnimations::IsCurrentlyAnimatingProperty(
void ElementAnimations::OnFilterAnimated(ElementListType list_type,
const FilterOperations& filters,
- KeyframeModel* keyframe_model) {
+ gfx::KeyframeModel* keyframe_model) {
ElementId target_element_id = CalculateTargetElementId(this, keyframe_model);
DCHECK(target_element_id);
DCHECK(animation_host_);
@@ -453,7 +465,7 @@ void ElementAnimations::OnFilterAnimated(ElementListType list_type,
void ElementAnimations::OnBackdropFilterAnimated(
ElementListType list_type,
const FilterOperations& backdrop_filters,
- KeyframeModel* keyframe_model) {
+ gfx::KeyframeModel* keyframe_model) {
ElementId target_element_id = CalculateTargetElementId(this, keyframe_model);
DCHECK(target_element_id);
DCHECK(animation_host_);
@@ -464,7 +476,7 @@ void ElementAnimations::OnBackdropFilterAnimated(
void ElementAnimations::OnOpacityAnimated(ElementListType list_type,
float opacity,
- KeyframeModel* keyframe_model) {
+ gfx::KeyframeModel* keyframe_model) {
ElementId target_element_id = CalculateTargetElementId(this, keyframe_model);
DCHECK(target_element_id);
DCHECK(animation_host_);
@@ -474,18 +486,26 @@ void ElementAnimations::OnOpacityAnimated(ElementListType list_type,
}
void ElementAnimations::OnCustomPropertyAnimated(
- PaintWorkletInput::PropertyValue custom_prop_value,
- KeyframeModel* keyframe_model) {
+ PaintWorkletInput::PropertyValue property_value,
+ KeyframeModel* keyframe_model,
+ int target_property_id) {
DCHECK(animation_host_);
DCHECK(animation_host_->mutator_host_client());
+ ElementId id = CalculateTargetElementId(this, keyframe_model);
+ PaintWorkletInput::PropertyKey property_key =
+ target_property_id == TargetProperty::NATIVE_PROPERTY
+ ? PaintWorkletInput::PropertyKey(
+ keyframe_model->native_property_type(), id)
+ : PaintWorkletInput::PropertyKey(
+ keyframe_model->custom_property_name(), id);
animation_host_->mutator_host_client()->OnCustomPropertyMutated(
- CalculateTargetElementId(this, keyframe_model),
- keyframe_model->custom_property_name(), std::move(custom_prop_value));
+ std::move(property_key), std::move(property_value));
}
-void ElementAnimations::OnTransformAnimated(ElementListType list_type,
- const gfx::Transform& transform,
- KeyframeModel* keyframe_model) {
+void ElementAnimations::OnTransformAnimated(
+ ElementListType list_type,
+ const gfx::Transform& transform,
+ gfx::KeyframeModel* keyframe_model) {
ElementId target_element_id = CalculateTargetElementId(this, keyframe_model);
DCHECK(target_element_id);
DCHECK(animation_host_);
@@ -497,7 +517,7 @@ void ElementAnimations::OnTransformAnimated(ElementListType list_type,
void ElementAnimations::OnScrollOffsetAnimated(
ElementListType list_type,
const gfx::ScrollOffset& scroll_offset,
- KeyframeModel* keyframe_model) {
+ gfx::KeyframeModel* keyframe_model) {
ElementId target_element_id = CalculateTargetElementId(this, keyframe_model);
DCHECK(target_element_id);
DCHECK(animation_host_);
@@ -534,6 +554,18 @@ PropertyToElementIdMap ElementAnimations::GetPropertyToElementIdMap() const {
for (int property_index = TargetProperty::FIRST_TARGET_PROPERTY;
property_index <= TargetProperty::LAST_TARGET_PROPERTY;
++property_index) {
+ // We skip the set of properties that uses paint worklet, because the
+ // animation is not directly associated with the element its compositing
+ // layer targets and we use reserved element id when we attach a layer for
+ // the animation. In that case, the DCHECK here is no longer applicable.
+ // For example, when we have two paint worklet elements with two different
+ // custom property animations, then these two KeyframeModels would have
+ // different element_id and thus fail the first DCHECK here.
+ // It is not valid to include these properties in the PropertyToElementIdMap
+ // as they do not map to a single element id. Therefore, these properties
+ // should not be included in the map.
+ if (UsingPaintWorklet(property_index))
+ continue;
TargetProperty::Type property =
static_cast<TargetProperty::Type>(property_index);
ElementId element_id_for_property;
@@ -579,7 +611,7 @@ unsigned int ElementAnimations::CountKeyframesForTesting() const {
}
KeyframeEffect* ElementAnimations::FirstKeyframeEffectForTesting() const {
- DCHECK(keyframe_effects_list_.might_have_observers());
+ DCHECK(!keyframe_effects_list_.empty());
return &*keyframe_effects_list_.begin();
}
@@ -589,24 +621,26 @@ bool ElementAnimations::HasKeyframeEffectForTesting(
}
bool ElementAnimations::KeyframeModelAffectsActiveElements(
- KeyframeModel* keyframe_model) const {
+ gfx::KeyframeModel* keyframe_model) const {
// When we force a keyframe_model update due to a notification, we do not have
// a KeyframeModel instance. In this case, we force an update of active
// elements.
if (!keyframe_model)
return true;
- return keyframe_model->affects_active_elements() &&
+ return KeyframeModel::ToCcKeyframeModel(keyframe_model)
+ ->affects_active_elements() &&
has_element_in_active_list();
}
bool ElementAnimations::KeyframeModelAffectsPendingElements(
- KeyframeModel* keyframe_model) const {
+ gfx::KeyframeModel* keyframe_model) const {
// When we force a keyframe_model update due to a notification, we do not have
// a KeyframeModel instance. In this case, we force an update of pending
// elements.
if (!keyframe_model)
return true;
- return keyframe_model->affects_pending_elements() &&
+ return KeyframeModel::ToCcKeyframeModel(keyframe_model)
+ ->affects_pending_elements() &&
has_element_in_pending_list();
}
diff --git a/chromium/cc/animation/element_animations.h b/chromium/cc/animation/element_animations.h
index 22a29defd10..e306a69e992 100644
--- a/chromium/cc/animation/element_animations.h
+++ b/chromium/cc/animation/element_animations.h
@@ -11,20 +11,27 @@
#include "base/memory/ref_counted.h"
#include "base/observer_list.h"
#include "cc/animation/animation_export.h"
-#include "cc/animation/animation_target.h"
+#include "cc/animation/filter_animation_curve.h"
+#include "cc/animation/scroll_offset_animation_curve.h"
#include "cc/paint/element_id.h"
#include "cc/paint/paint_worklet_input.h"
#include "cc/trees/property_animation_state.h"
#include "cc/trees/target_property.h"
+#include "ui/gfx/animation/keyframe/animation_curve.h"
+#include "ui/gfx/animation/keyframe/target_property.h"
#include "ui/gfx/geometry/scroll_offset.h"
#include "ui/gfx/transform.h"
+namespace gfx {
+class TransformOperations;
+} // namespace gfx
+
namespace cc {
class AnimationHost;
class FilterOperations;
class KeyframeEffect;
-class TransformOperations;
+class KeyframeModel;
enum class ElementListType;
// An ElementAnimations owns a list of all KeyframeEffects attached to a single
@@ -34,7 +41,11 @@ enum class ElementListType;
// of the word; this naming is a legacy leftover. A target is just an amorphous
// blob that has properties that can be animated.
class CC_ANIMATION_EXPORT ElementAnimations
- : public AnimationTarget,
+ : public gfx::FloatAnimationCurve::Target,
+ public gfx::ColorAnimationCurve::Target,
+ public gfx::TransformAnimationCurve::Target,
+ public ScrollOffsetAnimationCurve::Target,
+ public FilterAnimationCurve::Target,
public base::RefCounted<ElementAnimations> {
public:
static scoped_refptr<ElementAnimations> Create(AnimationHost* host,
@@ -107,15 +118,10 @@ class CC_ANIMATION_EXPORT ElementAnimations
bool AnimationsPreserveAxisAlignment() const;
- // Gets scales transform animations. On return, |maximum_scale| is the maximum
- // scale along any dimension at any destination in active scale animations,
- // and |starting_scale| is the maximum of starting animation scale along any
- // dimension at any destination in active scale animations. They are set to
- // kNotScaled if there is no active scale animation or the scales cannot be
- // computed.
- void GetAnimationScales(ElementListType list_type,
- float* maximum_scale,
- float* starting_scale) const;
+ // Returns the maximum scale along any dimension at any destination in active
+ // scale animations, or kInvalidScale if there is no active transform
+ // animation or the scale cannot be computed.
+ float MaximumScale(ElementListType list_type) const;
bool ScrollOffsetAnimationWasInterrupted() const;
@@ -129,25 +135,28 @@ class CC_ANIMATION_EXPORT ElementAnimations
// that have changed since the last update.
void UpdateClientAnimationState();
- void NotifyClientFloatAnimated(float value,
- int target_property_id,
- KeyframeModel* keyframe_model) override;
- void NotifyClientFilterAnimated(const FilterOperations& filter,
- int target_property_id,
- KeyframeModel* keyframe_model) override;
- void NotifyClientSizeAnimated(const gfx::SizeF& size,
- int target_property_id,
- KeyframeModel* keyframe_model) override {}
- void NotifyClientColorAnimated(SkColor color,
- int target_property_id,
- KeyframeModel* keyframe_model) override;
- void NotifyClientTransformOperationsAnimated(
- const TransformOperations& operations,
- int target_property_id,
- KeyframeModel* keyframe_model) override;
- void NotifyClientScrollOffsetAnimated(const gfx::ScrollOffset& scroll_offset,
- int target_property_id,
- KeyframeModel* keyframe_model) override;
+ // TODO(crbug.com/1176334): Animation targets should be attached to curves
+ // when they're created and the concrete subclass is known. This function
+ // exists as a stopgap: the animation machinery previously expected to
+ // announce a target and then pass curves that would implicitly animate the
+ // target (i.e., the machinery handled the attachment).
+ void AttachToCurve(gfx::AnimationCurve* c);
+
+ void OnFloatAnimated(const float& value,
+ int target_property_id,
+ gfx::KeyframeModel* keyframe_model) override;
+ void OnFilterAnimated(const FilterOperations& filter,
+ int target_property_id,
+ gfx::KeyframeModel* keyframe_model) override;
+ void OnColorAnimated(const SkColor& color,
+ int target_property_id,
+ gfx::KeyframeModel* keyframe_model) override;
+ void OnTransformAnimated(const gfx::TransformOperations& operations,
+ int target_property_id,
+ gfx::KeyframeModel* keyframe_model) override;
+ void OnScrollOffsetAnimated(const gfx::ScrollOffset& scroll_offset,
+ int target_property_id,
+ gfx::KeyframeModel* keyframe_model) override;
gfx::ScrollOffset ScrollOffsetForAnimation() const;
@@ -174,30 +183,40 @@ class CC_ANIMATION_EXPORT ElementAnimations
void OnFilterAnimated(ElementListType list_type,
const FilterOperations& filters,
- KeyframeModel* keyframe_model);
+ gfx::KeyframeModel* keyframe_model);
void OnBackdropFilterAnimated(ElementListType list_type,
const FilterOperations& backdrop_filters,
- KeyframeModel* keyframe_model);
+ gfx::KeyframeModel* keyframe_model);
void OnOpacityAnimated(ElementListType list_type,
float opacity,
- KeyframeModel* keyframe_model);
- void OnCustomPropertyAnimated(
- PaintWorkletInput::PropertyValue custom_prop_value,
- KeyframeModel* keyframe_model);
+ gfx::KeyframeModel* keyframe_model);
+ // In addition to custom property animations, these also represent animations
+ // of native properties whose values are known to the Blink PaintWorklet
+ // responsible for painting them but not known to the compositor. The
+ // compositor animates a simple float progress which is then passed into blink
+ // code to interpolate. Unlike other native properties listed above, CC is not
+ // capable of drawing interpolations of these properties and defers to
+ // NativePaintWorklet subclasses to interpret the animation progress as it
+ // pertains to how to paint the native property.
+ void OnCustomPropertyAnimated(PaintWorkletInput::PropertyValue property_value,
+ KeyframeModel* keyframe_model,
+ int target_property_id);
void OnTransformAnimated(ElementListType list_type,
const gfx::Transform& transform,
- KeyframeModel* keyframe_model);
+ gfx::KeyframeModel* keyframe_model);
void OnScrollOffsetAnimated(ElementListType list_type,
const gfx::ScrollOffset& scroll_offset,
- KeyframeModel* keyframe_model);
+ gfx::KeyframeModel* keyframe_model);
- static TargetProperties GetPropertiesMaskForAnimationState();
+ static gfx::TargetProperties GetPropertiesMaskForAnimationState();
void UpdateKeyframeEffectsTickingState() const;
void RemoveKeyframeEffectsFromTicking() const;
- bool KeyframeModelAffectsActiveElements(KeyframeModel* keyframe_model) const;
- bool KeyframeModelAffectsPendingElements(KeyframeModel* keyframe_model) const;
+ bool KeyframeModelAffectsActiveElements(
+ gfx::KeyframeModel* keyframe_model) const;
+ bool KeyframeModelAffectsPendingElements(
+ gfx::KeyframeModel* keyframe_model) const;
base::ObserverList<KeyframeEffect>::Unchecked keyframe_effects_list_;
AnimationHost* animation_host_;
@@ -211,9 +230,7 @@ class CC_ANIMATION_EXPORT ElementAnimations
PropertyAnimationState active_state_;
PropertyAnimationState pending_state_;
float active_maximum_scale_;
- float active_starting_scale_;
float pending_maximum_scale_;
- float pending_starting_scale_;
};
} // namespace cc
diff --git a/chromium/cc/animation/element_animations_unittest.cc b/chromium/cc/animation/element_animations_unittest.cc
index 9e1fa8337f3..e5fecd65354 100644
--- a/chromium/cc/animation/element_animations_unittest.cc
+++ b/chromium/cc/animation/element_animations_unittest.cc
@@ -4,6 +4,9 @@
#include "cc/animation/element_animations.h"
+#include <limits>
+#include <utility>
+
#include "base/memory/ptr_util.h"
#include "cc/animation/animation.h"
#include "cc/animation/animation_delegate.h"
@@ -12,13 +15,13 @@
#include "cc/animation/animation_id_provider.h"
#include "cc/animation/animation_timeline.h"
#include "cc/animation/keyframe_effect.h"
-#include "cc/animation/keyframed_animation_curve.h"
#include "cc/animation/scroll_offset_animation_curve.h"
#include "cc/animation/scroll_offset_animation_curve_factory.h"
-#include "cc/animation/transform_operations.h"
#include "cc/test/animation_test_common.h"
#include "cc/test/animation_timelines_test_common.h"
+#include "ui/gfx/animation/keyframe/keyframed_animation_curve.h"
#include "ui/gfx/geometry/box_f.h"
+#include "ui/gfx/transform_operations.h"
namespace cc {
namespace {
@@ -40,9 +43,7 @@ class ElementAnimationsTest : public AnimationTimelinesTest {
ElementAnimationsTest() = default;
~ElementAnimationsTest() override = default;
- void SetUp() override {
- AnimationTimelinesTest::SetUp();
- }
+ void SetUp() override { AnimationTimelinesTest::SetUp(); }
void CreateImplTimelineAndAnimation() override {
AnimationTimelinesTest::CreateImplTimelineAndAnimation();
@@ -269,14 +270,15 @@ TEST_F(ElementAnimationsTest,
curve_fixed->SetInitialValue(initial_value);
const int animation1_id = 1;
std::unique_ptr<KeyframeModel> animation_fixed(KeyframeModel::Create(
- std::move(curve_fixed), animation1_id, 0, TargetProperty::SCROLL_OFFSET));
+ std::move(curve_fixed), animation1_id, 0,
+ KeyframeModel::TargetPropertyId(TargetProperty::SCROLL_OFFSET)));
animation_->AddKeyframeModel(std::move(animation_fixed));
PushProperties();
- EXPECT_VECTOR2DF_EQ(initial_value, animation_impl_->keyframe_effect()
- ->GetKeyframeModelById(animation1_id)
- ->curve()
- ->ToScrollOffsetAnimationCurve()
- ->GetValue(base::TimeDelta()));
+ auto* scroll_curve = ScrollOffsetAnimationCurve::ToScrollOffsetAnimationCurve(
+ animation_impl_->keyframe_effect()
+ ->GetKeyframeModelById(animation1_id)
+ ->curve());
+ EXPECT_VECTOR2DF_EQ(initial_value, scroll_curve->GetValue(base::TimeDelta()));
animation_->RemoveKeyframeModel(animation1_id);
// Animation without initial value set.
@@ -285,15 +287,16 @@ TEST_F(ElementAnimationsTest,
target_value));
const int animation2_id = 2;
std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create(
- std::move(curve), animation2_id, 1, TargetProperty::SCROLL_OFFSET));
+ std::move(curve), animation2_id, 1,
+ KeyframeModel::TargetPropertyId(TargetProperty::SCROLL_OFFSET)));
animation_->AddKeyframeModel(std::move(keyframe_model));
PushProperties();
+ scroll_curve = static_cast<ScrollOffsetAnimationCurve*>(
+ animation_impl_->keyframe_effect()
+ ->GetKeyframeModelById(animation2_id)
+ ->curve());
EXPECT_VECTOR2DF_EQ(provider_initial_value,
- animation_impl_->keyframe_effect()
- ->GetKeyframeModelById(animation2_id)
- ->curve()
- ->ToScrollOffsetAnimationCurve()
- ->GetValue(base::TimeDelta()));
+ scroll_curve->GetValue(base::TimeDelta()));
animation_->RemoveKeyframeModel(animation2_id);
}
@@ -748,10 +751,11 @@ TEST_F(ElementAnimationsTest, AnimationsAreDeleted) {
// Tests that transitioning opacity from 0 to 1 works as expected.
static std::unique_ptr<KeyframeModel> CreateKeyframeModel(
- std::unique_ptr<AnimationCurve> curve,
+ std::unique_ptr<gfx::AnimationCurve> curve,
int group_id,
TargetProperty::Type property) {
- return KeyframeModel::Create(std::move(curve), 0, group_id, property);
+ return KeyframeModel::Create(std::move(curve), 0, group_id,
+ KeyframeModel::TargetPropertyId(property));
}
TEST_F(ElementAnimationsTest, TrivialTransition) {
@@ -760,9 +764,10 @@ TEST_F(ElementAnimationsTest, TrivialTransition) {
auto events = CreateEventsForTesting();
- std::unique_ptr<KeyframeModel> to_add(CreateKeyframeModel(
- std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)),
- 1, TargetProperty::OPACITY));
+ std::unique_ptr<KeyframeModel> to_add(
+ CreateKeyframeModel(std::unique_ptr<gfx::AnimationCurve>(
+ new FakeFloatTransition(1.0, 0.f, 1.f)),
+ 1, TargetProperty::OPACITY));
int keyframe_model_id = to_add->id();
EXPECT_FALSE(
@@ -807,8 +812,9 @@ TEST_F(ElementAnimationsTest, FilterTransition) {
curve->AddKeyframe(FilterKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
end_filters, nullptr));
- std::unique_ptr<KeyframeModel> keyframe_model(
- KeyframeModel::Create(std::move(curve), 1, 0, TargetProperty::FILTER));
+ std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create(
+ std::move(curve), 1, 0,
+ KeyframeModel::TargetPropertyId(TargetProperty::FILTER)));
animation_->AddKeyframeModel(std::move(keyframe_model));
animation_->Tick(kInitialTickTime);
@@ -850,7 +856,8 @@ TEST_F(ElementAnimationsTest, BackdropFilterTransition) {
end_filters, nullptr));
std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create(
- std::move(curve), 1, 0, TargetProperty::BACKDROP_FILTER));
+ std::move(curve), 1, 0,
+ KeyframeModel::TargetPropertyId(TargetProperty::BACKDROP_FILTER)));
animation_->AddKeyframeModel(std::move(keyframe_model));
animation_->Tick(kInitialTickTime);
@@ -889,7 +896,8 @@ TEST_F(ElementAnimationsTest, ScrollOffsetTransition) {
target_value));
std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create(
- std::move(curve), 1, 0, TargetProperty::SCROLL_OFFSET));
+ std::move(curve), 1, 0,
+ KeyframeModel::TargetPropertyId(TargetProperty::SCROLL_OFFSET)));
keyframe_model->set_needs_synchronized_start_time(true);
animation_->AddKeyframeModel(std::move(keyframe_model));
@@ -961,7 +969,8 @@ TEST_F(ElementAnimationsTest, ScrollOffsetTransitionOnImplOnly) {
double duration_in_seconds = curve->Duration().InSecondsF();
std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create(
- std::move(curve), 1, 0, TargetProperty::SCROLL_OFFSET));
+ std::move(curve), 1, 0,
+ KeyframeModel::TargetPropertyId(TargetProperty::SCROLL_OFFSET)));
keyframe_model->SetIsImplOnly();
animation_impl_->AddKeyframeModel(std::move(keyframe_model));
@@ -1060,7 +1069,8 @@ TEST_F(ElementAnimationsTest, ScrollOffsetTransitionNoImplProvider) {
target_value));
std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create(
- std::move(curve), 1, 0, TargetProperty::SCROLL_OFFSET));
+ std::move(curve), 1, 0,
+ KeyframeModel::TargetPropertyId(TargetProperty::SCROLL_OFFSET)));
keyframe_model->set_needs_synchronized_start_time(true);
animation_->AddKeyframeModel(std::move(keyframe_model));
@@ -1139,7 +1149,8 @@ TEST_F(ElementAnimationsTest, ScrollOffsetRemovalClearsScrollDelta) {
int keyframe_model_id = 1;
std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create(
- std::move(curve), keyframe_model_id, 0, TargetProperty::SCROLL_OFFSET));
+ std::move(curve), keyframe_model_id, 0,
+ KeyframeModel::TargetPropertyId(TargetProperty::SCROLL_OFFSET)));
keyframe_model->set_needs_synchronized_start_time(true);
animation_->AddKeyframeModel(std::move(keyframe_model));
PushProperties();
@@ -1166,8 +1177,9 @@ TEST_F(ElementAnimationsTest, ScrollOffsetRemovalClearsScrollDelta) {
// Now, test the 2-argument version of RemoveKeyframeModel.
curve = ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting(
target_value);
- keyframe_model = KeyframeModel::Create(std::move(curve), keyframe_model_id, 0,
- TargetProperty::SCROLL_OFFSET);
+ keyframe_model = KeyframeModel::Create(
+ std::move(curve), keyframe_model_id, 0,
+ KeyframeModel::TargetPropertyId(TargetProperty::SCROLL_OFFSET));
keyframe_model->set_needs_synchronized_start_time(true);
animation_->AddKeyframeModel(std::move(keyframe_model));
PushProperties();
@@ -1261,7 +1273,8 @@ TEST_F(ElementAnimationsTest,
curve->SetInitialValue(initial_value);
TimeDelta duration = curve->Duration();
std::unique_ptr<KeyframeModel> to_add(KeyframeModel::Create(
- std::move(curve), 1, 0, TargetProperty::SCROLL_OFFSET));
+ std::move(curve), 1, 0,
+ KeyframeModel::TargetPropertyId(TargetProperty::SCROLL_OFFSET)));
to_add->SetIsImplOnly();
animation_impl_->AddKeyframeModel(std::move(to_add));
@@ -1333,9 +1346,10 @@ TEST_F(ElementAnimationsTest,
auto events = CreateEventsForTesting();
- std::unique_ptr<KeyframeModel> to_add(CreateKeyframeModel(
- std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)),
- 1, TargetProperty::OPACITY));
+ std::unique_ptr<KeyframeModel> to_add(
+ CreateKeyframeModel(std::unique_ptr<gfx::AnimationCurve>(
+ new FakeFloatTransition(1.0, 0.f, 1.f)),
+ 1, TargetProperty::OPACITY));
to_add->set_needs_synchronized_start_time(true);
int keyframe_model_id = to_add->id();
@@ -1378,11 +1392,15 @@ TEST_F(ElementAnimationsTest, TrivialQueuing) {
int animation1_id = 1;
int animation2_id = 2;
animation_->AddKeyframeModel(KeyframeModel::Create(
- std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)),
- animation1_id, 1, TargetProperty::OPACITY));
+ std::unique_ptr<gfx::AnimationCurve>(
+ new FakeFloatTransition(1.0, 0.f, 1.f)),
+ animation1_id, 1,
+ KeyframeModel::TargetPropertyId(TargetProperty::OPACITY)));
animation_->AddKeyframeModel(KeyframeModel::Create(
- std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 1.f, 0.5f)),
- animation2_id, 2, TargetProperty::OPACITY));
+ std::unique_ptr<gfx::AnimationCurve>(
+ new FakeFloatTransition(1.0, 1.f, 0.5f)),
+ animation2_id, 2,
+ KeyframeModel::TargetPropertyId(TargetProperty::OPACITY)));
animation_->Tick(kInitialTickTime);
@@ -1435,17 +1453,19 @@ TEST_F(ElementAnimationsTest, Interrupt) {
auto events = CreateEventsForTesting();
- animation_->AddKeyframeModel(CreateKeyframeModel(
- std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)),
- 1, TargetProperty::OPACITY));
+ animation_->AddKeyframeModel(
+ CreateKeyframeModel(std::unique_ptr<gfx::AnimationCurve>(
+ new FakeFloatTransition(1.0, 0.f, 1.f)),
+ 1, TargetProperty::OPACITY));
animation_->Tick(kInitialTickTime);
animation_->UpdateState(true, events.get());
EXPECT_TRUE(animation_->keyframe_effect()->HasTickingKeyframeModel());
EXPECT_EQ(0.f, client_.GetOpacity(element_id_, ElementListType::ACTIVE));
- std::unique_ptr<KeyframeModel> to_add(CreateKeyframeModel(
- std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 1.f, 0.5f)),
- 2, TargetProperty::OPACITY));
+ std::unique_ptr<KeyframeModel> to_add(
+ CreateKeyframeModel(std::unique_ptr<gfx::AnimationCurve>(
+ new FakeFloatTransition(1.0, 1.f, 0.5f)),
+ 2, TargetProperty::OPACITY));
animation_->AbortKeyframeModelsWithProperty(TargetProperty::OPACITY, false);
animation_->AddKeyframeModel(std::move(to_add));
@@ -1470,14 +1490,15 @@ TEST_F(ElementAnimationsTest, ScheduleTogetherWhenAPropertyIsBlocked) {
auto events = CreateEventsForTesting();
animation_->AddKeyframeModel(CreateKeyframeModel(
- std::unique_ptr<AnimationCurve>(new FakeTransformTransition(1)), 1,
+ std::unique_ptr<gfx::AnimationCurve>(new FakeTransformTransition(1)), 1,
TargetProperty::TRANSFORM));
animation_->AddKeyframeModel(CreateKeyframeModel(
- std::unique_ptr<AnimationCurve>(new FakeTransformTransition(1)), 2,
+ std::unique_ptr<gfx::AnimationCurve>(new FakeTransformTransition(1)), 2,
TargetProperty::TRANSFORM));
- animation_->AddKeyframeModel(CreateKeyframeModel(
- std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)),
- 2, TargetProperty::OPACITY));
+ animation_->AddKeyframeModel(
+ CreateKeyframeModel(std::unique_ptr<gfx::AnimationCurve>(
+ new FakeFloatTransition(1.0, 0.f, 1.f)),
+ 2, TargetProperty::OPACITY));
animation_->Tick(kInitialTickTime);
animation_->UpdateState(true, events.get());
@@ -1505,14 +1526,16 @@ TEST_F(ElementAnimationsTest, ScheduleTogetherWithAnAnimWaiting) {
auto events = CreateEventsForTesting();
animation_->AddKeyframeModel(CreateKeyframeModel(
- std::unique_ptr<AnimationCurve>(new FakeTransformTransition(2)), 1,
+ std::unique_ptr<gfx::AnimationCurve>(new FakeTransformTransition(2)), 1,
TargetProperty::TRANSFORM));
- animation_->AddKeyframeModel(CreateKeyframeModel(
- std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)),
- 1, TargetProperty::OPACITY));
- animation_->AddKeyframeModel(CreateKeyframeModel(
- std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 1.f, 0.5f)),
- 2, TargetProperty::OPACITY));
+ animation_->AddKeyframeModel(
+ CreateKeyframeModel(std::unique_ptr<gfx::AnimationCurve>(
+ new FakeFloatTransition(1.0, 0.f, 1.f)),
+ 1, TargetProperty::OPACITY));
+ animation_->AddKeyframeModel(
+ CreateKeyframeModel(std::unique_ptr<gfx::AnimationCurve>(
+ new FakeFloatTransition(1.0, 1.f, 0.5f)),
+ 2, TargetProperty::OPACITY));
// Animations with id 1 should both start now.
animation_->Tick(kInitialTickTime);
@@ -1543,9 +1566,10 @@ TEST_F(ElementAnimationsTest, TrivialLooping) {
auto events = CreateEventsForTesting();
- std::unique_ptr<KeyframeModel> to_add(CreateKeyframeModel(
- std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)),
- 1, TargetProperty::OPACITY));
+ std::unique_ptr<KeyframeModel> to_add(
+ CreateKeyframeModel(std::unique_ptr<gfx::AnimationCurve>(
+ new FakeFloatTransition(1.0, 0.f, 1.f)),
+ 1, TargetProperty::OPACITY));
to_add->set_iterations(3);
animation_->AddKeyframeModel(std::move(to_add));
@@ -1587,9 +1611,10 @@ TEST_F(ElementAnimationsTest, InfiniteLooping) {
auto events = CreateEventsForTesting();
- std::unique_ptr<KeyframeModel> to_add(CreateKeyframeModel(
- std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)),
- 1, TargetProperty::OPACITY));
+ std::unique_ptr<KeyframeModel> to_add(
+ CreateKeyframeModel(std::unique_ptr<gfx::AnimationCurve>(
+ new FakeFloatTransition(1.0, 0.f, 1.f)),
+ 1, TargetProperty::OPACITY));
to_add->set_iterations(std::numeric_limits<double>::infinity());
animation_->AddKeyframeModel(std::move(to_add));
@@ -1632,9 +1657,10 @@ TEST_F(ElementAnimationsTest, PauseResume) {
auto events = CreateEventsForTesting();
- animation_->AddKeyframeModel(CreateKeyframeModel(
- std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)),
- 1, TargetProperty::OPACITY));
+ animation_->AddKeyframeModel(
+ CreateKeyframeModel(std::unique_ptr<gfx::AnimationCurve>(
+ new FakeFloatTransition(1.0, 0.f, 1.f)),
+ 1, TargetProperty::OPACITY));
animation_->Tick(kInitialTickTime);
animation_->UpdateState(true, events.get());
@@ -1678,14 +1704,17 @@ TEST_F(ElementAnimationsTest, AbortAGroupedAnimation) {
const int keyframe_model_id = 2;
animation_->AddKeyframeModel(KeyframeModel::Create(
- std::unique_ptr<AnimationCurve>(new FakeTransformTransition(1)), 1, 1,
- TargetProperty::TRANSFORM));
+ std::unique_ptr<gfx::AnimationCurve>(new FakeTransformTransition(1)), 1,
+ 1, KeyframeModel::TargetPropertyId(TargetProperty::TRANSFORM)));
animation_->AddKeyframeModel(KeyframeModel::Create(
- std::unique_ptr<AnimationCurve>(new FakeFloatTransition(2.0, 0.f, 1.f)),
- keyframe_model_id, 1, TargetProperty::OPACITY));
+ std::unique_ptr<gfx::AnimationCurve>(
+ new FakeFloatTransition(2.0, 0.f, 1.f)),
+ keyframe_model_id, 1,
+ KeyframeModel::TargetPropertyId(TargetProperty::OPACITY)));
animation_->AddKeyframeModel(KeyframeModel::Create(
- std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 1.f, 0.75f)),
- 3, 2, TargetProperty::OPACITY));
+ std::unique_ptr<gfx::AnimationCurve>(
+ new FakeFloatTransition(1.0, 1.f, 0.75f)),
+ 3, 2, KeyframeModel::TargetPropertyId(TargetProperty::OPACITY)));
animation_->Tick(kInitialTickTime);
animation_->UpdateState(true, events.get());
@@ -1719,9 +1748,10 @@ TEST_F(ElementAnimationsTest, PushUpdatesWhenSynchronizedStartTimeNeeded) {
auto events = CreateEventsForTesting();
- std::unique_ptr<KeyframeModel> to_add(CreateKeyframeModel(
- std::unique_ptr<AnimationCurve>(new FakeFloatTransition(2.0, 0.f, 1.f)),
- 0, TargetProperty::OPACITY));
+ std::unique_ptr<KeyframeModel> to_add(
+ CreateKeyframeModel(std::unique_ptr<gfx::AnimationCurve>(
+ new FakeFloatTransition(2.0, 0.f, 1.f)),
+ 0, TargetProperty::OPACITY));
to_add->set_needs_synchronized_start_time(true);
animation_->AddKeyframeModel(std::move(to_add));
@@ -1752,7 +1782,7 @@ TEST_F(ElementAnimationsTest, SkipUpdateState) {
auto events = CreateEventsForTesting();
std::unique_ptr<KeyframeModel> first_keyframe_model(CreateKeyframeModel(
- std::unique_ptr<AnimationCurve>(new FakeTransformTransition(1)), 1,
+ std::unique_ptr<gfx::AnimationCurve>(new FakeTransformTransition(1)), 1,
TargetProperty::TRANSFORM));
first_keyframe_model->set_is_controlling_instance_for_test(true);
animation_->AddKeyframeModel(std::move(first_keyframe_model));
@@ -1760,9 +1790,10 @@ TEST_F(ElementAnimationsTest, SkipUpdateState) {
animation_->Tick(kInitialTickTime);
animation_->UpdateState(true, events.get());
- std::unique_ptr<KeyframeModel> second_keyframe_model(CreateKeyframeModel(
- std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)),
- 2, TargetProperty::OPACITY));
+ std::unique_ptr<KeyframeModel> second_keyframe_model(
+ CreateKeyframeModel(std::unique_ptr<gfx::AnimationCurve>(
+ new FakeFloatTransition(1.0, 0.f, 1.f)),
+ 2, TargetProperty::OPACITY));
second_keyframe_model->set_is_controlling_instance_for_test(true);
animation_->AddKeyframeModel(std::move(second_keyframe_model));
@@ -1798,9 +1829,10 @@ TEST_F(ElementAnimationsTest, InactiveObserverGetsTicked) {
auto events = CreateEventsForTesting();
const int id = 1;
- animation_impl_->AddKeyframeModel(CreateKeyframeModel(
- std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.5f, 1.f)),
- id, TargetProperty::OPACITY));
+ animation_impl_->AddKeyframeModel(
+ CreateKeyframeModel(std::unique_ptr<gfx::AnimationCurve>(
+ new FakeFloatTransition(1.0, 0.5f, 1.f)),
+ id, TargetProperty::OPACITY));
animation_impl_->GetKeyframeModel(TargetProperty::OPACITY)
->set_affects_active_elements(false);
@@ -1872,20 +1904,22 @@ TEST_F(ElementAnimationsTest, AbortKeyframeModelsWithProperty) {
// Start with several animations, and allow some of them to reach the finished
// state.
animation_->AddKeyframeModel(KeyframeModel::Create(
- std::unique_ptr<AnimationCurve>(new FakeTransformTransition(1.0)), 1, 1,
- TargetProperty::TRANSFORM));
+ std::unique_ptr<gfx::AnimationCurve>(new FakeTransformTransition(1.0)), 1,
+ 1, KeyframeModel::TargetPropertyId(TargetProperty::TRANSFORM)));
animation_->AddKeyframeModel(KeyframeModel::Create(
- std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)),
- 2, 2, TargetProperty::OPACITY));
+ std::unique_ptr<gfx::AnimationCurve>(
+ new FakeFloatTransition(1.0, 0.f, 1.f)),
+ 2, 2, KeyframeModel::TargetPropertyId(TargetProperty::OPACITY)));
animation_->AddKeyframeModel(KeyframeModel::Create(
- std::unique_ptr<AnimationCurve>(new FakeTransformTransition(1.0)), 3, 3,
- TargetProperty::TRANSFORM));
+ std::unique_ptr<gfx::AnimationCurve>(new FakeTransformTransition(1.0)), 3,
+ 3, KeyframeModel::TargetPropertyId(TargetProperty::TRANSFORM)));
animation_->AddKeyframeModel(KeyframeModel::Create(
- std::unique_ptr<AnimationCurve>(new FakeTransformTransition(2.0)), 4, 4,
- TargetProperty::TRANSFORM));
+ std::unique_ptr<gfx::AnimationCurve>(new FakeTransformTransition(2.0)), 4,
+ 4, KeyframeModel::TargetPropertyId(TargetProperty::TRANSFORM)));
animation_->AddKeyframeModel(KeyframeModel::Create(
- std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)),
- 5, 5, TargetProperty::OPACITY));
+ std::unique_ptr<gfx::AnimationCurve>(
+ new FakeFloatTransition(1.0, 0.f, 1.f)),
+ 5, 5, KeyframeModel::TargetPropertyId(TargetProperty::OPACITY)));
animation_->Tick(kInitialTickTime);
animation_->UpdateState(true, nullptr);
@@ -2047,7 +2081,8 @@ TEST_F(ElementAnimationsTest, ImplThreadTakeoverAnimationGetsDeleted) {
target_value));
curve->SetInitialValue(initial_value);
std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create(
- std::move(curve), keyframe_model_id, 0, TargetProperty::SCROLL_OFFSET));
+ std::move(curve), keyframe_model_id, 0,
+ KeyframeModel::TargetPropertyId(TargetProperty::SCROLL_OFFSET)));
keyframe_model->set_start_time(TicksFromSecondsF(123));
keyframe_model->SetIsImplOnly();
animation_impl_->AddKeyframeModel(std::move(keyframe_model));
@@ -2074,9 +2109,9 @@ TEST_F(ElementAnimationsTest, ImplThreadTakeoverAnimationGetsDeleted) {
EXPECT_EQ(1u, events->events_.size());
EXPECT_EQ(AnimationEvent::TAKEOVER, events->events_[0].type);
EXPECT_EQ(TicksFromSecondsF(123), events->events_[0].animation_start_time);
- EXPECT_EQ(
- target_value,
- events->events_[0].curve->ToScrollOffsetAnimationCurve()->target_value());
+ EXPECT_EQ(target_value, static_cast<ScrollOffsetAnimationCurve*>(
+ events->events_[0].curve.get())
+ ->target_value());
EXPECT_EQ(nullptr,
animation_impl_->GetKeyframeModel(TargetProperty::SCROLL_OFFSET));
@@ -2112,14 +2147,15 @@ TEST_F(ElementAnimationsTest, FinishedEventsForGroup) {
// Add two animations with the same group id but different durations.
std::unique_ptr<KeyframeModel> first_keyframe_model(KeyframeModel::Create(
- std::unique_ptr<AnimationCurve>(new FakeTransformTransition(2.0)), 1,
- group_id, TargetProperty::TRANSFORM));
+ std::unique_ptr<gfx::AnimationCurve>(new FakeTransformTransition(2.0)), 1,
+ group_id, KeyframeModel::TargetPropertyId(TargetProperty::TRANSFORM)));
first_keyframe_model->set_is_controlling_instance_for_test(true);
animation_impl_->AddKeyframeModel(std::move(first_keyframe_model));
std::unique_ptr<KeyframeModel> second_keyframe_model(KeyframeModel::Create(
- std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)),
- 2, group_id, TargetProperty::OPACITY));
+ std::unique_ptr<gfx::AnimationCurve>(
+ new FakeFloatTransition(1.0, 0.f, 1.f)),
+ 2, group_id, KeyframeModel::TargetPropertyId(TargetProperty::OPACITY)));
second_keyframe_model->set_is_controlling_instance_for_test(true);
animation_impl_->AddKeyframeModel(std::move(second_keyframe_model));
@@ -2166,14 +2202,15 @@ TEST_F(ElementAnimationsTest, FinishedAndAbortedEventsForGroup) {
// Add two animations with the same group id.
std::unique_ptr<KeyframeModel> first_keyframe_model(CreateKeyframeModel(
- std::unique_ptr<AnimationCurve>(new FakeTransformTransition(1.0)), 1,
+ std::unique_ptr<gfx::AnimationCurve>(new FakeTransformTransition(1.0)), 1,
TargetProperty::TRANSFORM));
first_keyframe_model->set_is_controlling_instance_for_test(true);
animation_impl_->AddKeyframeModel(std::move(first_keyframe_model));
- std::unique_ptr<KeyframeModel> second_keyframe_model(CreateKeyframeModel(
- std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)),
- 1, TargetProperty::OPACITY));
+ std::unique_ptr<KeyframeModel> second_keyframe_model(
+ CreateKeyframeModel(std::unique_ptr<gfx::AnimationCurve>(
+ new FakeFloatTransition(1.0, 0.f, 1.f)),
+ 1, TargetProperty::OPACITY));
second_keyframe_model->set_is_controlling_instance_for_test(true);
animation_impl_->AddKeyframeModel(std::move(second_keyframe_model));
@@ -2201,289 +2238,283 @@ TEST_F(ElementAnimationsTest, FinishedAndAbortedEventsForGroup) {
EXPECT_EQ(TargetProperty::OPACITY, events->events_[1].target_property);
}
-TEST_F(ElementAnimationsTest, GetAnimationScalesNotScaled) {
+TEST_F(ElementAnimationsTest, MaximumAnimationScaleNotScaled) {
CreateTestLayer(true, false);
AttachTimelineAnimationLayer();
CreateImplTimelineAndAnimation();
- float max_scale = 999;
- float start_scale = 999;
- EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales(
- ElementListType::PENDING, &max_scale, &start_scale));
- EXPECT_EQ(kNotScaled, max_scale);
- EXPECT_EQ(kNotScaled, start_scale);
- EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales(
- ElementListType::ACTIVE, &max_scale, &start_scale));
- EXPECT_EQ(kNotScaled, max_scale);
- EXPECT_EQ(kNotScaled, start_scale);
-
- animation_impl_->AddKeyframeModel(CreateKeyframeModel(
- std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)),
- 1, TargetProperty::OPACITY));
+ EXPECT_EQ(kInvalidScale,
+ element_animations_impl_->MaximumScale(ElementListType::PENDING));
+ EXPECT_EQ(kInvalidScale,
+ element_animations_impl_->MaximumScale(ElementListType::ACTIVE));
+
+ animation_impl_->AddKeyframeModel(
+ CreateKeyframeModel(std::unique_ptr<gfx::AnimationCurve>(
+ new FakeFloatTransition(1.0, 0.f, 1.f)),
+ 1, TargetProperty::OPACITY));
// Opacity animations aren't non-translation transforms.
- EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales(
- ElementListType::PENDING, &max_scale, &start_scale));
- EXPECT_EQ(kNotScaled, max_scale);
- EXPECT_EQ(kNotScaled, start_scale);
- EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales(
- ElementListType::ACTIVE, &max_scale, &start_scale));
- EXPECT_EQ(kNotScaled, max_scale);
- EXPECT_EQ(kNotScaled, start_scale);
-
- std::unique_ptr<KeyframedTransformAnimationCurve> curve1(
- KeyframedTransformAnimationCurve::Create());
-
- TransformOperations operations1;
+ EXPECT_EQ(kInvalidScale,
+ element_animations_impl_->MaximumScale(ElementListType::PENDING));
+ EXPECT_EQ(kInvalidScale,
+ element_animations_impl_->MaximumScale(ElementListType::ACTIVE));
+
+ std::unique_ptr<gfx::KeyframedTransformAnimationCurve> curve1(
+ gfx::KeyframedTransformAnimationCurve::Create());
+
+ gfx::TransformOperations operations1;
curve1->AddKeyframe(
- TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
+ gfx::TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
operations1.AppendTranslate(10.0, 15.0, 0.0);
- curve1->AddKeyframe(TransformKeyframe::Create(
+ curve1->AddKeyframe(gfx::TransformKeyframe::Create(
base::TimeDelta::FromSecondsD(1.0), operations1, nullptr));
std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create(
- std::move(curve1), 2, 2, TargetProperty::TRANSFORM));
+ std::move(curve1), 2, 2,
+ KeyframeModel::TargetPropertyId(TargetProperty::TRANSFORM)));
animation_impl_->AddKeyframeModel(std::move(keyframe_model));
// The only transform animation we've added is a translation.
- EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales(
- ElementListType::PENDING, &max_scale, &start_scale));
- EXPECT_EQ(kNotScaled, max_scale);
- EXPECT_EQ(kNotScaled, start_scale);
- EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales(
- ElementListType::ACTIVE, &max_scale, &start_scale));
- EXPECT_EQ(kNotScaled, max_scale);
- EXPECT_EQ(kNotScaled, start_scale);
+ EXPECT_EQ(1.f,
+ element_animations_impl_->MaximumScale(ElementListType::PENDING));
+ EXPECT_EQ(1.f,
+ element_animations_impl_->MaximumScale(ElementListType::ACTIVE));
}
-TEST_F(ElementAnimationsTest, GetAnimationScales) {
+TEST_F(ElementAnimationsTest, MaximumAnimationNonCalculatableScale) {
CreateTestLayer(true, false);
AttachTimelineAnimationLayer();
CreateImplTimelineAndAnimation();
- std::unique_ptr<KeyframedTransformAnimationCurve> curve1(
- KeyframedTransformAnimationCurve::Create());
+ std::unique_ptr<gfx::KeyframedTransformAnimationCurve> curve1(
+ gfx::KeyframedTransformAnimationCurve::Create());
+
+ gfx::TransformOperations operations1;
+ operations1.AppendScale(2.0, 2.0, 2.0);
+ operations1.AppendPerspective(100);
+ curve1->AddKeyframe(
+ gfx::TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
+ operations1.AppendTranslate(10.0, 15.0, 0.0);
+ curve1->AddKeyframe(gfx::TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(1.0), operations1, nullptr));
+
+ std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create(
+ std::move(curve1), 2, 2,
+ KeyframeModel::TargetPropertyId(TargetProperty::TRANSFORM)));
+ animation_impl_->AddKeyframeModel(std::move(keyframe_model));
+
+ // All keyframes have perspective, so the ElementAnimations' scale is not
+ // calculatable.
+ EXPECT_EQ(kInvalidScale,
+ element_animations_impl_->MaximumScale(ElementListType::PENDING));
+ EXPECT_EQ(kInvalidScale,
+ element_animations_impl_->MaximumScale(ElementListType::ACTIVE));
+}
- TransformOperations operations1a;
+TEST_F(ElementAnimationsTest, MaximumAnimationPartialNonCalculatableScale) {
+ CreateTestLayer(true, false);
+ AttachTimelineAnimationLayer();
+ CreateImplTimelineAndAnimation();
+
+ std::unique_ptr<gfx::KeyframedTransformAnimationCurve> curve1(
+ gfx::KeyframedTransformAnimationCurve::Create());
+
+ gfx::TransformOperations operations1;
+ operations1.AppendScale(2.0, 2.0, 2.0);
+ curve1->AddKeyframe(
+ gfx::TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
+ operations1.AppendPerspective(100);
+ curve1->AddKeyframe(gfx::TransformKeyframe::Create(
+ base::TimeDelta::FromSecondsD(1.0), operations1, nullptr));
+
+ std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create(
+ std::move(curve1), 2, 2,
+ KeyframeModel::TargetPropertyId(TargetProperty::TRANSFORM)));
+ animation_impl_->AddKeyframeModel(std::move(keyframe_model));
+
+ // Though some keyframes have perspective and the scale is not calculatable,
+ // we use the other keyframes to calculate the ElementAnimations' scale.
+ EXPECT_EQ(2.f,
+ element_animations_impl_->MaximumScale(ElementListType::PENDING));
+ EXPECT_EQ(2.f,
+ element_animations_impl_->MaximumScale(ElementListType::ACTIVE));
+}
+
+TEST_F(ElementAnimationsTest, MaximumScale) {
+ CreateTestLayer(true, false);
+ AttachTimelineAnimationLayer();
+ CreateImplTimelineAndAnimation();
+
+ std::unique_ptr<gfx::KeyframedTransformAnimationCurve> curve1(
+ gfx::KeyframedTransformAnimationCurve::Create());
+
+ gfx::TransformOperations operations1a;
operations1a.AppendScale(2.0, 3.0, 4.0);
curve1->AddKeyframe(
- TransformKeyframe::Create(base::TimeDelta(), operations1a, nullptr));
- TransformOperations operations1b;
+ gfx::TransformKeyframe::Create(base::TimeDelta(), operations1a, nullptr));
+ gfx::TransformOperations operations1b;
operations1b.AppendScale(5.0, 4.0, 3.0);
- curve1->AddKeyframe(TransformKeyframe::Create(
+ curve1->AddKeyframe(gfx::TransformKeyframe::Create(
base::TimeDelta::FromSecondsD(1.0), operations1b, nullptr));
std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create(
- std::move(curve1), 1, 1, TargetProperty::TRANSFORM));
+ std::move(curve1), 1, 1,
+ KeyframeModel::TargetPropertyId(TargetProperty::TRANSFORM)));
keyframe_model->set_affects_active_elements(false);
animation_impl_->AddKeyframeModel(std::move(keyframe_model));
- float max_scale = kNotScaled;
- float start_scale = kNotScaled;
- EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales(
- ElementListType::PENDING, &max_scale, &start_scale));
- EXPECT_EQ(5.f, max_scale);
- EXPECT_EQ(4.f, start_scale);
- EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales(
- ElementListType::ACTIVE, &max_scale, &start_scale));
- EXPECT_EQ(kNotScaled, max_scale);
- EXPECT_EQ(kNotScaled, start_scale);
+ EXPECT_EQ(5.f,
+ element_animations_impl_->MaximumScale(ElementListType::PENDING));
+ EXPECT_EQ(kInvalidScale,
+ element_animations_impl_->MaximumScale(ElementListType::ACTIVE));
animation_impl_->ActivateKeyframeModels();
- EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales(
- ElementListType::PENDING, &max_scale, &start_scale));
- EXPECT_EQ(5.f, max_scale);
- EXPECT_EQ(4.f, start_scale);
- EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales(
- ElementListType::ACTIVE, &max_scale, &start_scale));
- EXPECT_EQ(5.f, max_scale);
- EXPECT_EQ(4.f, start_scale);
-
- std::unique_ptr<KeyframedTransformAnimationCurve> curve2(
- KeyframedTransformAnimationCurve::Create());
-
- TransformOperations operations2a;
+ EXPECT_EQ(5.f,
+ element_animations_impl_->MaximumScale(ElementListType::PENDING));
+ EXPECT_EQ(5.f,
+ element_animations_impl_->MaximumScale(ElementListType::ACTIVE));
+
+ std::unique_ptr<gfx::KeyframedTransformAnimationCurve> curve2(
+ gfx::KeyframedTransformAnimationCurve::Create());
+
+ gfx::TransformOperations operations2a;
operations2a.AppendScale(1.0, 2.0, 3.0);
curve2->AddKeyframe(
- TransformKeyframe::Create(base::TimeDelta(), operations2a, nullptr));
- TransformOperations operations2b;
+ gfx::TransformKeyframe::Create(base::TimeDelta(), operations2a, nullptr));
+ gfx::TransformOperations operations2b;
operations2b.AppendScale(6.0, 5.0, 4.0);
- curve2->AddKeyframe(TransformKeyframe::Create(
+ curve2->AddKeyframe(gfx::TransformKeyframe::Create(
base::TimeDelta::FromSecondsD(1.0), operations2b, nullptr));
animation_impl_->RemoveKeyframeModel(1);
- keyframe_model =
- KeyframeModel::Create(std::move(curve2), 2, 2, TargetProperty::TRANSFORM);
+ keyframe_model = KeyframeModel::Create(
+ std::move(curve2), 2, 2,
+ KeyframeModel::TargetPropertyId(TargetProperty::TRANSFORM));
// Reverse Direction
keyframe_model->set_direction(KeyframeModel::Direction::REVERSE);
keyframe_model->set_affects_active_elements(false);
animation_impl_->AddKeyframeModel(std::move(keyframe_model));
- std::unique_ptr<KeyframedTransformAnimationCurve> curve3(
- KeyframedTransformAnimationCurve::Create());
+ std::unique_ptr<gfx::KeyframedTransformAnimationCurve> curve3(
+ gfx::KeyframedTransformAnimationCurve::Create());
- TransformOperations operations3a;
+ gfx::TransformOperations operations3a;
operations3a.AppendScale(5.0, 3.0, 1.0);
curve3->AddKeyframe(
- TransformKeyframe::Create(base::TimeDelta(), operations3a, nullptr));
- TransformOperations operations3b;
+ gfx::TransformKeyframe::Create(base::TimeDelta(), operations3a, nullptr));
+ gfx::TransformOperations operations3b;
operations3b.AppendScale(1.5, 2.5, 3.5);
- curve3->AddKeyframe(TransformKeyframe::Create(
+ curve3->AddKeyframe(gfx::TransformKeyframe::Create(
base::TimeDelta::FromSecondsD(1.0), operations3b, nullptr));
- keyframe_model =
- KeyframeModel::Create(std::move(curve3), 3, 3, TargetProperty::TRANSFORM);
+ keyframe_model = KeyframeModel::Create(
+ std::move(curve3), 3, 3,
+ KeyframeModel::TargetPropertyId(TargetProperty::TRANSFORM));
keyframe_model->set_affects_active_elements(false);
animation_impl_->AddKeyframeModel(std::move(keyframe_model));
- EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales(
- ElementListType::PENDING, &max_scale, &start_scale));
- EXPECT_EQ(3.5f, max_scale);
- EXPECT_EQ(6.f, start_scale);
- EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales(
- ElementListType::ACTIVE, &max_scale, &start_scale));
- EXPECT_EQ(kNotScaled, max_scale);
- EXPECT_EQ(kNotScaled, start_scale);
+ EXPECT_EQ(6.f,
+ element_animations_impl_->MaximumScale(ElementListType::PENDING));
+ EXPECT_EQ(kInvalidScale,
+ element_animations_impl_->MaximumScale(ElementListType::ACTIVE));
animation_impl_->ActivateKeyframeModels();
- EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales(
- ElementListType::PENDING, &max_scale, &start_scale));
- EXPECT_EQ(3.5f, max_scale);
- EXPECT_EQ(6.f, start_scale);
- EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales(
- ElementListType::ACTIVE, &max_scale, &start_scale));
- EXPECT_EQ(3.5f, max_scale);
- EXPECT_EQ(6.f, start_scale);
+ EXPECT_EQ(6.f,
+ element_animations_impl_->MaximumScale(ElementListType::PENDING));
+ EXPECT_EQ(6.f,
+ element_animations_impl_->MaximumScale(ElementListType::ACTIVE));
animation_impl_->keyframe_effect()->GetKeyframeModelById(2)->SetRunState(
KeyframeModel::FINISHED, TicksFromSecondsF(0.0));
- // Only unfinished animations should be considered by GetAnimationScales.
- EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales(
- ElementListType::PENDING, &max_scale, &start_scale));
- EXPECT_EQ(3.5f, max_scale);
- EXPECT_EQ(5.f, start_scale);
- EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales(
- ElementListType::ACTIVE, &max_scale, &start_scale));
- EXPECT_EQ(3.5f, max_scale);
- EXPECT_EQ(5.f, start_scale);
+ // Only unfinished animations should be considered by MaximumAnimationScale.
+ EXPECT_EQ(5.f,
+ element_animations_impl_->MaximumScale(ElementListType::PENDING));
+ EXPECT_EQ(5.f,
+ element_animations_impl_->MaximumScale(ElementListType::ACTIVE));
}
-TEST_F(ElementAnimationsTest, GetAnimationScalesWithDirection) {
+TEST_F(ElementAnimationsTest, MaximumAnimationScaleWithDirection) {
CreateTestLayer(true, false);
AttachTimelineAnimationLayer();
CreateImplTimelineAndAnimation();
- std::unique_ptr<KeyframedTransformAnimationCurve> curve1(
- KeyframedTransformAnimationCurve::Create());
- TransformOperations operations1;
+ std::unique_ptr<gfx::KeyframedTransformAnimationCurve> curve1(
+ gfx::KeyframedTransformAnimationCurve::Create());
+ gfx::TransformOperations operations1;
operations1.AppendScale(1.0, 2.0, 3.0);
curve1->AddKeyframe(
- TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
- TransformOperations operations2;
+ gfx::TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
+ gfx::TransformOperations operations2;
operations2.AppendScale(4.0, 5.0, 6.0);
- curve1->AddKeyframe(TransformKeyframe::Create(
+ curve1->AddKeyframe(gfx::TransformKeyframe::Create(
base::TimeDelta::FromSecondsD(1.0), operations2, nullptr));
std::unique_ptr<KeyframeModel> keyframe_model_owned(KeyframeModel::Create(
- std::move(curve1), 1, 1, TargetProperty::TRANSFORM));
+ std::move(curve1), 1, 1,
+ KeyframeModel::TargetPropertyId(TargetProperty::TRANSFORM)));
KeyframeModel* keyframe_model = keyframe_model_owned.get();
animation_impl_->AddKeyframeModel(std::move(keyframe_model_owned));
- float max_scale = 999;
- float start_scale = 999;
-
EXPECT_GT(keyframe_model->playback_rate(), 0.0);
// NORMAL direction with positive playback rate.
keyframe_model->set_direction(KeyframeModel::Direction::NORMAL);
- EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales(
- ElementListType::PENDING, &max_scale, &start_scale));
- EXPECT_EQ(6.f, max_scale);
- EXPECT_EQ(3.f, start_scale);
- EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales(
- ElementListType::ACTIVE, &max_scale, &start_scale));
- EXPECT_EQ(6.f, max_scale);
- EXPECT_EQ(3.f, start_scale);
+ EXPECT_EQ(6.f,
+ element_animations_impl_->MaximumScale(ElementListType::PENDING));
+ EXPECT_EQ(6.f,
+ element_animations_impl_->MaximumScale(ElementListType::ACTIVE));
// ALTERNATE direction with positive playback rate.
keyframe_model->set_direction(KeyframeModel::Direction::ALTERNATE_NORMAL);
- EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales(
- ElementListType::PENDING, &max_scale, &start_scale));
- EXPECT_EQ(6.f, max_scale);
- EXPECT_EQ(3.f, start_scale);
- EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales(
- ElementListType::ACTIVE, &max_scale, &start_scale));
- EXPECT_EQ(6.f, max_scale);
- EXPECT_EQ(3.f, start_scale);
+ EXPECT_EQ(6.f,
+ element_animations_impl_->MaximumScale(ElementListType::PENDING));
+ EXPECT_EQ(6.f,
+ element_animations_impl_->MaximumScale(ElementListType::ACTIVE));
// REVERSE direction with positive playback rate.
keyframe_model->set_direction(KeyframeModel::Direction::REVERSE);
- EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales(
- ElementListType::PENDING, &max_scale, &start_scale));
- EXPECT_EQ(3.f, max_scale);
- EXPECT_EQ(6.f, start_scale);
- EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales(
- ElementListType::ACTIVE, &max_scale, &start_scale));
- EXPECT_EQ(3.f, max_scale);
- EXPECT_EQ(6.f, start_scale);
+ EXPECT_EQ(6.f,
+ element_animations_impl_->MaximumScale(ElementListType::PENDING));
+ EXPECT_EQ(6.f,
+ element_animations_impl_->MaximumScale(ElementListType::ACTIVE));
// ALTERNATE reverse direction.
keyframe_model->set_direction(KeyframeModel::Direction::REVERSE);
- EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales(
- ElementListType::PENDING, &max_scale, &start_scale));
- EXPECT_EQ(3.f, max_scale);
- EXPECT_EQ(6.f, start_scale);
- EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales(
- ElementListType::ACTIVE, &max_scale, &start_scale));
- EXPECT_EQ(3.f, max_scale);
- EXPECT_EQ(6.f, start_scale);
+ EXPECT_EQ(6.f,
+ element_animations_impl_->MaximumScale(ElementListType::PENDING));
+ EXPECT_EQ(6.f,
+ element_animations_impl_->MaximumScale(ElementListType::ACTIVE));
keyframe_model->set_playback_rate(-1.0);
// NORMAL direction with negative playback rate.
keyframe_model->set_direction(KeyframeModel::Direction::NORMAL);
- EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales(
- ElementListType::PENDING, &max_scale, &start_scale));
- EXPECT_EQ(3.f, max_scale);
- EXPECT_EQ(6.f, start_scale);
- EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales(
- ElementListType::ACTIVE, &max_scale, &start_scale));
- EXPECT_EQ(3.f, max_scale);
- EXPECT_EQ(6.f, start_scale);
+ EXPECT_EQ(6.f,
+ element_animations_impl_->MaximumScale(ElementListType::PENDING));
+ EXPECT_EQ(6.f,
+ element_animations_impl_->MaximumScale(ElementListType::ACTIVE));
// ALTERNATE direction with negative playback rate.
keyframe_model->set_direction(KeyframeModel::Direction::ALTERNATE_NORMAL);
- EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales(
- ElementListType::PENDING, &max_scale, &start_scale));
- EXPECT_EQ(3.f, max_scale);
- EXPECT_EQ(6.f, start_scale);
- EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales(
- ElementListType::ACTIVE, &max_scale, &start_scale));
- EXPECT_EQ(3.f, max_scale);
- EXPECT_EQ(6.f, start_scale);
+ EXPECT_EQ(6.f,
+ element_animations_impl_->MaximumScale(ElementListType::PENDING));
+ EXPECT_EQ(6.f,
+ element_animations_impl_->MaximumScale(ElementListType::ACTIVE));
// REVERSE direction with negative playback rate.
keyframe_model->set_direction(KeyframeModel::Direction::REVERSE);
- EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales(
- ElementListType::PENDING, &max_scale, &start_scale));
- EXPECT_EQ(6.f, max_scale);
- EXPECT_EQ(3.f, start_scale);
- EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales(
- ElementListType::ACTIVE, &max_scale, &start_scale));
- EXPECT_EQ(6.f, max_scale);
- EXPECT_EQ(3.f, start_scale);
+ EXPECT_EQ(6.f,
+ element_animations_impl_->MaximumScale(ElementListType::PENDING));
+ EXPECT_EQ(6.f,
+ element_animations_impl_->MaximumScale(ElementListType::ACTIVE));
// ALTERNATE reverse direction with negative playback rate.
keyframe_model->set_direction(KeyframeModel::Direction::REVERSE);
- EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales(
- ElementListType::PENDING, &max_scale, &start_scale));
- EXPECT_EQ(6.f, max_scale);
- EXPECT_EQ(3.f, start_scale);
- EXPECT_TRUE(animation_impl_->keyframe_effect()->GetAnimationScales(
- ElementListType::ACTIVE, &max_scale, &start_scale));
- EXPECT_EQ(6.f, max_scale);
- EXPECT_EQ(3.f, start_scale);
+ EXPECT_EQ(6.f,
+ element_animations_impl_->MaximumScale(ElementListType::PENDING));
+ EXPECT_EQ(6.f,
+ element_animations_impl_->MaximumScale(ElementListType::ACTIVE));
}
TEST_F(ElementAnimationsTest, NewlyPushedAnimationWaitsForActivation) {
@@ -3689,9 +3720,10 @@ TEST_F(ElementAnimationsTest, TestIsCurrentlyAnimatingProperty) {
AttachTimelineAnimationLayer();
// Create an animation that initially affects only pending elements.
- std::unique_ptr<KeyframeModel> keyframe_model(CreateKeyframeModel(
- std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)),
- 1, TargetProperty::OPACITY));
+ std::unique_ptr<KeyframeModel> keyframe_model(
+ CreateKeyframeModel(std::unique_ptr<gfx::AnimationCurve>(
+ new FakeFloatTransition(1.0, 0.f, 1.f)),
+ 1, TargetProperty::OPACITY));
keyframe_model->set_affects_active_elements(false);
animation_->AddKeyframeModel(std::move(keyframe_model));
@@ -3759,9 +3791,10 @@ TEST_F(ElementAnimationsTest, TestIsAnimatingPropertyTimeOffsetFillMode) {
// Create an animation that initially affects only pending elements, and has
// a start delay of 2 seconds.
- std::unique_ptr<KeyframeModel> keyframe_model(CreateKeyframeModel(
- std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)),
- 1, TargetProperty::OPACITY));
+ std::unique_ptr<KeyframeModel> keyframe_model(
+ CreateKeyframeModel(std::unique_ptr<gfx::AnimationCurve>(
+ new FakeFloatTransition(1.0, 0.f, 1.f)),
+ 1, TargetProperty::OPACITY));
keyframe_model->set_fill_mode(KeyframeModel::FillMode::NONE);
keyframe_model->set_time_offset(TimeDelta::FromMilliseconds(-2000));
keyframe_model->set_affects_active_elements(false);
@@ -3837,9 +3870,10 @@ TEST_F(ElementAnimationsTest, DestroyTestMainLayerBeforePushProperties) {
AttachTimelineAnimationLayer();
EXPECT_EQ(0u, host_->ticking_animations_for_testing().size());
- animation_->AddKeyframeModel(CreateKeyframeModel(
- std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 1.f, 0.5f)),
- 2, TargetProperty::OPACITY));
+ animation_->AddKeyframeModel(
+ CreateKeyframeModel(std::unique_ptr<gfx::AnimationCurve>(
+ new FakeFloatTransition(1.0, 1.f, 0.5f)),
+ 2, TargetProperty::OPACITY));
EXPECT_EQ(1u, host_->ticking_animations_for_testing().size());
DestroyTestMainLayer();
@@ -3859,18 +3893,20 @@ TEST_F(ElementAnimationsTest, RemoveAndReAddAnimationToTicking) {
// Add an animation and ensure the animation is in the host's ticking
// animations. Remove the animation using RemoveFromTicking().
- animation_->AddKeyframeModel(CreateKeyframeModel(
- std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 1.f, 0.5f)),
- 1, TargetProperty::OPACITY));
+ animation_->AddKeyframeModel(
+ CreateKeyframeModel(std::unique_ptr<gfx::AnimationCurve>(
+ new FakeFloatTransition(1.0, 1.f, 0.5f)),
+ 1, TargetProperty::OPACITY));
ASSERT_EQ(1u, host_->ticking_animations_for_testing().size());
animation_->keyframe_effect()->RemoveFromTicking();
ASSERT_EQ(0u, host_->ticking_animations_for_testing().size());
// Ensure that adding a new animation will correctly update the ticking
// animations list.
- animation_->AddKeyframeModel(CreateKeyframeModel(
- std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 1.f, 0.5f)),
- 2, TargetProperty::OPACITY));
+ animation_->AddKeyframeModel(
+ CreateKeyframeModel(std::unique_ptr<gfx::AnimationCurve>(
+ new FakeFloatTransition(1.0, 1.f, 0.5f)),
+ 2, TargetProperty::OPACITY));
EXPECT_EQ(1u, host_->ticking_animations_for_testing().size());
}
@@ -3882,11 +3918,12 @@ TEST_F(ElementAnimationsTest, FinishedKeyframeModelsNotCopiedToImpl) {
CreateImplTimelineAndAnimation();
animation_->AddKeyframeModel(KeyframeModel::Create(
- std::unique_ptr<AnimationCurve>(new FakeTransformTransition(1.0)), 1, 1,
- TargetProperty::TRANSFORM));
+ std::unique_ptr<gfx::AnimationCurve>(new FakeTransformTransition(1.0)), 1,
+ 1, KeyframeModel::TargetPropertyId(TargetProperty::TRANSFORM)));
animation_->AddKeyframeModel(KeyframeModel::Create(
- std::unique_ptr<AnimationCurve>(new FakeFloatTransition(2.0, 0.f, 1.f)),
- 2, 2, TargetProperty::OPACITY));
+ std::unique_ptr<gfx::AnimationCurve>(
+ new FakeFloatTransition(2.0, 0.f, 1.f)),
+ 2, 2, KeyframeModel::TargetPropertyId(TargetProperty::OPACITY)));
// Finish the first keyframe model.
animation_->Tick(kInitialTickTime);
@@ -3908,5 +3945,30 @@ TEST_F(ElementAnimationsTest, FinishedKeyframeModelsNotCopiedToImpl) {
EXPECT_TRUE(animation_impl_->keyframe_effect()->GetKeyframeModelById(2));
}
+TEST_F(ElementAnimationsTest, ClientAnimationState) {
+ client_.RegisterElementId(element_id_, ElementListType::ACTIVE);
+ AttachTimelineAnimationLayer();
+ CreateImplTimelineAndAnimation();
+
+ animation_->AddKeyframeModel(KeyframeModel::Create(
+ std::make_unique<FakeTransformTransition>(1.0), 1, 1,
+ KeyframeModel::TargetPropertyId(TargetProperty::TRANSFORM)));
+
+ auto* layer = client_.FindTestLayer(element_id_, ElementListType::ACTIVE);
+ EXPECT_TRUE(layer->is_currently_animating(TargetProperty::TRANSFORM));
+ EXPECT_EQ(1.f, layer->maximum_animation_scale());
+
+ // The client resets the cached data, simulating a property rebuild or a
+ // property push with different values.
+ layer->set_is_currently_animating(TargetProperty::TRANSFORM, false);
+ layer->set_maximum_animation_scale(kInvalidScale);
+
+ // The client should call this function which should refresh all data of the
+ // client.
+ element_animations_->InitClientAnimationState();
+ EXPECT_TRUE(layer->is_currently_animating(TargetProperty::TRANSFORM));
+ EXPECT_EQ(1.f, layer->maximum_animation_scale());
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/animation/filter_animation_curve.cc b/chromium/cc/animation/filter_animation_curve.cc
new file mode 100644
index 00000000000..83d991c0662
--- /dev/null
+++ b/chromium/cc/animation/filter_animation_curve.cc
@@ -0,0 +1,206 @@
+// Copyright 2021 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/animation/filter_animation_curve.h"
+
+#include "base/memory/ptr_util.h"
+
+namespace cc {
+
+// TODO(crbug.com/747185): All code in this namespace duplicates code from
+// ui/gfx/keyframe/animation/ unnecessarily.
+namespace {
+
+template <class KeyframeType>
+void InsertKeyframe(std::unique_ptr<KeyframeType> keyframe,
+ std::vector<std::unique_ptr<KeyframeType>>* keyframes) {
+ // Usually, the keyframes will be added in order, so this loop would be
+ // unnecessary and we should skip it if possible.
+ if (!keyframes->empty() && keyframe->Time() < keyframes->back()->Time()) {
+ for (size_t i = 0; i < keyframes->size(); ++i) {
+ if (keyframe->Time() < keyframes->at(i)->Time()) {
+ keyframes->insert(keyframes->begin() + i, std::move(keyframe));
+ return;
+ }
+ }
+ }
+
+ keyframes->push_back(std::move(keyframe));
+}
+
+struct TimeValues {
+ base::TimeDelta start_time;
+ base::TimeDelta duration;
+ double progress;
+};
+
+template <typename KeyframeType>
+TimeValues GetTimeValues(const KeyframeType& start_frame,
+ const KeyframeType& end_frame,
+ double scaled_duration,
+ base::TimeDelta time) {
+ TimeValues values;
+ values.start_time = start_frame.Time() * scaled_duration;
+ values.duration = (end_frame.Time() * scaled_duration) - values.start_time;
+ const base::TimeDelta elapsed = time - values.start_time;
+ values.progress = (elapsed.is_inf() || values.duration.is_zero())
+ ? 1.0
+ : (elapsed / values.duration);
+ return values;
+}
+
+template <typename KeyframeType>
+base::TimeDelta TransformedAnimationTime(
+ const std::vector<std::unique_ptr<KeyframeType>>& keyframes,
+ const std::unique_ptr<gfx::TimingFunction>& timing_function,
+ double scaled_duration,
+ base::TimeDelta time) {
+ if (timing_function) {
+ const auto values = GetTimeValues(*keyframes.front(), *keyframes.back(),
+ scaled_duration, time);
+ time = (values.duration * timing_function->GetValue(values.progress)) +
+ values.start_time;
+ }
+
+ return time;
+}
+
+template <typename KeyframeType>
+size_t GetActiveKeyframe(
+ const std::vector<std::unique_ptr<KeyframeType>>& keyframes,
+ double scaled_duration,
+ base::TimeDelta time) {
+ DCHECK_GE(keyframes.size(), 2ul);
+ size_t i = 0;
+ while ((i < keyframes.size() - 2) && // Last keyframe is never active.
+ (time >= (keyframes[i + 1]->Time() * scaled_duration)))
+ ++i;
+
+ return i;
+}
+
+template <typename KeyframeType>
+double TransformedKeyframeProgress(
+ const std::vector<std::unique_ptr<KeyframeType>>& keyframes,
+ double scaled_duration,
+ base::TimeDelta time,
+ size_t i) {
+ const double progress =
+ GetTimeValues(*keyframes[i], *keyframes[i + 1], scaled_duration, time)
+ .progress;
+ return keyframes[i]->timing_function()
+ ? keyframes[i]->timing_function()->GetValue(progress)
+ : progress;
+}
+
+} // namespace
+
+void FilterAnimationCurve::Tick(base::TimeDelta t,
+ int property_id,
+ gfx::KeyframeModel* keyframe_model) const {
+ if (target_) {
+ target_->OnFilterAnimated(GetValue(t), property_id, keyframe_model);
+ }
+}
+
+int FilterAnimationCurve::Type() const {
+ return gfx::AnimationCurve::FILTER;
+}
+
+const char* FilterAnimationCurve::TypeName() const {
+ return "Filter";
+}
+
+const FilterAnimationCurve* FilterAnimationCurve::ToFilterAnimationCurve(
+ const gfx::AnimationCurve* c) {
+ DCHECK_EQ(gfx::AnimationCurve::FILTER, c->Type());
+ return static_cast<const FilterAnimationCurve*>(c);
+}
+
+FilterAnimationCurve* FilterAnimationCurve::ToFilterAnimationCurve(
+ gfx::AnimationCurve* c) {
+ DCHECK_EQ(AnimationCurve::FILTER, c->Type());
+ return static_cast<FilterAnimationCurve*>(c);
+}
+
+std::unique_ptr<FilterKeyframe> FilterKeyframe::Create(
+ base::TimeDelta time,
+ const FilterOperations& value,
+ std::unique_ptr<gfx::TimingFunction> timing_function) {
+ return base::WrapUnique(
+ new FilterKeyframe(time, value, std::move(timing_function)));
+}
+
+FilterKeyframe::FilterKeyframe(
+ base::TimeDelta time,
+ const FilterOperations& value,
+ std::unique_ptr<gfx::TimingFunction> timing_function)
+ : Keyframe(time, std::move(timing_function)), value_(value) {}
+
+FilterKeyframe::~FilterKeyframe() = default;
+
+const FilterOperations& FilterKeyframe::Value() const {
+ return value_;
+}
+
+std::unique_ptr<FilterKeyframe> FilterKeyframe::Clone() const {
+ std::unique_ptr<gfx::TimingFunction> func;
+ if (timing_function())
+ func = timing_function()->Clone();
+ return FilterKeyframe::Create(Time(), Value(), std::move(func));
+}
+
+void KeyframedFilterAnimationCurve::AddKeyframe(
+ std::unique_ptr<FilterKeyframe> keyframe) {
+ InsertKeyframe(std::move(keyframe), &keyframes_);
+}
+
+base::TimeDelta KeyframedFilterAnimationCurve::Duration() const {
+ return (keyframes_.back()->Time() - keyframes_.front()->Time()) *
+ scaled_duration();
+}
+
+std::unique_ptr<gfx::AnimationCurve> KeyframedFilterAnimationCurve::Clone()
+ const {
+ std::unique_ptr<KeyframedFilterAnimationCurve> to_return =
+ KeyframedFilterAnimationCurve::Create();
+ for (const auto& keyframe : keyframes_)
+ to_return->AddKeyframe(keyframe->Clone());
+
+ if (timing_function_)
+ to_return->SetTimingFunction(timing_function_->Clone());
+
+ to_return->set_scaled_duration(scaled_duration());
+
+ return std::move(to_return);
+}
+
+FilterOperations KeyframedFilterAnimationCurve::GetValue(
+ base::TimeDelta t) const {
+ if (t <= (keyframes_.front()->Time() * scaled_duration()))
+ return keyframes_.front()->Value();
+
+ if (t >= (keyframes_.back()->Time() * scaled_duration()))
+ return keyframes_.back()->Value();
+
+ t = TransformedAnimationTime(keyframes_, timing_function_, scaled_duration(),
+ t);
+ size_t i = GetActiveKeyframe(keyframes_, scaled_duration(), t);
+ double progress =
+ TransformedKeyframeProgress(keyframes_, scaled_duration(), t, i);
+
+ return keyframes_[i + 1]->Value().Blend(keyframes_[i]->Value(), progress);
+}
+
+std::unique_ptr<KeyframedFilterAnimationCurve>
+KeyframedFilterAnimationCurve::Create() {
+ return base::WrapUnique(new KeyframedFilterAnimationCurve);
+}
+
+KeyframedFilterAnimationCurve::KeyframedFilterAnimationCurve()
+ : scaled_duration_(1.0) {}
+
+KeyframedFilterAnimationCurve::~KeyframedFilterAnimationCurve() = default;
+
+} // namespace cc
diff --git a/chromium/cc/animation/filter_animation_curve.h b/chromium/cc/animation/filter_animation_curve.h
new file mode 100644
index 00000000000..0455d67df19
--- /dev/null
+++ b/chromium/cc/animation/filter_animation_curve.h
@@ -0,0 +1,83 @@
+// Copyright 2021 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_ANIMATION_FILTER_ANIMATION_CURVE_H_
+#define CC_ANIMATION_FILTER_ANIMATION_CURVE_H_
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "ui/gfx/animation/keyframe/keyframed_animation_curve.h"
+
+#include "cc/animation/animation_export.h"
+#include "cc/paint/filter_operations.h"
+
+namespace cc {
+
+class CC_ANIMATION_EXPORT FilterAnimationCurve : public gfx::AnimationCurve {
+ DECLARE_ANIMATION_CURVE_BODY(FilterOperations, Filter)
+};
+
+class CC_ANIMATION_EXPORT FilterKeyframe : public gfx::Keyframe {
+ public:
+ static std::unique_ptr<FilterKeyframe> Create(
+ base::TimeDelta time,
+ const FilterOperations& value,
+ std::unique_ptr<gfx::TimingFunction> timing_function);
+ ~FilterKeyframe() override;
+
+ const FilterOperations& Value() const;
+
+ std::unique_ptr<FilterKeyframe> Clone() const;
+
+ private:
+ FilterKeyframe(base::TimeDelta time,
+ const FilterOperations& value,
+ std::unique_ptr<gfx::TimingFunction> timing_function);
+
+ FilterOperations value_;
+};
+
+class CC_ANIMATION_EXPORT KeyframedFilterAnimationCurve
+ : public FilterAnimationCurve {
+ public:
+ // It is required that the keyframes be sorted by time.
+ static std::unique_ptr<KeyframedFilterAnimationCurve> Create();
+
+ KeyframedFilterAnimationCurve(const KeyframedFilterAnimationCurve&) = delete;
+ ~KeyframedFilterAnimationCurve() override;
+
+ KeyframedFilterAnimationCurve& operator=(
+ const KeyframedFilterAnimationCurve&) = delete;
+
+ void AddKeyframe(std::unique_ptr<FilterKeyframe> keyframe);
+ void SetTimingFunction(std::unique_ptr<gfx::TimingFunction> timing_function) {
+ timing_function_ = std::move(timing_function);
+ }
+ double scaled_duration() const { return scaled_duration_; }
+ void set_scaled_duration(double scaled_duration) {
+ scaled_duration_ = scaled_duration;
+ }
+
+ // AnimationCurve implementation
+ base::TimeDelta Duration() const override;
+ std::unique_ptr<gfx::AnimationCurve> Clone() const override;
+
+ // FilterAnimationCurve implementation
+ FilterOperations GetValue(base::TimeDelta t) const override;
+
+ private:
+ KeyframedFilterAnimationCurve();
+
+ // Always sorted in order of increasing time. No two keyframes have the
+ // same time.
+ std::vector<std::unique_ptr<FilterKeyframe>> keyframes_;
+ std::unique_ptr<gfx::TimingFunction> timing_function_;
+ double scaled_duration_;
+};
+
+} // namespace cc
+
+#endif // CC_ANIMATION_FILTER_ANIMATION_CURVE_H_
diff --git a/chromium/cc/animation/filter_animation_curve_unittest.cc b/chromium/cc/animation/filter_animation_curve_unittest.cc
new file mode 100644
index 00000000000..e7401a78a11
--- /dev/null
+++ b/chromium/cc/animation/filter_animation_curve_unittest.cc
@@ -0,0 +1,127 @@
+// Copyright 2012 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/animation/filter_animation_curve.h"
+
+#include <memory>
+
+#include "cc/test/geometry_test_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/animation/tween.h"
+#include "ui/gfx/geometry/box_f.h"
+#include "ui/gfx/test/gfx_util.h"
+#include "ui/gfx/transform_operations.h"
+
+namespace cc {
+namespace {
+
+void ExpectBrightness(double brightness, const FilterOperations& filter) {
+ EXPECT_EQ(1u, filter.size());
+ EXPECT_EQ(FilterOperation::BRIGHTNESS, filter.at(0).type());
+ EXPECT_FLOAT_EQ(brightness, filter.at(0).amount());
+}
+
+// Tests that a filter animation with one keyframe works as expected.
+TEST(KeyframedAnimationCurveTest, OneFilterKeyframe) {
+ std::unique_ptr<KeyframedFilterAnimationCurve> curve(
+ KeyframedFilterAnimationCurve::Create());
+ FilterOperations operations;
+ operations.Append(FilterOperation::CreateBrightnessFilter(2.f));
+ curve->AddKeyframe(
+ FilterKeyframe::Create(base::TimeDelta(), operations, nullptr));
+
+ ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+ ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+ ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+}
+
+// Tests that a filter animation with two keyframes works as expected.
+TEST(KeyframedAnimationCurveTest, TwoFilterKeyframe) {
+ std::unique_ptr<KeyframedFilterAnimationCurve> curve(
+ KeyframedFilterAnimationCurve::Create());
+ FilterOperations operations1;
+ operations1.Append(FilterOperation::CreateBrightnessFilter(2.f));
+ FilterOperations operations2;
+ operations2.Append(FilterOperation::CreateBrightnessFilter(4.f));
+
+ curve->AddKeyframe(
+ FilterKeyframe::Create(base::TimeDelta(), operations1, nullptr));
+ curve->AddKeyframe(FilterKeyframe::Create(base::TimeDelta::FromSecondsD(1.f),
+ operations2, nullptr));
+ ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ ExpectBrightness(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+ ExpectBrightness(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+ ExpectBrightness(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+}
+
+// Tests that a filter animation with three keyframes works as expected.
+TEST(KeyframedAnimationCurveTest, ThreeFilterKeyframe) {
+ std::unique_ptr<KeyframedFilterAnimationCurve> curve(
+ KeyframedFilterAnimationCurve::Create());
+ FilterOperations operations1;
+ operations1.Append(FilterOperation::CreateBrightnessFilter(2.f));
+ FilterOperations operations2;
+ operations2.Append(FilterOperation::CreateBrightnessFilter(4.f));
+ FilterOperations operations3;
+ operations3.Append(FilterOperation::CreateBrightnessFilter(8.f));
+ curve->AddKeyframe(
+ FilterKeyframe::Create(base::TimeDelta(), operations1, nullptr));
+ curve->AddKeyframe(FilterKeyframe::Create(base::TimeDelta::FromSecondsD(1.f),
+ operations2, nullptr));
+ curve->AddKeyframe(FilterKeyframe::Create(base::TimeDelta::FromSecondsD(2.f),
+ operations3, nullptr));
+ ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ ExpectBrightness(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+ ExpectBrightness(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+ ExpectBrightness(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
+ ExpectBrightness(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+ ExpectBrightness(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
+}
+
+// Tests that a filter animation with multiple keys at a given time works
+// sanely.
+TEST(KeyframedAnimationCurveTest, RepeatedFilterKeyTimes) {
+ std::unique_ptr<KeyframedFilterAnimationCurve> curve(
+ KeyframedFilterAnimationCurve::Create());
+ // A step function.
+ FilterOperations operations1;
+ operations1.Append(FilterOperation::CreateBrightnessFilter(4.f));
+ FilterOperations operations2;
+ operations2.Append(FilterOperation::CreateBrightnessFilter(4.f));
+ FilterOperations operations3;
+ operations3.Append(FilterOperation::CreateBrightnessFilter(6.f));
+ FilterOperations operations4;
+ operations4.Append(FilterOperation::CreateBrightnessFilter(6.f));
+ curve->AddKeyframe(
+ FilterKeyframe::Create(base::TimeDelta(), operations1, nullptr));
+ curve->AddKeyframe(FilterKeyframe::Create(base::TimeDelta::FromSecondsD(1.f),
+ operations2, nullptr));
+ curve->AddKeyframe(FilterKeyframe::Create(base::TimeDelta::FromSecondsD(1.f),
+ operations3, nullptr));
+ curve->AddKeyframe(FilterKeyframe::Create(base::TimeDelta::FromSecondsD(2.f),
+ operations4, nullptr));
+
+ ExpectBrightness(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+ ExpectBrightness(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+ ExpectBrightness(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+
+ // There is a discontinuity at 1. Any value between 4 and 6 is valid.
+ FilterOperations value = curve->GetValue(base::TimeDelta::FromSecondsD(1.f));
+ EXPECT_EQ(1u, value.size());
+ EXPECT_EQ(FilterOperation::BRIGHTNESS, value.at(0).type());
+ EXPECT_GE(value.at(0).amount(), 4);
+ EXPECT_LE(value.at(0).amount(), 6);
+
+ ExpectBrightness(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
+ ExpectBrightness(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+ ExpectBrightness(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/animation/keyframe_effect.cc b/chromium/cc/animation/keyframe_effect.cc
index a6d70065b15..ef4ec75cb45 100644
--- a/chromium/cc/animation/keyframe_effect.cc
+++ b/chromium/cc/animation/keyframe_effect.cc
@@ -4,18 +4,21 @@
#include "cc/animation/keyframe_effect.h"
+#include <algorithm>
#include <memory>
+#include <string>
+#include <utility>
#include "base/stl_util.h"
#include "base/time/time.h"
#include "cc/animation/animation.h"
-#include "cc/animation/animation_curve.h"
#include "cc/animation/animation_host.h"
#include "cc/animation/animation_timeline.h"
-#include "cc/animation/keyframe_model.h"
#include "cc/animation/scroll_offset_animation_curve.h"
-#include "cc/animation/transform_operations.h"
#include "cc/trees/property_animation_state.h"
+#include "ui/gfx//transform_operations.h"
+#include "ui/gfx/animation/keyframe/animation_curve.h"
+#include "ui/gfx/animation/keyframe/target_property.h"
namespace cc {
@@ -108,8 +111,7 @@ void KeyframeEffect::Tick(base::TimeTicks monotonic_time) {
StartKeyframeModels(monotonic_time);
for (auto& keyframe_model : keyframe_models_) {
- TickKeyframeModel(monotonic_time, keyframe_model.get(),
- element_animations_.get());
+ TickKeyframeModel(monotonic_time, keyframe_model.get());
}
last_tick_time_ = monotonic_time;
@@ -117,51 +119,18 @@ void KeyframeEffect::Tick(base::TimeTicks monotonic_time) {
}
void KeyframeEffect::TickKeyframeModel(base::TimeTicks monotonic_time,
- KeyframeModel* keyframe_model,
- AnimationTarget* target) {
- if ((keyframe_model->run_state() != KeyframeModel::STARTING &&
- keyframe_model->run_state() != KeyframeModel::RUNNING &&
- keyframe_model->run_state() != KeyframeModel::PAUSED) ||
+ KeyframeModel* keyframe_model) {
+ if ((keyframe_model->run_state() != gfx::KeyframeModel::STARTING &&
+ keyframe_model->run_state() != gfx::KeyframeModel::RUNNING &&
+ keyframe_model->run_state() != gfx::KeyframeModel::PAUSED) ||
!keyframe_model->InEffect(monotonic_time)) {
return;
}
- AnimationCurve* curve = keyframe_model->curve();
+ gfx::AnimationCurve* curve = keyframe_model->curve();
base::TimeDelta trimmed =
keyframe_model->TrimTimeToCurrentIteration(monotonic_time);
-
- switch (curve->Type()) {
- case AnimationCurve::TRANSFORM:
- target->NotifyClientTransformOperationsAnimated(
- curve->ToTransformAnimationCurve()->GetValue(trimmed),
- keyframe_model->target_property_id(), keyframe_model);
- break;
- case AnimationCurve::FLOAT:
- target->NotifyClientFloatAnimated(
- curve->ToFloatAnimationCurve()->GetValue(trimmed),
- keyframe_model->target_property_id(), keyframe_model);
- break;
- case AnimationCurve::FILTER:
- target->NotifyClientFilterAnimated(
- curve->ToFilterAnimationCurve()->GetValue(trimmed),
- keyframe_model->target_property_id(), keyframe_model);
- break;
- case AnimationCurve::COLOR:
- target->NotifyClientColorAnimated(
- curve->ToColorAnimationCurve()->GetValue(trimmed),
- keyframe_model->target_property_id(), keyframe_model);
- break;
- case AnimationCurve::SCROLL_OFFSET:
- target->NotifyClientScrollOffsetAnimated(
- curve->ToScrollOffsetAnimationCurve()->GetValue(trimmed),
- keyframe_model->target_property_id(), keyframe_model);
- break;
- case AnimationCurve::SIZE:
- target->NotifyClientSizeAnimated(
- curve->ToSizeAnimationCurve()->GetValue(trimmed),
- keyframe_model->target_property_id(), keyframe_model);
- break;
- }
+ curve->Tick(trimmed, keyframe_model->TargetProperty(), keyframe_model);
}
void KeyframeEffect::RemoveFromTicking() {
@@ -225,8 +194,8 @@ void KeyframeEffect::Pause(base::TimeDelta pause_offset,
// to tick scroll-linked keyframe models directly.
if (pause_condition == PauseCondition::kAfterStart &&
(keyframe_model->run_state() ==
- KeyframeModel::WAITING_FOR_TARGET_AVAILABILITY ||
- keyframe_model->run_state() == KeyframeModel::STARTING))
+ gfx::KeyframeModel::WAITING_FOR_TARGET_AVAILABILITY ||
+ keyframe_model->run_state() == gfx::KeyframeModel::STARTING))
continue;
keyframe_model->Pause(pause_offset);
did_pause = true;
@@ -240,29 +209,26 @@ void KeyframeEffect::Pause(base::TimeDelta pause_offset,
void KeyframeEffect::AddKeyframeModel(
std::unique_ptr<KeyframeModel> keyframe_model) {
- DCHECK(keyframe_model->target_property_id() !=
- TargetProperty::SCROLL_OFFSET ||
- (animation_->animation_host()->SupportsScrollAnimations()));
DCHECK(!keyframe_model->is_impl_only() ||
- keyframe_model->target_property_id() == TargetProperty::SCROLL_OFFSET);
+ keyframe_model->TargetProperty() == TargetProperty::SCROLL_OFFSET);
// This is to make sure that keyframe models in the same group, i.e., start
// together, don't animate the same property.
- DCHECK(std::none_of(
- keyframe_models_.begin(), keyframe_models_.end(),
- [&](const auto& existing_keyframe_model) {
- return keyframe_model->target_property_id() ==
- existing_keyframe_model->target_property_id() &&
- keyframe_model->group() == existing_keyframe_model->group();
- }));
-
- if (keyframe_model->target_property_id() == TargetProperty::SCROLL_OFFSET) {
+ DCHECK(std::none_of(keyframe_models_.begin(), keyframe_models_.end(),
+ [&](const auto& existing_keyframe_model) {
+ return keyframe_model->TargetProperty() ==
+ existing_keyframe_model->TargetProperty() &&
+ keyframe_model->group() ==
+ existing_keyframe_model->group();
+ }));
+
+ if (keyframe_model->TargetProperty() == TargetProperty::SCROLL_OFFSET) {
// We should never have more than one scroll offset animation queued on the
// same scrolling element as this would result in multiple automated
// scrolls.
DCHECK(std::none_of(
keyframe_models_.begin(), keyframe_models_.end(),
[&](const auto& existing_keyframe_model) {
- return existing_keyframe_model->target_property_id() ==
+ return existing_keyframe_model->TargetProperty() ==
TargetProperty::SCROLL_OFFSET &&
!existing_keyframe_model->is_finished() &&
(!existing_keyframe_model->is_controlling_instance() ||
@@ -306,7 +272,7 @@ void KeyframeEffect::RemoveKeyframeModel(int keyframe_model_id) {
});
for (auto it = keyframe_models_to_remove; it != keyframe_models_.end();
++it) {
- if ((*it)->target_property_id() == TargetProperty::SCROLL_OFFSET) {
+ if ((*it)->TargetProperty() == TargetProperty::SCROLL_OFFSET) {
if (has_bound_element_animations())
scroll_offset_animation_was_interrupted_ = true;
} else if (!(*it)->is_finished()) {
@@ -328,7 +294,7 @@ void KeyframeEffect::RemoveKeyframeModel(int keyframe_model_id) {
void KeyframeEffect::AbortKeyframeModel(int keyframe_model_id) {
if (KeyframeModel* keyframe_model = GetKeyframeModelById(keyframe_model_id)) {
if (!keyframe_model->is_finished()) {
- keyframe_model->SetRunState(KeyframeModel::ABORTED,
+ keyframe_model->SetRunState(gfx::KeyframeModel::ABORTED,
last_tick_time_.value_or(base::TimeTicks()));
if (has_bound_element_animations())
element_animations_->UpdateClientAnimationState();
@@ -349,17 +315,17 @@ void KeyframeEffect::AbortKeyframeModelsWithProperty(
bool aborted_keyframe_model = false;
for (auto& keyframe_model : keyframe_models_) {
- if (keyframe_model->target_property_id() == target_property &&
+ if (keyframe_model->TargetProperty() == target_property &&
!keyframe_model->is_finished()) {
// Currently only impl-only scroll offset KeyframeModels can be completed
// on the main thread.
if (needs_completion && keyframe_model->is_impl_only()) {
keyframe_model->SetRunState(
- KeyframeModel::ABORTED_BUT_NEEDS_COMPLETION,
+ gfx::KeyframeModel::ABORTED_BUT_NEEDS_COMPLETION,
last_tick_time_.value_or(base::TimeTicks()));
} else {
keyframe_model->SetRunState(
- KeyframeModel::ABORTED,
+ gfx::KeyframeModel::ABORTED,
last_tick_time_.value_or(base::TimeTicks()));
}
aborted_keyframe_model = true;
@@ -400,6 +366,9 @@ void KeyframeEffect::KeyframeModelAdded() {
needs_to_start_keyframe_models_ = true;
UpdateTickingState();
+ for (auto& keyframe_model : keyframe_models_) {
+ element_animations_->AttachToCurve(keyframe_model->curve());
+ }
element_animations_->UpdateClientAnimationState();
}
@@ -433,7 +402,7 @@ bool KeyframeEffect::DispatchAnimationEventToKeyframeModel(
case AnimationEvent::ABORTED:
if (keyframe_model) {
- keyframe_model->SetRunState(KeyframeModel::ABORTED,
+ keyframe_model->SetRunState(gfx::KeyframeModel::ABORTED,
event.monotonic_time);
keyframe_model->set_received_finished_event(true);
dispatched = true;
@@ -474,14 +443,14 @@ bool KeyframeEffect::HasTickingKeyframeModel() const {
bool KeyframeEffect::AffectsCustomProperty() const {
for (const auto& it : keyframe_models_)
- if (it->target_property_id() == TargetProperty::CSS_CUSTOM_PROPERTY)
+ if (it->TargetProperty() == TargetProperty::CSS_CUSTOM_PROPERTY)
return true;
return false;
}
bool KeyframeEffect::HasNonDeletedKeyframeModel() const {
for (const auto& keyframe_model : keyframe_models_) {
- if (keyframe_model->run_state() != KeyframeModel::WAITING_FOR_DELETION)
+ if (keyframe_model->run_state() != gfx::KeyframeModel::WAITING_FOR_DELETION)
return true;
}
return false;
@@ -489,28 +458,19 @@ bool KeyframeEffect::HasNonDeletedKeyframeModel() const {
bool KeyframeEffect::AnimationsPreserveAxisAlignment() const {
for (const auto& keyframe_model : keyframe_models_) {
- if (keyframe_model->is_finished() ||
- keyframe_model->target_property_id() != TargetProperty::TRANSFORM)
+ if (keyframe_model->is_finished())
continue;
- const TransformAnimationCurve* transform_animation_curve =
- keyframe_model->curve()->ToTransformAnimationCurve();
- if (!transform_animation_curve->PreservesAxisAlignment())
+ if (!keyframe_model->curve()->PreservesAxisAlignment())
return false;
}
return true;
}
-bool KeyframeEffect::GetAnimationScales(ElementListType list_type,
- float* maximum_scale,
- float* starting_scale) const {
- *maximum_scale = kNotScaled;
- *starting_scale = kNotScaled;
- bool maximum_scale_valid = true;
- bool starting_scale_valid = true;
+float KeyframeEffect::MaximumScale(ElementListType list_type) const {
+ float maximum_scale = kInvalidScale;
for (const auto& keyframe_model : keyframe_models_) {
- if (keyframe_model->is_finished() ||
- keyframe_model->target_property_id() != TargetProperty::TRANSFORM)
+ if (keyframe_model->is_finished())
continue;
if ((list_type == ElementListType::ACTIVE &&
@@ -519,50 +479,11 @@ bool KeyframeEffect::GetAnimationScales(ElementListType list_type,
!keyframe_model->affects_pending_elements()))
continue;
- const TransformAnimationCurve* transform_animation_curve =
- keyframe_model->curve()->ToTransformAnimationCurve();
- if (transform_animation_curve->IsTranslation())
- continue;
-
- bool forward_direction = true;
- switch (keyframe_model->direction()) {
- case KeyframeModel::Direction::NORMAL:
- case KeyframeModel::Direction::ALTERNATE_NORMAL:
- forward_direction = keyframe_model->playback_rate() >= 0.0;
- break;
- case KeyframeModel::Direction::REVERSE:
- case KeyframeModel::Direction::ALTERNATE_REVERSE:
- forward_direction = keyframe_model->playback_rate() < 0.0;
- break;
- }
-
- if (maximum_scale_valid) {
- float keyframe_model_maximum_scale = kNotScaled;
- if (transform_animation_curve->MaximumTargetScale(
- forward_direction, &keyframe_model_maximum_scale)) {
- *maximum_scale = std::max(*maximum_scale, keyframe_model_maximum_scale);
- } else {
- maximum_scale_valid = false;
- *maximum_scale = kNotScaled;
- }
- }
-
- if (starting_scale_valid) {
- float keyframe_model_starting_scale = kNotScaled;
- if (transform_animation_curve->AnimationStartScale(
- forward_direction, &keyframe_model_starting_scale)) {
- *starting_scale =
- std::max(*starting_scale, keyframe_model_starting_scale);
- } else {
- starting_scale_valid = false;
- *starting_scale = kNotScaled;
- }
- }
-
- if (!maximum_scale_valid && !starting_scale_valid)
- return false;
+ float curve_maximum_scale = kInvalidScale;
+ if (keyframe_model->curve()->MaximumScale(&curve_maximum_scale))
+ maximum_scale = std::max(maximum_scale, curve_maximum_scale);
}
- return true;
+ return maximum_scale;
}
bool KeyframeEffect::IsPotentiallyAnimatingProperty(
@@ -570,7 +491,7 @@ bool KeyframeEffect::IsPotentiallyAnimatingProperty(
ElementListType list_type) const {
for (const auto& keyframe_model : keyframe_models_) {
if (!keyframe_model->is_finished() &&
- keyframe_model->target_property_id() == target_property) {
+ keyframe_model->TargetProperty() == target_property) {
if ((list_type == ElementListType::ACTIVE &&
keyframe_model->affects_active_elements()) ||
(list_type == ElementListType::PENDING &&
@@ -587,7 +508,7 @@ bool KeyframeEffect::IsCurrentlyAnimatingProperty(
for (const auto& keyframe_model : keyframe_models_) {
if (!keyframe_model->is_finished() &&
keyframe_model->InEffect(last_tick_time_.value_or(base::TimeTicks())) &&
- keyframe_model->target_property_id() == target_property) {
+ keyframe_model->TargetProperty() == target_property) {
if ((list_type == ElementListType::ACTIVE &&
keyframe_model->affects_active_elements()) ||
(list_type == ElementListType::PENDING &&
@@ -602,7 +523,7 @@ KeyframeModel* KeyframeEffect::GetKeyframeModel(
TargetProperty::Type target_property) const {
for (size_t i = 0; i < keyframe_models_.size(); ++i) {
size_t index = keyframe_models_.size() - i - 1;
- if (keyframe_models_[index]->target_property_id() == target_property)
+ if (keyframe_models_[index]->TargetProperty() == target_property)
return keyframe_models_[index].get();
}
return nullptr;
@@ -628,7 +549,7 @@ void KeyframeEffect::GetPropertyAnimationState(
keyframe_model->InEffect(last_tick_time_.value_or(base::TimeTicks()));
bool active = keyframe_model->affects_active_elements();
bool pending = keyframe_model->affects_pending_elements();
- int property = keyframe_model->target_property_id();
+ int property = keyframe_model->TargetProperty();
if (pending)
pending_state->potentially_animating[property] = true;
@@ -653,12 +574,12 @@ void KeyframeEffect::MarkAbortedKeyframeModelsForDeletion(
// deletion.
if (KeyframeModel* keyframe_model =
GetKeyframeModelById(keyframe_model_impl->id())) {
- if (keyframe_model->run_state() == KeyframeModel::ABORTED) {
+ if (keyframe_model->run_state() == gfx::KeyframeModel::ABORTED) {
keyframe_model_impl->SetRunState(
- KeyframeModel::WAITING_FOR_DELETION,
+ gfx::KeyframeModel::WAITING_FOR_DELETION,
keyframe_effect_impl->last_tick_time_.value_or(base::TimeTicks()));
keyframe_model->SetRunState(
- KeyframeModel::WAITING_FOR_DELETION,
+ gfx::KeyframeModel::WAITING_FOR_DELETION,
last_tick_time_.value_or(base::TimeTicks()));
keyframe_model_aborted = true;
}
@@ -674,7 +595,7 @@ void KeyframeEffect::PurgeKeyframeModelsMarkedForDeletion(bool impl_only) {
keyframe_models_,
[impl_only](const std::unique_ptr<KeyframeModel>& keyframe_model) {
return keyframe_model->run_state() ==
- KeyframeModel::WAITING_FOR_DELETION &&
+ gfx::KeyframeModel::WAITING_FOR_DELETION &&
(!impl_only || keyframe_model->is_impl_only());
});
}
@@ -683,7 +604,7 @@ void KeyframeEffect::PurgeDeletedKeyframeModels() {
base::EraseIf(keyframe_models_,
[](const std::unique_ptr<KeyframeModel>& keyframe_model) {
return keyframe_model->run_state() ==
- KeyframeModel::WAITING_FOR_DELETION &&
+ gfx::KeyframeModel::WAITING_FOR_DELETION &&
!keyframe_model->affects_pending_elements();
});
}
@@ -703,9 +624,9 @@ void KeyframeEffect::PushNewKeyframeModelsToImplThread(
if (keyframe_effect_impl->GetKeyframeModelById(keyframe_model->id()))
continue;
- if (keyframe_model->target_property_id() == TargetProperty::SCROLL_OFFSET &&
- !keyframe_model->curve()
- ->ToScrollOffsetAnimationCurve()
+ if (keyframe_model->TargetProperty() == TargetProperty::SCROLL_OFFSET &&
+ !ScrollOffsetAnimationCurve::ToScrollOffsetAnimationCurve(
+ keyframe_model->curve())
->HasSetInitialValue()) {
gfx::ScrollOffset current_scroll_offset;
if (keyframe_effect_impl->HasElementInActiveList()) {
@@ -716,13 +637,15 @@ void KeyframeEffect::PushNewKeyframeModelsToImplThread(
// scroll offset will be up to date.
current_scroll_offset = ScrollOffsetForAnimation();
}
- keyframe_model->curve()->ToScrollOffsetAnimationCurve()->SetInitialValue(
- current_scroll_offset);
+ ScrollOffsetAnimationCurve* curve =
+ ScrollOffsetAnimationCurve::ToScrollOffsetAnimationCurve(
+ keyframe_model->curve());
+ curve->SetInitialValue(current_scroll_offset);
}
// The new keyframe_model should be set to run as soon as possible.
- KeyframeModel::RunState initial_run_state =
- KeyframeModel::WAITING_FOR_TARGET_AVAILABILITY;
+ gfx::KeyframeModel::RunState initial_run_state =
+ gfx::KeyframeModel::WAITING_FOR_TARGET_AVAILABILITY;
std::unique_ptr<KeyframeModel> to_add(
keyframe_model->CreateImplInstance(initial_run_state));
DCHECK(!to_add->needs_synchronized_start_time());
@@ -735,7 +658,8 @@ namespace {
bool IsCompleted(KeyframeModel* keyframe_model,
const KeyframeEffect* main_thread_keyframe_effect) {
if (keyframe_model->is_impl_only()) {
- return (keyframe_model->run_state() == KeyframeModel::WAITING_FOR_DELETION);
+ return (keyframe_model->run_state() ==
+ gfx::KeyframeModel::WAITING_FOR_DELETION);
} else {
KeyframeModel* main_thread_keyframe_model =
main_thread_keyframe_effect->GetKeyframeModelById(keyframe_model->id());
@@ -824,21 +748,33 @@ std::string KeyframeEffect::KeyframeModelsToString() const {
return str;
}
+base::TimeDelta KeyframeEffect::MinimumTickInterval() const {
+ base::TimeDelta min_interval = base::TimeDelta::Max();
+ for (const auto& model : keyframe_models_) {
+ base::TimeDelta interval = model->curve()->TickInterval();
+ if (interval.is_zero())
+ return interval;
+ if (interval < min_interval)
+ min_interval = interval;
+ }
+ return min_interval;
+}
+
void KeyframeEffect::StartKeyframeModels(base::TimeTicks monotonic_time) {
DCHECK(needs_to_start_keyframe_models_);
needs_to_start_keyframe_models_ = false;
// First collect running properties affecting each type of element.
- TargetProperties blocked_properties_for_active_elements;
- TargetProperties blocked_properties_for_pending_elements;
+ gfx::TargetProperties blocked_properties_for_active_elements;
+ gfx::TargetProperties blocked_properties_for_pending_elements;
std::vector<size_t> keyframe_models_waiting_for_target;
keyframe_models_waiting_for_target.reserve(keyframe_models_.size());
for (size_t i = 0; i < keyframe_models_.size(); ++i) {
auto& keyframe_model = keyframe_models_[i];
- if (keyframe_model->run_state() == KeyframeModel::STARTING ||
- keyframe_model->run_state() == KeyframeModel::RUNNING) {
- int property = keyframe_model->target_property_id();
+ if (keyframe_model->run_state() == gfx::KeyframeModel::STARTING ||
+ keyframe_model->run_state() == gfx::KeyframeModel::RUNNING) {
+ int property = keyframe_model->TargetProperty();
if (keyframe_model->affects_active_elements()) {
blocked_properties_for_active_elements[property] = true;
}
@@ -846,7 +782,7 @@ void KeyframeEffect::StartKeyframeModels(base::TimeTicks monotonic_time) {
blocked_properties_for_pending_elements[property] = true;
}
} else if (keyframe_model->run_state() ==
- KeyframeModel::WAITING_FOR_TARGET_AVAILABILITY) {
+ gfx::KeyframeModel::WAITING_FOR_TARGET_AVAILABILITY) {
keyframe_models_waiting_for_target.push_back(i);
}
}
@@ -861,19 +797,19 @@ void KeyframeEffect::StartKeyframeModels(base::TimeTicks monotonic_time) {
// for target because it might have changed the run state while handling
// previous keyframe_model in this loop (if they belong to same group).
if (keyframe_model_waiting_for_target->run_state() ==
- KeyframeModel::WAITING_FOR_TARGET_AVAILABILITY) {
- TargetProperties enqueued_properties;
+ gfx::KeyframeModel::WAITING_FOR_TARGET_AVAILABILITY) {
+ gfx::TargetProperties enqueued_properties;
bool affects_active_elements =
keyframe_model_waiting_for_target->affects_active_elements();
bool affects_pending_elements =
keyframe_model_waiting_for_target->affects_pending_elements();
- enqueued_properties[keyframe_model_waiting_for_target
- ->target_property_id()] = true;
+ enqueued_properties[keyframe_model_waiting_for_target->TargetProperty()] =
+ true;
for (size_t j = keyframe_model_index + 1; j < keyframe_models_.size();
++j) {
if (keyframe_model_waiting_for_target->group() ==
keyframe_models_[j]->group()) {
- enqueued_properties[keyframe_models_[j]->target_property_id()] = true;
+ enqueued_properties[keyframe_models_[j]->TargetProperty()] = true;
affects_active_elements |=
keyframe_models_[j]->affects_active_elements();
affects_pending_elements |=
@@ -908,13 +844,13 @@ void KeyframeEffect::StartKeyframeModels(base::TimeTicks monotonic_time) {
// If the intersection is null, then we are free to start the
// KeyframeModels in the group.
if (null_intersection) {
- keyframe_model_waiting_for_target->SetRunState(KeyframeModel::STARTING,
- monotonic_time);
+ keyframe_model_waiting_for_target->SetRunState(
+ gfx::KeyframeModel::STARTING, monotonic_time);
for (size_t j = keyframe_model_index + 1; j < keyframe_models_.size();
++j) {
if (keyframe_model_waiting_for_target->group() ==
keyframe_models_[j]->group()) {
- keyframe_models_[j]->SetRunState(KeyframeModel::STARTING,
+ keyframe_models_[j]->SetRunState(gfx::KeyframeModel::STARTING,
monotonic_time);
}
}
@@ -927,9 +863,9 @@ void KeyframeEffect::StartKeyframeModels(base::TimeTicks monotonic_time) {
void KeyframeEffect::PromoteStartedKeyframeModels(AnimationEvents* events) {
for (auto& keyframe_model : keyframe_models_) {
- if (keyframe_model->run_state() == KeyframeModel::STARTING &&
+ if (keyframe_model->run_state() == gfx::KeyframeModel::STARTING &&
keyframe_model->affects_active_elements()) {
- keyframe_model->SetRunState(KeyframeModel::RUNNING,
+ keyframe_model->SetRunState(gfx::KeyframeModel::RUNNING,
last_tick_time_.value_or(base::TimeTicks()));
if (!keyframe_model->has_set_start_time() &&
!keyframe_model->needs_synchronized_start_time())
@@ -953,7 +889,7 @@ void KeyframeEffect::MarkKeyframeModelsForDeletion(
AnimationEvents* events) {
bool marked_keyframe_model_for_deletion = false;
auto MarkForDeletion = [&](KeyframeModel* keyframe_model) {
- keyframe_model->SetRunState(KeyframeModel::WAITING_FOR_DELETION,
+ keyframe_model->SetRunState(gfx::KeyframeModel::WAITING_FOR_DELETION,
monotonic_time);
marked_keyframe_model_for_deletion = true;
};
@@ -965,7 +901,7 @@ void KeyframeEffect::MarkKeyframeModelsForDeletion(
// deletion.
for (size_t i = 0; i < keyframe_models_.size(); i++) {
KeyframeModel* keyframe_model = keyframe_models_[i].get();
- if (keyframe_model->run_state() == KeyframeModel::ABORTED) {
+ if (keyframe_model->run_state() == gfx::KeyframeModel::ABORTED) {
GenerateEvent(events, *keyframe_model, AnimationEvent::ABORTED,
monotonic_time);
// If this is the controlling instance or it has already received finish
@@ -979,7 +915,7 @@ void KeyframeEffect::MarkKeyframeModelsForDeletion(
// main thread, generate takeover event.
if (keyframe_model->is_controlling_instance() &&
keyframe_model->run_state() ==
- KeyframeModel::ABORTED_BUT_NEEDS_COMPLETION) {
+ gfx::KeyframeModel::ABORTED_BUT_NEEDS_COMPLETION) {
GenerateTakeoverEventForScrollAnimation(events, *keyframe_model,
monotonic_time);
// Remove the keyframe model from the impl thread.
@@ -987,7 +923,7 @@ void KeyframeEffect::MarkKeyframeModelsForDeletion(
continue;
}
- if (keyframe_model->run_state() != KeyframeModel::FINISHED)
+ if (keyframe_model->run_state() != gfx::KeyframeModel::FINISHED)
continue;
// Since deleting an animation on the main thread leads to its deletion
@@ -1008,7 +944,7 @@ void KeyframeEffect::MarkKeyframeModelsForDeletion(
keyframe_models_in_same_group.cend(), [&](size_t index) {
KeyframeModel* keyframe_model = keyframe_models_[index].get();
return !keyframe_model->is_finished() ||
- (keyframe_model->run_state() == KeyframeModel::FINISHED &&
+ (keyframe_model->run_state() == gfx::KeyframeModel::FINISHED &&
NeedsFinishedEvent(keyframe_model));
});
@@ -1024,8 +960,8 @@ void KeyframeEffect::MarkKeyframeModelsForDeletion(
// Skip any keyframe model in this group which is already processed.
if (same_group_keyframe_model->run_state() ==
- KeyframeModel::WAITING_FOR_DELETION ||
- same_group_keyframe_model->run_state() == KeyframeModel::ABORTED)
+ gfx::KeyframeModel::WAITING_FOR_DELETION ||
+ same_group_keyframe_model->run_state() == gfx::KeyframeModel::ABORTED)
continue;
GenerateEvent(events, *same_group_keyframe_model,
@@ -1048,18 +984,19 @@ void KeyframeEffect::MarkFinishedKeyframeModels(
for (auto& keyframe_model : keyframe_models_) {
if (!keyframe_model->is_finished() &&
keyframe_model->IsFinishedAt(monotonic_time)) {
- keyframe_model->SetRunState(KeyframeModel::FINISHED, monotonic_time);
+ keyframe_model->SetRunState(gfx::KeyframeModel::FINISHED, monotonic_time);
keyframe_model_finished = true;
SetNeedsPushProperties();
}
if (!keyframe_model->affects_active_elements() &&
!keyframe_model->affects_pending_elements()) {
switch (keyframe_model->run_state()) {
- case KeyframeModel::WAITING_FOR_TARGET_AVAILABILITY:
- case KeyframeModel::STARTING:
- case KeyframeModel::RUNNING:
- case KeyframeModel::PAUSED:
- keyframe_model->SetRunState(KeyframeModel::FINISHED, monotonic_time);
+ case gfx::KeyframeModel::WAITING_FOR_TARGET_AVAILABILITY:
+ case gfx::KeyframeModel::STARTING:
+ case gfx::KeyframeModel::RUNNING:
+ case gfx::KeyframeModel::PAUSED:
+ keyframe_model->SetRunState(gfx::KeyframeModel::FINISHED,
+ monotonic_time);
keyframe_model_finished = true;
break;
default:
@@ -1091,8 +1028,8 @@ void KeyframeEffect::GenerateEvent(AnimationEvents* events,
AnimationEvent event(type,
{animation_->animation_timeline()->id(),
animation_->id(), keyframe_model.id()},
- keyframe_model.group(),
- keyframe_model.target_property_id(), monotonic_time);
+ keyframe_model.group(), keyframe_model.TargetProperty(),
+ monotonic_time);
event.is_impl_only = keyframe_model.is_impl_only();
if (!event.is_impl_only) {
events->events_.push_back(event);
@@ -1106,29 +1043,28 @@ void KeyframeEffect::GenerateTakeoverEventForScrollAnimation(
AnimationEvents* events,
const KeyframeModel& keyframe_model,
base::TimeTicks monotonic_time) {
- DCHECK_EQ(keyframe_model.target_property_id(), TargetProperty::SCROLL_OFFSET);
+ DCHECK_EQ(keyframe_model.TargetProperty(), TargetProperty::SCROLL_OFFSET);
if (!events)
return;
- AnimationEvent takeover_event(AnimationEvent::TAKEOVER,
- {animation_->animation_timeline()->id(),
- animation_->id(), keyframe_model.id()},
- keyframe_model.group(),
- keyframe_model.target_property_id(),
- monotonic_time);
+ AnimationEvent takeover_event(
+ AnimationEvent::TAKEOVER,
+ {animation_->animation_timeline()->id(), animation_->id(),
+ keyframe_model.id()},
+ keyframe_model.group(), keyframe_model.TargetProperty(), monotonic_time);
takeover_event.animation_start_time = keyframe_model.start_time();
const ScrollOffsetAnimationCurve* scroll_offset_animation_curve =
- keyframe_model.curve()->ToScrollOffsetAnimationCurve();
+ ScrollOffsetAnimationCurve::ToScrollOffsetAnimationCurve(
+ keyframe_model.curve());
takeover_event.curve = scroll_offset_animation_curve->Clone();
// Notify main thread.
events->events_.push_back(takeover_event);
- AnimationEvent finished_event(AnimationEvent::FINISHED,
- {animation_->animation_timeline()->id(),
- animation_->id(), keyframe_model.id()},
- keyframe_model.group(),
- keyframe_model.target_property_id(),
- monotonic_time);
+ AnimationEvent finished_event(
+ AnimationEvent::FINISHED,
+ {animation_->animation_timeline()->id(), animation_->id(),
+ keyframe_model.id()},
+ keyframe_model.group(), keyframe_model.TargetProperty(), monotonic_time);
// Notify the compositor that the animation is finished.
finished_event.is_impl_only = true;
animation_->DispatchAndDelegateAnimationEvent(finished_event);
diff --git a/chromium/cc/animation/keyframe_effect.h b/chromium/cc/animation/keyframe_effect.h
index 0e1280f82e1..9e511add1f8 100644
--- a/chromium/cc/animation/keyframe_effect.h
+++ b/chromium/cc/animation/keyframe_effect.h
@@ -5,20 +5,22 @@
#ifndef CC_ANIMATION_KEYFRAME_EFFECT_H_
#define CC_ANIMATION_KEYFRAME_EFFECT_H_
+#include <memory>
+#include <string>
+#include <vector>
+
#include "base/memory/ref_counted.h"
#include "base/time/time.h"
#include "cc/animation/animation_events.h"
#include "cc/animation/animation_export.h"
#include "cc/animation/element_animations.h"
+#include "cc/animation/keyframe_model.h"
#include "cc/paint/element_id.h"
#include "cc/trees/mutator_host_client.h"
#include "cc/trees/target_property.h"
#include "ui/gfx/geometry/box_f.h"
#include "ui/gfx/geometry/scroll_offset.h"
-#include <memory>
-#include <vector>
-
namespace cc {
class Animation;
@@ -80,8 +82,7 @@ class CC_ANIMATION_EXPORT KeyframeEffect {
virtual void Tick(base::TimeTicks monotonic_time);
static void TickKeyframeModel(base::TimeTicks monotonic_time,
- KeyframeModel* keyframe_model,
- AnimationTarget* target);
+ KeyframeModel* keyframe_model);
void RemoveFromTicking();
void UpdateState(bool start_ready_keyframe_models, AnimationEvents* events);
@@ -115,15 +116,10 @@ class CC_ANIMATION_EXPORT KeyframeEffect {
bool AnimationsPreserveAxisAlignment() const;
- // Gets scales transform animations. On return, |maximum_scale| is the maximum
- // scale along any dimension at any destination in active scale animations,
- // and |starting_scale| is the maximum of starting animation scale along any
- // dimension at any destination in active scale animations. They are set to
- // kNotScaled if there is no active scale animation or the scales cannot be
- // computed. Returns false if the scales cannot be computed.
- bool GetAnimationScales(ElementListType,
- float* maximum_scale,
- float* starting_scale) const;
+ // Returns the maximum scale along any dimension at any destination in active
+ // scale animations, or kInvalidScale if there is no active transform
+ // animation or the scale cannot be computed.
+ float MaximumScale(ElementListType) const;
// Returns true if there is a keyframe_model that is either currently
// animating the given property or scheduled to animate this property in the
@@ -153,6 +149,12 @@ class CC_ANIMATION_EXPORT KeyframeEffect {
std::string KeyframeModelsToString() const;
+ // Iterates through all |keyframe_models_| and returns the minimum of their
+ // animation curve's tick intervals.
+ // Returns 0 if there is a continuous animation which should be ticked as
+ // fast as possible.
+ base::TimeDelta MinimumTickInterval() const;
+
private:
void StartKeyframeModels(base::TimeTicks monotonic_time);
void PromoteStartedKeyframeModels(AnimationEvents* events);
diff --git a/chromium/cc/animation/keyframe_model.cc b/chromium/cc/animation/keyframe_model.cc
index 0f73210ba14..7f4801ea695 100644
--- a/chromium/cc/animation/keyframe_model.cc
+++ b/chromium/cc/animation/keyframe_model.cc
@@ -16,51 +16,54 @@
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/trace_event/trace_event.h"
-#include "cc/animation/animation_curve.h"
#include "cc/trees/target_property.h"
+#include "ui/gfx/animation/keyframe/animation_curve.h"
-namespace {
+namespace cc {
-// This should match the RunState enum.
-static const char* const s_runStateNames[] = {"WAITING_FOR_TARGET_AVAILABILITY",
- "WAITING_FOR_DELETION",
- "STARTING",
- "RUNNING",
- "PAUSED",
- "FINISHED",
- "ABORTED",
- "ABORTED_BUT_NEEDS_COMPLETION"};
+// static
+const KeyframeModel* KeyframeModel::ToCcKeyframeModel(
+ const gfx::KeyframeModel* keyframe_model) {
+ return static_cast<const KeyframeModel*>(keyframe_model);
+}
-static_assert(static_cast<int>(cc::KeyframeModel::LAST_RUN_STATE) + 1 ==
- base::size(s_runStateNames),
- "RunStateEnumSize should equal the number of elements in "
- "s_runStateNames");
+// static
+KeyframeModel* KeyframeModel::ToCcKeyframeModel(
+ gfx::KeyframeModel* keyframe_model) {
+ return static_cast<KeyframeModel*>(keyframe_model);
+}
-static const char* const s_curveTypeNames[] = {
- "COLOR", "FLOAT", "TRANSFORM", "FILTER", "SCROLL_OFFSET", "SIZE"};
+KeyframeModel::TargetPropertyId::TargetPropertyId(int target_property_type)
+ : target_property_type_(target_property_type),
+ custom_property_name_(""),
+ native_property_type_(PaintWorkletInput::NativePropertyType::kInvalid) {}
-static_assert(static_cast<int>(cc::AnimationCurve::LAST_CURVE_TYPE) + 1 ==
- base::size(s_curveTypeNames),
- "CurveType enum should equal the number of elements in "
- "s_runStateNames");
+KeyframeModel::TargetPropertyId::TargetPropertyId(
+ int target_property_type,
+ const std::string& custom_property_name)
+ : target_property_type_(target_property_type),
+ custom_property_name_(custom_property_name),
+ native_property_type_(PaintWorkletInput::NativePropertyType::kInvalid) {}
-} // namespace
+KeyframeModel::TargetPropertyId::TargetPropertyId(
+ int target_property_type,
+ PaintWorkletInput::NativePropertyType native_property_type)
+ : target_property_type_(target_property_type),
+ custom_property_name_(""),
+ native_property_type_(native_property_type) {}
-namespace cc {
+KeyframeModel::TargetPropertyId::TargetPropertyId(
+ const TargetPropertyId& other) = default;
-std::string KeyframeModel::ToString(RunState state) {
- return s_runStateNames[state];
-}
+KeyframeModel::TargetPropertyId::~TargetPropertyId() = default;
std::unique_ptr<KeyframeModel> KeyframeModel::Create(
- std::unique_ptr<AnimationCurve> curve,
+ std::unique_ptr<gfx::AnimationCurve> curve,
int keyframe_model_id,
int group_id,
- int target_property_id,
- const std::string& custom_property_name) {
+ TargetPropertyId target_property_id) {
return base::WrapUnique(new KeyframeModel(std::move(curve), keyframe_model_id,
- group_id, target_property_id,
- custom_property_name));
+ group_id, target_property_id));
}
std::unique_ptr<KeyframeModel> KeyframeModel::CreateImplInstance(
@@ -69,65 +72,56 @@ std::unique_ptr<KeyframeModel> KeyframeModel::CreateImplInstance(
// creating multiple controlling instances.
DCHECK(!is_controlling_instance_);
std::unique_ptr<KeyframeModel> to_return(
- new KeyframeModel(curve_->Clone(), id_, group_, target_property_id_,
- custom_property_name_));
+ new KeyframeModel(curve()->Clone(), id(), group_, target_property_id_));
to_return->element_id_ = element_id_;
- to_return->run_state_ = initial_run_state;
- to_return->iterations_ = iterations_;
- to_return->iteration_start_ = iteration_start_;
- to_return->start_time_ = start_time_;
- to_return->pause_time_ = pause_time_;
- to_return->total_paused_duration_ = total_paused_duration_;
- to_return->time_offset_ = time_offset_;
- to_return->direction_ = direction_;
- to_return->playback_rate_ = playback_rate_;
- to_return->fill_mode_ = fill_mode_;
+ to_return->ForceRunState(initial_run_state);
+ to_return->set_iterations(iterations());
+ to_return->set_iteration_start(iteration_start());
+ to_return->set_start_time(start_time());
+ to_return->set_pause_time(pause_time());
+ to_return->set_total_paused_duration(total_paused_duration());
+ to_return->set_time_offset(time_offset());
+ to_return->set_direction(direction());
+ to_return->set_playback_rate(playback_rate());
+ to_return->set_fill_mode(fill_mode());
DCHECK(!to_return->is_controlling_instance_);
to_return->is_controlling_instance_ = true;
return to_return;
}
-KeyframeModel::KeyframeModel(std::unique_ptr<AnimationCurve> curve,
+KeyframeModel::KeyframeModel(std::unique_ptr<gfx::AnimationCurve> curve,
int keyframe_model_id,
int group_id,
- int target_property_id,
- const std::string& custom_property_name)
- : curve_(std::move(curve)),
- id_(keyframe_model_id),
+ TargetPropertyId target_property_id)
+ : gfx::KeyframeModel(std::move(curve),
+ keyframe_model_id,
+ target_property_id.target_property_type()),
group_(group_id),
target_property_id_(target_property_id),
- run_state_(WAITING_FOR_TARGET_AVAILABILITY),
- iterations_(1),
- iteration_start_(0),
- direction_(Direction::NORMAL),
- playback_rate_(1),
- fill_mode_(FillMode::BOTH),
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),
- custom_property_name_(custom_property_name) {
- DCHECK(custom_property_name_.empty() ||
- target_property_id_ == TargetProperty::CSS_CUSTOM_PROPERTY);
-}
+ affects_pending_elements_(true) {}
-KeyframeModel::~KeyframeModel() {
- if (run_state_ == RUNNING || run_state_ == PAUSED)
- SetRunState(ABORTED, base::TimeTicks());
+KeyframeModel::~KeyframeModel() = default;
+
+int KeyframeModel::TargetProperty() const {
+ return target_property_id_.target_property_type();
}
-void KeyframeModel::SetRunState(RunState run_state,
+void KeyframeModel::SetRunState(RunState new_run_state,
base::TimeTicks monotonic_time) {
char name_buffer[256];
base::snprintf(name_buffer, sizeof(name_buffer), "%s-%d-%d",
- s_curveTypeNames[curve_->Type()], target_property_id_, group_);
+ curve()->TypeName(), TargetProperty(), group_);
bool is_waiting_to_start =
- run_state_ == WAITING_FOR_TARGET_AVAILABILITY || run_state_ == STARTING;
+ run_state() == WAITING_FOR_TARGET_AVAILABILITY || run_state() == STARTING;
- if (is_controlling_instance_ && is_waiting_to_start && run_state == RUNNING) {
+ if (is_controlling_instance_ && is_waiting_to_start &&
+ new_run_state == RUNNING) {
TRACE_EVENT_NESTABLE_ASYNC_BEGIN1("cc", "KeyframeModel",
TRACE_ID_LOCAL(this), "Name",
TRACE_STR_COPY(name_buffer));
@@ -135,15 +129,9 @@ void KeyframeModel::SetRunState(RunState run_state,
bool was_finished = is_finished();
- const char* old_run_state_name = s_runStateNames[run_state_];
-
- if (run_state == RUNNING && run_state_ == PAUSED)
- total_paused_duration_ += (monotonic_time - pause_time_);
- else if (run_state == PAUSED)
- pause_time_ = monotonic_time;
- run_state_ = run_state;
-
- const char* new_run_state_name = s_runStateNames[run_state];
+ auto old_run_state_name = gfx::KeyframeModel::ToString(run_state());
+ gfx::KeyframeModel::SetRunState(new_run_state, monotonic_time);
+ auto new_run_state_name = gfx::KeyframeModel::ToString(new_run_state);
if (is_controlling_instance_ && !was_finished && is_finished()) {
TRACE_EVENT_NESTABLE_ASYNC_END0("cc", "KeyframeModel",
@@ -152,208 +140,37 @@ void KeyframeModel::SetRunState(RunState run_state,
char state_buffer[256];
base::snprintf(state_buffer, sizeof(state_buffer), "%s->%s",
- old_run_state_name, new_run_state_name);
+ old_run_state_name.c_str(), new_run_state_name.c_str());
TRACE_EVENT_INSTANT2(
"cc", "ElementAnimations::SetRunState", TRACE_EVENT_SCOPE_THREAD, "Name",
TRACE_STR_COPY(name_buffer), "State", TRACE_STR_COPY(state_buffer));
}
-void KeyframeModel::Pause(base::TimeDelta pause_offset) {
- // Convert pause offset which is in local time to monotonic time.
- // TODO(crbug.com/912407): This should be scaled by playbackrate.
- base::TimeTicks monotonic_time =
- pause_offset + start_time_ + total_paused_duration_;
- SetRunState(PAUSED, monotonic_time);
-}
-
-bool KeyframeModel::IsFinishedAt(base::TimeTicks monotonic_time) const {
- if (is_finished())
- return true;
-
- if (needs_synchronized_start_time_)
- return false;
-
- if (playback_rate_ == 0)
- return false;
-
- return run_state_ == RUNNING && std::isfinite(iterations_) &&
- (curve_->Duration() * (iterations_ / std::abs(playback_rate_))) <=
- (ConvertMonotonicTimeToLocalTime(monotonic_time) + time_offset_);
-}
-
-KeyframeModel::Phase KeyframeModel::CalculatePhaseForTesting(
- base::TimeDelta local_time) const {
- return CalculatePhase(local_time);
-}
-
-KeyframeModel::Phase KeyframeModel::CalculatePhase(
- base::TimeDelta local_time) const {
- base::TimeDelta opposite_time_offset = time_offset_ == base::TimeDelta::Min()
- ? base::TimeDelta::Max()
- : -time_offset_;
- base::TimeDelta before_active_boundary_time =
- std::max(opposite_time_offset, base::TimeDelta());
- if (local_time < before_active_boundary_time ||
- (local_time == before_active_boundary_time && playback_rate_ < 0)) {
- return KeyframeModel::Phase::BEFORE;
- }
- // TODO(crbug.com/909794): By spec end time = max(start delay + duration +
- // end delay, 0). The logic should be updated once "end delay" is supported.
- base::TimeDelta active_after_boundary_time = base::TimeDelta::Max();
- if (std::isfinite(iterations_)) {
- // Scaling the duration is against spec but needed to comply with the cc
- // implementation. By spec (in blink) the playback rate is an Animation
- // level concept but in cc it's per KeyframeModel. We grab the active time
- // calculated here and later scale it with the playback rate in order to get
- // a proper progress. Therefore we need to un-scale it here. This can be
- // fixed once we scale the local time by playback rate. See
- // https://crbug.com/912407.
- base::TimeDelta active_duration =
- curve_->Duration() * iterations_ / std::abs(playback_rate_);
- active_after_boundary_time =
- std::max(opposite_time_offset + active_duration, base::TimeDelta());
- }
- if (local_time > active_after_boundary_time ||
- (local_time == active_after_boundary_time && playback_rate_ > 0)) {
- return KeyframeModel::Phase::AFTER;
- }
- return KeyframeModel::Phase::ACTIVE;
-}
-
-base::Optional<base::TimeDelta> KeyframeModel::CalculateActiveTime(
- base::TimeTicks monotonic_time) const {
- base::TimeDelta local_time = ConvertMonotonicTimeToLocalTime(monotonic_time);
- KeyframeModel::Phase phase = CalculatePhase(local_time);
- DCHECK(playback_rate_);
- switch (phase) {
- case KeyframeModel::Phase::BEFORE:
- if (fill_mode_ == FillMode::BACKWARDS || fill_mode_ == FillMode::BOTH)
- return std::max(local_time + time_offset_, base::TimeDelta());
- return base::nullopt;
- case KeyframeModel::Phase::ACTIVE:
- return local_time + time_offset_;
- case KeyframeModel::Phase::AFTER:
- if (fill_mode_ == FillMode::FORWARDS || fill_mode_ == FillMode::BOTH) {
- DCHECK_NE(iterations_, std::numeric_limits<double>::infinity());
- base::TimeDelta active_duration =
- curve_->Duration() * iterations_ / std::abs(playback_rate_);
- return std::max(std::min(local_time + time_offset_, active_duration),
- base::TimeDelta());
- }
- return base::nullopt;
- default:
- NOTREACHED();
- return base::nullopt;
- }
-}
-
bool KeyframeModel::InEffect(base::TimeTicks monotonic_time) const {
return CalculateActiveTime(monotonic_time).has_value();
}
-// TODO(crbug.com/912407): Local time should be scaled by playback rate by spec.
-base::TimeDelta KeyframeModel::ConvertMonotonicTimeToLocalTime(
- base::TimeTicks monotonic_time) const {
- // When waiting on receiving a start time, then our global clock is 'stuck' at
- // the initial state.
- if ((run_state_ == STARTING && !has_set_start_time()) ||
- needs_synchronized_start_time())
- return base::TimeDelta();
-
- // If we're paused, time is 'stuck' at the pause time.
- base::TimeTicks time = (run_state_ == PAUSED) ? pause_time_ : monotonic_time;
- return time - start_time_ - total_paused_duration_;
-}
-
-base::TimeDelta KeyframeModel::TrimTimeToCurrentIteration(
- base::TimeTicks monotonic_time) const {
- DCHECK(playback_rate_);
- DCHECK_GE(iteration_start_, 0);
-
- DCHECK(InEffect(monotonic_time));
- base::TimeDelta active_time = CalculateActiveTime(monotonic_time).value();
- base::TimeDelta start_offset = curve_->Duration() * iteration_start_;
-
- // Return start offset if we are before the start of the keyframe model
- if (active_time < base::TimeDelta())
- return start_offset;
- // Always return zero if we have no iterations.
- if (!iterations_)
- return base::TimeDelta();
-
- // Don't attempt to trim if we have no duration.
- if (curve_->Duration() <= base::TimeDelta())
- return base::TimeDelta();
-
- base::TimeDelta repeated_duration = std::isfinite(iterations_)
- ? (curve_->Duration() * iterations_)
- : base::TimeDelta::Max();
-
- // Calculate the scaled active time
- base::TimeDelta scaled_active_time;
- if (playback_rate_ < 0) {
- DCHECK(std::isfinite(iterations_));
- base::TimeDelta active_duration =
- repeated_duration / std::abs(playback_rate_);
- scaled_active_time =
- ((active_time - active_duration) * playback_rate_) + start_offset;
- } else {
- scaled_active_time = (active_time * playback_rate_) + start_offset;
- }
-
- // Calculate the iteration time
- base::TimeDelta iteration_time;
- bool has_defined_time_delta =
- (start_offset != scaled_active_time) ||
- !(start_offset.is_max() || start_offset.is_min());
- if (has_defined_time_delta &&
- scaled_active_time - start_offset == repeated_duration &&
- fmod(iterations_ + iteration_start_, 1) == 0)
- iteration_time = curve_->Duration();
- else
- iteration_time = scaled_active_time % curve_->Duration();
-
- // Calculate the current iteration
- int iteration;
- if (scaled_active_time <= base::TimeDelta())
- iteration = 0;
- else if (iteration_time == curve_->Duration())
- iteration = ceil(iteration_start_ + iterations_ - 1);
- else
- iteration = base::ClampFloor(scaled_active_time / curve_->Duration());
-
- // Check if we are running the keyframe model in reverse direction for the
- // current iteration
- bool reverse =
- (direction_ == Direction::REVERSE) ||
- (direction_ == Direction::ALTERNATE_NORMAL && iteration % 2 == 1) ||
- (direction_ == Direction::ALTERNATE_REVERSE && iteration % 2 == 0);
-
- // If we are running the keyframe model in reverse direction, reverse the
- // result
- if (reverse)
- iteration_time = curve_->Duration() - iteration_time;
-
- return iteration_time;
-}
-
void KeyframeModel::PushPropertiesTo(KeyframeModel* other) const {
other->element_id_ = element_id_;
- if (run_state_ == KeyframeModel::PAUSED ||
- other->run_state_ == KeyframeModel::PAUSED) {
- other->run_state_ = run_state_;
- other->pause_time_ = pause_time_;
- other->total_paused_duration_ = total_paused_duration_;
+ if (run_state() == KeyframeModel::PAUSED ||
+ other->run_state() == KeyframeModel::PAUSED) {
+ other->ForceRunState(run_state());
+ other->set_pause_time(pause_time());
+ other->set_total_paused_duration(total_paused_duration());
}
}
std::string KeyframeModel::ToString() const {
return base::StringPrintf(
- "KeyframeModel{id=%d, group=%d, target_property_id=%d, "
- "run_state=%s}",
- id_, group_, target_property_id_,
- KeyframeModel::ToString(run_state_).c_str());
+ "KeyframeModel{id=%d, group=%d, target_property_type=%d, "
+ "custom_property_name=%s, native_property_type=%d, run_state=%s, "
+ "element_id=%s}",
+ id(), group_, TargetProperty(),
+ target_property_id_.custom_property_name().c_str(),
+ static_cast<int>(target_property_id_.native_property_type()),
+ gfx::KeyframeModel::ToString(run_state()).c_str(),
+ element_id_.ToString().c_str());
}
void KeyframeModel::SetIsImplOnly() {
@@ -362,4 +179,9 @@ void KeyframeModel::SetIsImplOnly() {
// controlling instance.
is_controlling_instance_ = true;
}
+
+bool KeyframeModel::StartShouldBeDeferred() const {
+ return needs_synchronized_start_time_;
+}
+
} // namespace cc
diff --git a/chromium/cc/animation/keyframe_model.h b/chromium/cc/animation/keyframe_model.h
index b7b52cd8cbf..22c2a9037f2 100644
--- a/chromium/cc/animation/keyframe_model.h
+++ b/chromium/cc/animation/keyframe_model.h
@@ -6,130 +6,87 @@
#define CC_ANIMATION_KEYFRAME_MODEL_H_
#include <memory>
+#include <string>
#include "base/optional.h"
#include "base/time/time.h"
#include "cc/animation/animation_export.h"
#include "cc/paint/element_id.h"
+#include "cc/paint/paint_worklet_input.h"
+#include "ui/gfx/animation/keyframe/keyframe_model.h"
namespace cc {
-class AnimationCurve;
-
// A KeyframeModel contains all the state required to play an AnimationCurve.
// Specifically, the affected property, the run state (paused, finished, etc.),
// loop count, last pause time, and the total time spent paused.
// It represents a model of the keyframes (internally represented as a curve).
-class CC_ANIMATION_EXPORT KeyframeModel {
+class CC_ANIMATION_EXPORT KeyframeModel : public gfx::KeyframeModel {
public:
- // KeyframeModels begin in the 'WAITING_FOR_TARGET_AVAILABILITY' state. A
- // KeyframeModel waiting for target availibility will run as soon as its
- // target property is free (and all the KeyframeModels animating with it are
- // also able to run). When this time arrives, the controller will move the
- // keyframe model into the STARTING state, and then into the RUNNING state.
- // RUNNING KeyframeModels may toggle between RUNNING and PAUSED, and may be
- // stopped by moving into either the ABORTED or FINISHED states. A FINISHED
- // keyframe model was allowed to run to completion, but an ABORTED keyframe
- // model was not. An animation in the state ABORTED_BUT_NEEDS_COMPLETION is a
- // keyframe model that was aborted for some reason, but needs to be finished.
- // Currently this is for impl-only scroll offset KeyframeModels that need to
- // be completed on the main thread.
- enum RunState {
- WAITING_FOR_TARGET_AVAILABILITY = 0,
- WAITING_FOR_DELETION,
- STARTING,
- RUNNING,
- PAUSED,
- FINISHED,
- ABORTED,
- ABORTED_BUT_NEEDS_COMPLETION,
- // This sentinel must be last.
- LAST_RUN_STATE = ABORTED_BUT_NEEDS_COMPLETION
+ static const KeyframeModel* ToCcKeyframeModel(
+ const gfx::KeyframeModel* keyframe_model);
+
+ static KeyframeModel* ToCcKeyframeModel(gfx::KeyframeModel* keyframe_model);
+
+ // Bundles a property id with its name and native type.
+ class CC_ANIMATION_EXPORT TargetPropertyId {
+ public:
+ // For a property that is neither TargetProperty::CSS_CUSTOM_PROPERTY nor
+ // TargetProperty::NATIVE_PROPERTY.
+ explicit TargetPropertyId(int target_property_type);
+ // For TargetProperty::CSS_CUSTOM_PROPERTY, the string is the custom
+ // property name.
+ TargetPropertyId(int target_property_type,
+ const std::string& custom_property_name);
+ // For TargetProperty::NATIVE_PROPERTY.
+ TargetPropertyId(
+ int target_property_type,
+ PaintWorkletInput::NativePropertyType native_property_type);
+ TargetPropertyId(const TargetPropertyId&);
+ ~TargetPropertyId();
+
+ int target_property_type() const { return target_property_type_; }
+ const std::string& custom_property_name() const {
+ return custom_property_name_;
+ }
+ PaintWorkletInput::NativePropertyType native_property_type() const {
+ return native_property_type_;
+ }
+
+ private:
+ int target_property_type_;
+ // Name of the animated custom property. Empty if it is an animated native
+ // property.
+ std::string custom_property_name_;
+ // Type of the animated native property.
+ PaintWorkletInput::NativePropertyType native_property_type_;
};
- static std::string ToString(RunState);
-
- enum class Direction { NORMAL, REVERSE, ALTERNATE_NORMAL, ALTERNATE_REVERSE };
-
- enum class FillMode { NONE, FORWARDS, BACKWARDS, BOTH, AUTO };
-
- enum class Phase { BEFORE, ACTIVE, AFTER };
- // The |custom_property_name| has a default value of an empty string,
- // indicating that the animated property is a native property. When it is an
- // animated custom property, it should be the property name.
static std::unique_ptr<KeyframeModel> Create(
- std::unique_ptr<AnimationCurve> curve,
+ std::unique_ptr<gfx::AnimationCurve> curve,
int keyframe_model_id,
int group_id,
- int target_property_id,
- const std::string& custom_property_name = "");
+ TargetPropertyId target_property_id);
std::unique_ptr<KeyframeModel> CreateImplInstance(
RunState initial_run_state) const;
KeyframeModel(const KeyframeModel&) = delete;
- virtual ~KeyframeModel();
+ ~KeyframeModel() override;
KeyframeModel& operator=(const KeyframeModel&) = delete;
- int id() const { return id_; }
int group() const { return group_; }
- int target_property_id() const { return target_property_id_; }
-
- ElementId element_id() const { return element_id_; }
- void set_element_id(ElementId element_id) { element_id_ = element_id; }
-
- RunState run_state() const { return run_state_; }
- void SetRunState(RunState run_state, base::TimeTicks monotonic_time);
-
- // This is the number of times that the keyframe model will play. If this
- // value is zero the keyframe model will not play. If it is negative, then
- // the keyframe model will loop indefinitely.
- double iterations() const { return iterations_; }
- void set_iterations(double n) { iterations_ = n; }
-
- double iteration_start() const { return iteration_start_; }
- void set_iteration_start(double iteration_start) {
- iteration_start_ = iteration_start;
- }
-
- base::TimeTicks start_time() const { return start_time_; }
-
- void set_start_time(base::TimeTicks monotonic_time) {
- start_time_ = monotonic_time;
- }
- bool has_set_start_time() const { return !start_time_.is_null(); }
-
- base::TimeDelta time_offset() const { return time_offset_; }
- void set_time_offset(base::TimeDelta monotonic_time) {
- time_offset_ = monotonic_time;
- }
- // Pause the keyframe effect at local time |pause_offset|.
- void Pause(base::TimeDelta pause_offset);
+ int TargetProperty() const override;
- Direction direction() { return direction_; }
- void set_direction(Direction direction) { direction_ = direction; }
+ void SetRunState(RunState run_state, base::TimeTicks monotonic_time) override;
- FillMode fill_mode() { return fill_mode_; }
- void set_fill_mode(FillMode fill_mode) { fill_mode_ = fill_mode; }
-
- double playback_rate() { return playback_rate_; }
- void set_playback_rate(double playback_rate) {
- playback_rate_ = playback_rate;
- }
-
- bool IsFinishedAt(base::TimeTicks monotonic_time) const;
- bool is_finished() const {
- return run_state_ == FINISHED || run_state_ == ABORTED ||
- run_state_ == WAITING_FOR_DELETION;
- }
+ ElementId element_id() const { return element_id_; }
+ void set_element_id(ElementId element_id) { element_id_ = element_id; }
bool InEffect(base::TimeTicks monotonic_time) const;
- AnimationCurve* curve() { return curve_.get(); }
- const AnimationCurve* curve() const { return curve_.get(); }
-
// If this is true, even if the keyframe model is running, it will not be
// tickable until it is given a start time. This is true for KeyframeModels
// running on the main thread.
@@ -148,11 +105,6 @@ class CC_ANIMATION_EXPORT KeyframeModel {
received_finished_event_ = received_finished_event;
}
- // Takes the given absolute time, and using the start time and the number
- // of iterations, returns the relative time in the current iteration.
- base::TimeDelta TrimTimeToCurrentIteration(
- base::TimeTicks monotonic_time) const;
-
void set_is_controlling_instance_for_test(bool is_controlling_instance) {
is_controlling_instance_ = is_controlling_instance;
}
@@ -176,90 +128,35 @@ class CC_ANIMATION_EXPORT KeyframeModel {
bool affects_pending_elements() const { return affects_pending_elements_; }
const std::string& custom_property_name() const {
- return custom_property_name_;
+ return target_property_id_.custom_property_name();
}
- KeyframeModel::Phase CalculatePhaseForTesting(
- base::TimeDelta local_time) const;
+ PaintWorkletInput::NativePropertyType native_property_type() const {
+ return target_property_id_.native_property_type();
+ }
+
+ bool StartShouldBeDeferred() const override;
private:
- KeyframeModel(std::unique_ptr<AnimationCurve> curve,
+ KeyframeModel(std::unique_ptr<gfx::AnimationCurve> curve,
int keyframe_model_id,
int group_id,
- int target_property_id,
- const std::string& custom_property_name);
-
- // Return local time for this keyframe model given the absolute monotonic
- // time.
- //
- // Local time represents the time value that is used to tick this keyframe
- // model and is relative to its start time. It is closely related to the local
- // time concept in web animations [1]. It is:
- // - for playing animation : wall time - start time - paused duration
- // - for paused animation : paused time
- // - otherwise : zero
- //
- // Here is small diagram that shows how active, local, and monotonic times
- // relate to each other and to the run state.
- //
- // run state Starting (R)unning Paused (R) Paused (R) Finished
- // ^ ^
- // | |
- // monotonic time ------------------------------------------------->
- // | |
- // local time +-----------------+ +---+ +--------->
- // | |
- // active time + +------+ +---+ +------+
- // (-offset)
- //
- // [1] https://drafts.csswg.org/web-animations/#local-time-section
- base::TimeDelta ConvertMonotonicTimeToLocalTime(
- base::TimeTicks monotonic_time) const;
-
- KeyframeModel::Phase CalculatePhase(base::TimeDelta local_time) const;
- base::Optional<base::TimeDelta> CalculateActiveTime(
- base::TimeTicks monotonic_time) const;
-
- std::unique_ptr<AnimationCurve> curve_;
-
- // IDs must be unique.
- int id_;
-
+ TargetPropertyId target_property_id);
// KeyframeModels that must be run together are called 'grouped' and have the
// same group id. Grouped KeyframeModels are guaranteed to start at the same
// time and no other KeyframeModels may animate any of the group's target
// properties until all KeyframeModels in the group have finished animating.
int group_;
+ TargetPropertyId target_property_id_;
+
// If specified, overrides the ElementId to apply this KeyframeModel's effect
// value on.
ElementId element_id_;
- int target_property_id_;
- RunState run_state_;
- double iterations_;
- double iteration_start_;
- base::TimeTicks start_time_;
- Direction direction_;
- double playback_rate_;
- FillMode fill_mode_;
-
- // The time offset effectively pushes the start of the keyframe model back in
- // time. This is used for resuming paused KeyframeModels -- an animation is
- // added with a non-zero time offset, causing the keyframe model to skip ahead
- // to the desired point in time.
- base::TimeDelta time_offset_;
-
bool needs_synchronized_start_time_;
bool received_finished_event_;
- // These are used when converting monotonic to local time to account for time
- // spent while paused. This is not included in AnimationState since it
- // there is absolutely no need for clients of this controller to know
- // about these values.
- base::TimeTicks pause_time_;
- base::TimeDelta total_paused_duration_;
-
// KeyframeModels lead dual lives. An active keyframe model will be
// conceptually owned by two controllers, one on the impl thread and one on
// the main. In reality, there will be two separate KeyframeModel instances
@@ -287,10 +184,6 @@ class CC_ANIMATION_EXPORT KeyframeModel {
// longer affect any elements, and are deleted.
bool affects_active_elements_;
bool affects_pending_elements_;
-
- // Name of the animated custom property. Empty if it is an animated native
- // property.
- std::string custom_property_name_;
};
} // namespace cc
diff --git a/chromium/cc/animation/keyframe_model_unittest.cc b/chromium/cc/animation/keyframe_model_unittest.cc
index 2d4e94bde8d..1e01ad2ac47 100644
--- a/chromium/cc/animation/keyframe_model_unittest.cc
+++ b/chromium/cc/animation/keyframe_model_unittest.cc
@@ -4,6 +4,8 @@
#include "cc/animation/keyframe_model.h"
+#include <limits>
+
#include "base/strings/stringprintf.h"
#include "cc/test/animation_test_common.h"
#include "cc/trees/target_property.h"
@@ -22,9 +24,9 @@ static base::TimeTicks TicksFromSecondsF(double seconds) {
std::unique_ptr<KeyframeModel> CreateKeyframeModel(double iterations,
double duration,
double playback_rate) {
- std::unique_ptr<KeyframeModel> to_return(
- KeyframeModel::Create(std::make_unique<FakeFloatAnimationCurve>(duration),
- 0, 1, TargetProperty::OPACITY));
+ std::unique_ptr<KeyframeModel> to_return(KeyframeModel::Create(
+ std::make_unique<FakeFloatAnimationCurve>(duration), 0, 1,
+ KeyframeModel::TargetPropertyId(TargetProperty::OPACITY)));
to_return->set_iterations(iterations);
to_return->set_playback_rate(playback_rate);
return to_return;
@@ -1381,27 +1383,29 @@ TEST(KeyframeModelTest, CalculatePhaseWithMinTimeOffset) {
}
TEST(KeyframeModelTest, ToString) {
- std::unique_ptr<KeyframeModel> keyframe_model =
- KeyframeModel::Create(std::make_unique<FakeFloatAnimationCurve>(15), 42,
- 73, TargetProperty::OPACITY);
- EXPECT_EQ(
- base::StringPrintf("KeyframeModel{id=%d, group=73, target_property_id=1, "
- "run_state=WAITING_FOR_TARGET_AVAILABILITY}",
- keyframe_model->id()),
- keyframe_model->ToString());
+ std::unique_ptr<KeyframeModel> keyframe_model = KeyframeModel::Create(
+ std::make_unique<FakeFloatAnimationCurve>(15), 42, 73,
+ KeyframeModel::TargetPropertyId(TargetProperty::OPACITY));
+ EXPECT_EQ(base::StringPrintf(
+ "KeyframeModel{id=%d, group=73, target_property_type=1, "
+ "custom_property_name=, native_property_type=1, "
+ "run_state=WAITING_FOR_TARGET_AVAILABILITY, element_id=(0)}",
+ keyframe_model->id()),
+ keyframe_model->ToString());
}
TEST(KeyframeModelTest, CustomPropertyKeyframe) {
std::unique_ptr<KeyframeModel> keyframe_model =
KeyframeModel::Create(std::make_unique<FakeFloatAnimationCurve>(1), 1, 1,
- TargetProperty::CSS_CUSTOM_PROPERTY, "foo");
+ KeyframeModel::TargetPropertyId(
+ TargetProperty::CSS_CUSTOM_PROPERTY, "foo"));
EXPECT_EQ(keyframe_model->custom_property_name(), "foo");
}
TEST(KeyframeModelTest, NonCustomPropertyKeyframe) {
- std::unique_ptr<KeyframeModel> keyframe_model =
- KeyframeModel::Create(std::make_unique<FakeFloatAnimationCurve>(1), 1, 1,
- TargetProperty::TRANSFORM);
+ std::unique_ptr<KeyframeModel> keyframe_model = KeyframeModel::Create(
+ std::make_unique<FakeFloatAnimationCurve>(1), 1, 1,
+ KeyframeModel::TargetPropertyId(TargetProperty::TRANSFORM));
EXPECT_EQ(keyframe_model->custom_property_name(), "");
}
diff --git a/chromium/cc/animation/keyframed_animation_curve.cc b/chromium/cc/animation/keyframed_animation_curve.cc
deleted file mode 100644
index ce679e5d8e8..00000000000
--- a/chromium/cc/animation/keyframed_animation_curve.cc
+++ /dev/null
@@ -1,548 +0,0 @@
-// Copyright 2012 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/animation/keyframed_animation_curve.h"
-
-#include <stddef.h>
-
-#include <algorithm>
-#include <memory>
-#include <utility>
-
-#include "base/memory/ptr_util.h"
-#include "ui/gfx/animation/tween.h"
-#include "ui/gfx/geometry/box_f.h"
-
-namespace cc {
-
-namespace {
-
-template <class KeyframeType>
-void InsertKeyframe(std::unique_ptr<KeyframeType> keyframe,
- std::vector<std::unique_ptr<KeyframeType>>* keyframes) {
- // Usually, the keyframes will be added in order, so this loop would be
- // unnecessary and we should skip it if possible.
- if (!keyframes->empty() && keyframe->Time() < keyframes->back()->Time()) {
- for (size_t i = 0; i < keyframes->size(); ++i) {
- if (keyframe->Time() < keyframes->at(i)->Time()) {
- keyframes->insert(keyframes->begin() + i, std::move(keyframe));
- return;
- }
- }
- }
-
- keyframes->push_back(std::move(keyframe));
-}
-
-template <typename KeyframeType>
-base::TimeDelta TransformedAnimationTime(
- const std::vector<std::unique_ptr<KeyframeType>>& keyframes,
- const std::unique_ptr<TimingFunction>& timing_function,
- double scaled_duration,
- base::TimeDelta time) {
- if (timing_function) {
- base::TimeDelta start_time = keyframes.front()->Time() * scaled_duration;
- base::TimeDelta duration =
- (keyframes.back()->Time() - keyframes.front()->Time()) *
- scaled_duration;
- const double progress =
- duration.is_zero() ? 1.0 : ((time - start_time) / duration);
-
- time = (duration * timing_function->GetValue(progress)) + start_time;
- }
-
- return time;
-}
-
-template <typename KeyframeType>
-size_t GetActiveKeyframe(
- const std::vector<std::unique_ptr<KeyframeType>>& keyframes,
- double scaled_duration,
- base::TimeDelta time) {
- DCHECK_GE(keyframes.size(), 2ul);
- size_t i = 0;
- while ((i < keyframes.size() - 2) && // Last keyframe is never active.
- (time >= (keyframes[i + 1]->Time() * scaled_duration)))
- ++i;
-
- return i;
-}
-
-template <typename KeyframeType>
-double TransformedKeyframeProgress(
- const std::vector<std::unique_ptr<KeyframeType>>& keyframes,
- double scaled_duration,
- base::TimeDelta time,
- size_t i) {
- const base::TimeDelta start_time = keyframes[i]->Time() * scaled_duration;
- const base::TimeDelta duration =
- keyframes[i + 1]->Time() * scaled_duration - start_time;
- const double progress =
- duration.is_zero() ? 1.0 : ((time - start_time) / duration);
-
- return keyframes[i]->timing_function()
- ? keyframes[i]->timing_function()->GetValue(progress)
- : progress;
-}
-
-} // namespace
-
-Keyframe::Keyframe(base::TimeDelta time,
- std::unique_ptr<TimingFunction> timing_function)
- : time_(time), timing_function_(std::move(timing_function)) {}
-
-Keyframe::~Keyframe() = default;
-
-base::TimeDelta Keyframe::Time() const {
- return time_;
-}
-
-std::unique_ptr<ColorKeyframe> ColorKeyframe::Create(
- base::TimeDelta time,
- SkColor value,
- std::unique_ptr<TimingFunction> timing_function) {
- return base::WrapUnique(
- new ColorKeyframe(time, value, std::move(timing_function)));
-}
-
-ColorKeyframe::ColorKeyframe(base::TimeDelta time,
- SkColor value,
- std::unique_ptr<TimingFunction> timing_function)
- : Keyframe(time, std::move(timing_function)), value_(value) {}
-
-ColorKeyframe::~ColorKeyframe() = default;
-
-SkColor ColorKeyframe::Value() const { return value_; }
-
-std::unique_ptr<ColorKeyframe> ColorKeyframe::Clone() const {
- std::unique_ptr<TimingFunction> func;
- if (timing_function())
- func = timing_function()->Clone();
- return ColorKeyframe::Create(Time(), Value(), std::move(func));
-}
-
-std::unique_ptr<FloatKeyframe> FloatKeyframe::Create(
- base::TimeDelta time,
- float value,
- std::unique_ptr<TimingFunction> timing_function) {
- return base::WrapUnique(
- new FloatKeyframe(time, value, std::move(timing_function)));
-}
-
-FloatKeyframe::FloatKeyframe(base::TimeDelta time,
- float value,
- std::unique_ptr<TimingFunction> timing_function)
- : Keyframe(time, std::move(timing_function)), value_(value) {}
-
-FloatKeyframe::~FloatKeyframe() = default;
-
-float FloatKeyframe::Value() const {
- return value_;
-}
-
-std::unique_ptr<FloatKeyframe> FloatKeyframe::Clone() const {
- std::unique_ptr<TimingFunction> func;
- if (timing_function())
- func = timing_function()->Clone();
- return FloatKeyframe::Create(Time(), Value(), std::move(func));
-}
-
-std::unique_ptr<TransformKeyframe> TransformKeyframe::Create(
- base::TimeDelta time,
- const TransformOperations& value,
- std::unique_ptr<TimingFunction> timing_function) {
- return base::WrapUnique(
- new TransformKeyframe(time, value, std::move(timing_function)));
-}
-
-TransformKeyframe::TransformKeyframe(
- base::TimeDelta time,
- const TransformOperations& value,
- std::unique_ptr<TimingFunction> timing_function)
- : Keyframe(time, std::move(timing_function)), value_(value) {}
-
-TransformKeyframe::~TransformKeyframe() = default;
-
-const TransformOperations& TransformKeyframe::Value() const {
- return value_;
-}
-
-std::unique_ptr<TransformKeyframe> TransformKeyframe::Clone() const {
- std::unique_ptr<TimingFunction> func;
- if (timing_function())
- func = timing_function()->Clone();
- return TransformKeyframe::Create(Time(), Value(), std::move(func));
-}
-
-std::unique_ptr<FilterKeyframe> FilterKeyframe::Create(
- base::TimeDelta time,
- const FilterOperations& value,
- std::unique_ptr<TimingFunction> timing_function) {
- return base::WrapUnique(
- new FilterKeyframe(time, value, std::move(timing_function)));
-}
-
-FilterKeyframe::FilterKeyframe(base::TimeDelta time,
- const FilterOperations& value,
- std::unique_ptr<TimingFunction> timing_function)
- : Keyframe(time, std::move(timing_function)), value_(value) {}
-
-FilterKeyframe::~FilterKeyframe() = default;
-
-const FilterOperations& FilterKeyframe::Value() const {
- return value_;
-}
-
-std::unique_ptr<FilterKeyframe> FilterKeyframe::Clone() const {
- std::unique_ptr<TimingFunction> func;
- if (timing_function())
- func = timing_function()->Clone();
- return FilterKeyframe::Create(Time(), Value(), std::move(func));
-}
-
-std::unique_ptr<SizeKeyframe> SizeKeyframe::Create(
- base::TimeDelta time,
- const gfx::SizeF& value,
- std::unique_ptr<TimingFunction> timing_function) {
- return base::WrapUnique(
- new SizeKeyframe(time, value, std::move(timing_function)));
-}
-
-SizeKeyframe::SizeKeyframe(base::TimeDelta time,
- const gfx::SizeF& value,
- std::unique_ptr<TimingFunction> timing_function)
- : Keyframe(time, std::move(timing_function)), value_(value) {}
-
-SizeKeyframe::~SizeKeyframe() = default;
-
-const gfx::SizeF& SizeKeyframe::Value() const {
- return value_;
-}
-
-std::unique_ptr<SizeKeyframe> SizeKeyframe::Clone() const {
- std::unique_ptr<TimingFunction> func;
- if (timing_function())
- func = timing_function()->Clone();
- return SizeKeyframe::Create(Time(), Value(), std::move(func));
-}
-
-std::unique_ptr<KeyframedColorAnimationCurve>
-KeyframedColorAnimationCurve::Create() {
- return base::WrapUnique(new KeyframedColorAnimationCurve);
-}
-
-KeyframedColorAnimationCurve::KeyframedColorAnimationCurve()
- : scaled_duration_(1.0) {}
-
-KeyframedColorAnimationCurve::~KeyframedColorAnimationCurve() = default;
-
-void KeyframedColorAnimationCurve::AddKeyframe(
- std::unique_ptr<ColorKeyframe> keyframe) {
- InsertKeyframe(std::move(keyframe), &keyframes_);
-}
-
-base::TimeDelta KeyframedColorAnimationCurve::Duration() const {
- return (keyframes_.back()->Time() - keyframes_.front()->Time()) *
- scaled_duration();
-}
-
-std::unique_ptr<AnimationCurve> KeyframedColorAnimationCurve::Clone() const {
- std::unique_ptr<KeyframedColorAnimationCurve> to_return =
- KeyframedColorAnimationCurve::Create();
- for (const auto& keyframe : keyframes_)
- to_return->AddKeyframe(keyframe->Clone());
-
- if (timing_function_)
- to_return->SetTimingFunction(timing_function_->Clone());
-
- to_return->set_scaled_duration(scaled_duration());
-
- return std::move(to_return);
-}
-
-SkColor KeyframedColorAnimationCurve::GetValue(base::TimeDelta t) const {
- if (t <= (keyframes_.front()->Time() * scaled_duration()))
- return keyframes_.front()->Value();
-
- if (t >= (keyframes_.back()->Time() * scaled_duration()))
- return keyframes_.back()->Value();
-
- t = TransformedAnimationTime(keyframes_, timing_function_, scaled_duration(),
- t);
- size_t i = GetActiveKeyframe(keyframes_, scaled_duration(), t);
- double progress =
- TransformedKeyframeProgress(keyframes_, scaled_duration(), t, i);
-
- return gfx::Tween::ColorValueBetween(
- progress, keyframes_[i]->Value(), keyframes_[i + 1]->Value());
-}
-
-std::unique_ptr<KeyframedFloatAnimationCurve>
-KeyframedFloatAnimationCurve::Create() {
- return base::WrapUnique(new KeyframedFloatAnimationCurve);
-}
-
-KeyframedFloatAnimationCurve::KeyframedFloatAnimationCurve()
- : scaled_duration_(1.0) {}
-
-KeyframedFloatAnimationCurve::~KeyframedFloatAnimationCurve() = default;
-
-void KeyframedFloatAnimationCurve::AddKeyframe(
- std::unique_ptr<FloatKeyframe> keyframe) {
- InsertKeyframe(std::move(keyframe), &keyframes_);
-}
-
-base::TimeDelta KeyframedFloatAnimationCurve::Duration() const {
- return (keyframes_.back()->Time() - keyframes_.front()->Time()) *
- scaled_duration();
-}
-
-std::unique_ptr<AnimationCurve> KeyframedFloatAnimationCurve::Clone() const {
- std::unique_ptr<KeyframedFloatAnimationCurve> to_return =
- KeyframedFloatAnimationCurve::Create();
- for (const auto& keyframe : keyframes_)
- to_return->AddKeyframe(keyframe->Clone());
-
- if (timing_function_)
- to_return->SetTimingFunction(timing_function_->Clone());
-
- to_return->set_scaled_duration(scaled_duration());
-
- return std::move(to_return);
-}
-
-float KeyframedFloatAnimationCurve::GetValue(base::TimeDelta t) const {
- if (t <= (keyframes_.front()->Time() * scaled_duration()))
- return keyframes_.front()->Value();
-
- if (t >= (keyframes_.back()->Time() * scaled_duration()))
- return keyframes_.back()->Value();
-
- t = TransformedAnimationTime(keyframes_, timing_function_, scaled_duration(),
- t);
- size_t i = GetActiveKeyframe(keyframes_, scaled_duration(), t);
- double progress =
- TransformedKeyframeProgress(keyframes_, scaled_duration(), t, i);
-
- return keyframes_[i]->Value() +
- (keyframes_[i+1]->Value() - keyframes_[i]->Value()) * progress;
-}
-
-std::unique_ptr<KeyframedTransformAnimationCurve>
-KeyframedTransformAnimationCurve::Create() {
- return base::WrapUnique(new KeyframedTransformAnimationCurve);
-}
-
-KeyframedTransformAnimationCurve::KeyframedTransformAnimationCurve()
- : scaled_duration_(1.0) {}
-
-KeyframedTransformAnimationCurve::~KeyframedTransformAnimationCurve() = default;
-
-void KeyframedTransformAnimationCurve::AddKeyframe(
- std::unique_ptr<TransformKeyframe> keyframe) {
- InsertKeyframe(std::move(keyframe), &keyframes_);
-}
-
-base::TimeDelta KeyframedTransformAnimationCurve::Duration() const {
- return (keyframes_.back()->Time() - keyframes_.front()->Time()) *
- scaled_duration();
-}
-
-std::unique_ptr<AnimationCurve> KeyframedTransformAnimationCurve::Clone()
- const {
- std::unique_ptr<KeyframedTransformAnimationCurve> to_return =
- KeyframedTransformAnimationCurve::Create();
- for (const auto& keyframe : keyframes_)
- to_return->AddKeyframe(keyframe->Clone());
-
- if (timing_function_)
- to_return->SetTimingFunction(timing_function_->Clone());
-
- to_return->set_scaled_duration(scaled_duration());
-
- return std::move(to_return);
-}
-
-TransformOperations KeyframedTransformAnimationCurve::GetValue(
- base::TimeDelta t) const {
- if (t <= (keyframes_.front()->Time() * scaled_duration()))
- return keyframes_.front()->Value();
-
- if (t >= (keyframes_.back()->Time() * scaled_duration()))
- return keyframes_.back()->Value();
-
- t = TransformedAnimationTime(keyframes_, timing_function_, scaled_duration(),
- t);
- size_t i = GetActiveKeyframe(keyframes_, scaled_duration(), t);
- double progress =
- TransformedKeyframeProgress(keyframes_, scaled_duration(), t, i);
-
- return keyframes_[i + 1]->Value().Blend(keyframes_[i]->Value(), progress);
-}
-
-bool KeyframedTransformAnimationCurve::PreservesAxisAlignment() const {
- for (const auto& keyframe : keyframes_) {
- if (!keyframe->Value().PreservesAxisAlignment())
- return false;
- }
- return true;
-}
-
-bool KeyframedTransformAnimationCurve::IsTranslation() const {
- for (const auto& keyframe : keyframes_) {
- if (!keyframe->Value().IsTranslation() && !keyframe->Value().IsIdentity())
- return false;
- }
- return true;
-}
-
-bool KeyframedTransformAnimationCurve::AnimationStartScale(
- bool forward_direction,
- float* start_scale) const {
- DCHECK_GE(keyframes_.size(), 2ul);
- *start_scale = 0.f;
- size_t start_location = 0;
- if (!forward_direction) {
- start_location = keyframes_.size() - 1;
- }
-
- return keyframes_[start_location]->Value().ScaleComponent(start_scale);
-}
-
-bool KeyframedTransformAnimationCurve::MaximumTargetScale(
- bool forward_direction,
- float* max_scale) const {
- DCHECK_GE(keyframes_.size(), 2ul);
- *max_scale = 0.f;
-
- // If |forward_direction| is true, then skip the first frame, otherwise
- // skip the last frame, since that is the original position in the animation.
- size_t start = 1;
- size_t end = keyframes_.size();
- if (!forward_direction) {
- --start;
- --end;
- }
-
- for (size_t i = start; i < end; ++i) {
- float target_scale_for_segment = 0.f;
- if (!keyframes_[i]->Value().ScaleComponent(&target_scale_for_segment))
- return false;
- *max_scale = fmax(*max_scale, target_scale_for_segment);
- }
- return true;
-}
-
-std::unique_ptr<KeyframedFilterAnimationCurve>
-KeyframedFilterAnimationCurve::Create() {
- return base::WrapUnique(new KeyframedFilterAnimationCurve);
-}
-
-KeyframedFilterAnimationCurve::KeyframedFilterAnimationCurve()
- : scaled_duration_(1.0) {}
-
-KeyframedFilterAnimationCurve::~KeyframedFilterAnimationCurve() = default;
-
-void KeyframedFilterAnimationCurve::AddKeyframe(
- std::unique_ptr<FilterKeyframe> keyframe) {
- InsertKeyframe(std::move(keyframe), &keyframes_);
-}
-
-base::TimeDelta KeyframedFilterAnimationCurve::Duration() const {
- return (keyframes_.back()->Time() - keyframes_.front()->Time()) *
- scaled_duration();
-}
-
-std::unique_ptr<AnimationCurve> KeyframedFilterAnimationCurve::Clone() const {
- std::unique_ptr<KeyframedFilterAnimationCurve> to_return =
- KeyframedFilterAnimationCurve::Create();
- for (const auto& keyframe : keyframes_)
- to_return->AddKeyframe(keyframe->Clone());
-
- if (timing_function_)
- to_return->SetTimingFunction(timing_function_->Clone());
-
- to_return->set_scaled_duration(scaled_duration());
-
- return std::move(to_return);
-}
-
-FilterOperations KeyframedFilterAnimationCurve::GetValue(
- base::TimeDelta t) const {
- if (t <= (keyframes_.front()->Time() * scaled_duration()))
- return keyframes_.front()->Value();
-
- if (t >= (keyframes_.back()->Time() * scaled_duration()))
- return keyframes_.back()->Value();
-
- t = TransformedAnimationTime(keyframes_, timing_function_, scaled_duration(),
- t);
- size_t i = GetActiveKeyframe(keyframes_, scaled_duration(), t);
- double progress =
- TransformedKeyframeProgress(keyframes_, scaled_duration(), t, i);
-
- return keyframes_[i + 1]->Value().Blend(keyframes_[i]->Value(), progress);
-}
-
-bool KeyframedFilterAnimationCurve::HasFilterThatMovesPixels() const {
- for (const auto& keyframe : keyframes_) {
- if (keyframe->Value().HasFilterThatMovesPixels()) {
- return true;
- }
- }
- return false;
-}
-
-std::unique_ptr<KeyframedSizeAnimationCurve>
-KeyframedSizeAnimationCurve::Create() {
- return base::WrapUnique(new KeyframedSizeAnimationCurve);
-}
-
-KeyframedSizeAnimationCurve::KeyframedSizeAnimationCurve()
- : scaled_duration_(1.0) {}
-
-KeyframedSizeAnimationCurve::~KeyframedSizeAnimationCurve() = default;
-
-void KeyframedSizeAnimationCurve::AddKeyframe(
- std::unique_ptr<SizeKeyframe> keyframe) {
- InsertKeyframe(std::move(keyframe), &keyframes_);
-}
-
-base::TimeDelta KeyframedSizeAnimationCurve::Duration() const {
- return (keyframes_.back()->Time() - keyframes_.front()->Time()) *
- scaled_duration();
-}
-
-std::unique_ptr<AnimationCurve> KeyframedSizeAnimationCurve::Clone() const {
- std::unique_ptr<KeyframedSizeAnimationCurve> to_return =
- KeyframedSizeAnimationCurve::Create();
- for (const auto& keyframe : keyframes_)
- to_return->AddKeyframe(keyframe->Clone());
-
- if (timing_function_)
- to_return->SetTimingFunction(timing_function_->Clone());
-
- to_return->set_scaled_duration(scaled_duration());
-
- return std::move(to_return);
-}
-
-gfx::SizeF KeyframedSizeAnimationCurve::GetValue(base::TimeDelta t) const {
- if (t <= (keyframes_.front()->Time() * scaled_duration()))
- return keyframes_.front()->Value();
-
- if (t >= (keyframes_.back()->Time() * scaled_duration()))
- return keyframes_.back()->Value();
-
- t = TransformedAnimationTime(keyframes_, timing_function_, scaled_duration(),
- t);
- size_t i = GetActiveKeyframe(keyframes_, scaled_duration(), t);
- double progress =
- TransformedKeyframeProgress(keyframes_, scaled_duration(), t, i);
-
- return gfx::Tween::SizeFValueBetween(progress, keyframes_[i]->Value(),
- keyframes_[i + 1]->Value());
-}
-
-} // namespace cc
diff --git a/chromium/cc/animation/keyframed_animation_curve.h b/chromium/cc/animation/keyframed_animation_curve.h
deleted file mode 100644
index c843fc7f782..00000000000
--- a/chromium/cc/animation/keyframed_animation_curve.h
+++ /dev/null
@@ -1,349 +0,0 @@
-// Copyright 2012 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_ANIMATION_KEYFRAMED_ANIMATION_CURVE_H_
-#define CC_ANIMATION_KEYFRAMED_ANIMATION_CURVE_H_
-
-#include <vector>
-
-#include "base/time/time.h"
-#include "cc/animation/animation_curve.h"
-#include "cc/animation/animation_export.h"
-#include "cc/animation/timing_function.h"
-#include "cc/animation/transform_operations.h"
-#include "ui/gfx/geometry/size_f.h"
-
-namespace cc {
-
-class CC_ANIMATION_EXPORT Keyframe {
- public:
- Keyframe(const Keyframe&) = delete;
- Keyframe& operator=(const Keyframe&) = delete;
-
- base::TimeDelta Time() const;
- const TimingFunction* timing_function() const {
- return timing_function_.get();
- }
-
- protected:
- Keyframe(base::TimeDelta time,
- std::unique_ptr<TimingFunction> timing_function);
- virtual ~Keyframe();
-
- private:
- base::TimeDelta time_;
- std::unique_ptr<TimingFunction> timing_function_;
-};
-
-class CC_ANIMATION_EXPORT ColorKeyframe : public Keyframe {
- public:
- static std::unique_ptr<ColorKeyframe> Create(
- base::TimeDelta time,
- SkColor value,
- std::unique_ptr<TimingFunction> timing_function);
- ~ColorKeyframe() override;
-
- SkColor Value() const;
-
- std::unique_ptr<ColorKeyframe> Clone() const;
-
- private:
- ColorKeyframe(base::TimeDelta time,
- SkColor value,
- std::unique_ptr<TimingFunction> timing_function);
-
- SkColor value_;
-};
-
-class CC_ANIMATION_EXPORT FloatKeyframe : public Keyframe {
- public:
- static std::unique_ptr<FloatKeyframe> Create(
- base::TimeDelta time,
- float value,
- std::unique_ptr<TimingFunction> timing_function);
- ~FloatKeyframe() override;
-
- float Value() const;
-
- std::unique_ptr<FloatKeyframe> Clone() const;
-
- private:
- FloatKeyframe(base::TimeDelta time,
- float value,
- std::unique_ptr<TimingFunction> timing_function);
-
- float value_;
-};
-
-class CC_ANIMATION_EXPORT TransformKeyframe : public Keyframe {
- public:
- static std::unique_ptr<TransformKeyframe> Create(
- base::TimeDelta time,
- const TransformOperations& value,
- std::unique_ptr<TimingFunction> timing_function);
- ~TransformKeyframe() override;
-
- const TransformOperations& Value() const;
-
- std::unique_ptr<TransformKeyframe> Clone() const;
-
- private:
- TransformKeyframe(base::TimeDelta time,
- const TransformOperations& value,
- std::unique_ptr<TimingFunction> timing_function);
-
- TransformOperations value_;
-};
-
-class CC_ANIMATION_EXPORT FilterKeyframe : public Keyframe {
- public:
- static std::unique_ptr<FilterKeyframe> Create(
- base::TimeDelta time,
- const FilterOperations& value,
- std::unique_ptr<TimingFunction> timing_function);
- ~FilterKeyframe() override;
-
- const FilterOperations& Value() const;
-
- std::unique_ptr<FilterKeyframe> Clone() const;
-
- private:
- FilterKeyframe(base::TimeDelta time,
- const FilterOperations& value,
- std::unique_ptr<TimingFunction> timing_function);
-
- FilterOperations value_;
-};
-
-class CC_ANIMATION_EXPORT SizeKeyframe : public Keyframe {
- public:
- static std::unique_ptr<SizeKeyframe> Create(
- base::TimeDelta time,
- const gfx::SizeF& bounds,
- std::unique_ptr<TimingFunction> timing_function);
- ~SizeKeyframe() override;
-
- const gfx::SizeF& Value() const;
-
- std::unique_ptr<SizeKeyframe> Clone() const;
-
- private:
- SizeKeyframe(base::TimeDelta time,
- const gfx::SizeF& value,
- std::unique_ptr<TimingFunction> timing_function);
-
- gfx::SizeF value_;
-};
-
-class CC_ANIMATION_EXPORT KeyframedColorAnimationCurve
- : public ColorAnimationCurve {
- public:
- // It is required that the keyframes be sorted by time.
- static std::unique_ptr<KeyframedColorAnimationCurve> Create();
-
- KeyframedColorAnimationCurve(const KeyframedColorAnimationCurve&) = delete;
- ~KeyframedColorAnimationCurve() override;
-
- KeyframedColorAnimationCurve& operator=(const KeyframedColorAnimationCurve&) =
- delete;
-
- void AddKeyframe(std::unique_ptr<ColorKeyframe> keyframe);
- void SetTimingFunction(std::unique_ptr<TimingFunction> timing_function) {
- timing_function_ = std::move(timing_function);
- }
- double scaled_duration() const { return scaled_duration_; }
- void set_scaled_duration(double scaled_duration) {
- scaled_duration_ = scaled_duration;
- }
-
- // AnimationCurve implementation
- base::TimeDelta Duration() const override;
- std::unique_ptr<AnimationCurve> Clone() const override;
-
- // BackgrounColorAnimationCurve implementation
- SkColor GetValue(base::TimeDelta t) const override;
-
- using Keyframes = std::vector<std::unique_ptr<ColorKeyframe>>;
- const Keyframes& keyframes_for_testing() const { return keyframes_; }
-
- private:
- KeyframedColorAnimationCurve();
-
- // Always sorted in order of increasing time. No two keyframes have the
- // same time.
- Keyframes keyframes_;
- std::unique_ptr<TimingFunction> timing_function_;
- double scaled_duration_;
-};
-
-class CC_ANIMATION_EXPORT KeyframedFloatAnimationCurve
- : public FloatAnimationCurve {
- public:
- // It is required that the keyframes be sorted by time.
- static std::unique_ptr<KeyframedFloatAnimationCurve> Create();
-
- KeyframedFloatAnimationCurve(const KeyframedFloatAnimationCurve&) = delete;
- ~KeyframedFloatAnimationCurve() override;
-
- KeyframedFloatAnimationCurve& operator=(const KeyframedFloatAnimationCurve&) =
- delete;
-
- void AddKeyframe(std::unique_ptr<FloatKeyframe> keyframe);
-
- void SetTimingFunction(std::unique_ptr<TimingFunction> timing_function) {
- timing_function_ = std::move(timing_function);
- }
- TimingFunction* timing_function_for_testing() const {
- return timing_function_.get();
- }
- double scaled_duration() const { return scaled_duration_; }
- void set_scaled_duration(double scaled_duration) {
- scaled_duration_ = scaled_duration;
- }
-
- // AnimationCurve implementation
- base::TimeDelta Duration() const override;
- std::unique_ptr<AnimationCurve> Clone() const override;
-
- // FloatAnimationCurve implementation
- float GetValue(base::TimeDelta t) const override;
-
- using Keyframes = std::vector<std::unique_ptr<FloatKeyframe>>;
- const Keyframes& keyframes_for_testing() const { return keyframes_; }
-
- private:
- KeyframedFloatAnimationCurve();
-
- // Always sorted in order of increasing time. No two keyframes have the
- // same time.
- Keyframes keyframes_;
- std::unique_ptr<TimingFunction> timing_function_;
- double scaled_duration_;
-};
-
-class CC_ANIMATION_EXPORT KeyframedTransformAnimationCurve
- : public TransformAnimationCurve {
- public:
- // It is required that the keyframes be sorted by time.
- static std::unique_ptr<KeyframedTransformAnimationCurve> Create();
-
- KeyframedTransformAnimationCurve(const KeyframedTransformAnimationCurve&) =
- delete;
- ~KeyframedTransformAnimationCurve() override;
-
- KeyframedTransformAnimationCurve& operator=(
- const KeyframedTransformAnimationCurve&) = delete;
-
- void AddKeyframe(std::unique_ptr<TransformKeyframe> keyframe);
- void SetTimingFunction(std::unique_ptr<TimingFunction> timing_function) {
- timing_function_ = std::move(timing_function);
- }
- double scaled_duration() const { return scaled_duration_; }
- void set_scaled_duration(double scaled_duration) {
- scaled_duration_ = scaled_duration;
- }
-
- // AnimationCurve implementation
- base::TimeDelta Duration() const override;
- std::unique_ptr<AnimationCurve> Clone() const override;
-
- // TransformAnimationCurve implementation
- TransformOperations GetValue(base::TimeDelta t) const override;
- bool PreservesAxisAlignment() const override;
- bool IsTranslation() const override;
- bool AnimationStartScale(bool forward_direction,
- float* start_scale) const override;
- bool MaximumTargetScale(bool forward_direction,
- float* max_scale) const override;
-
- private:
- KeyframedTransformAnimationCurve();
-
- // Always sorted in order of increasing time. No two keyframes have the
- // same time.
- std::vector<std::unique_ptr<TransformKeyframe>> keyframes_;
- std::unique_ptr<TimingFunction> timing_function_;
- double scaled_duration_;
-};
-
-class CC_ANIMATION_EXPORT KeyframedFilterAnimationCurve
- : public FilterAnimationCurve {
- public:
- // It is required that the keyframes be sorted by time.
- static std::unique_ptr<KeyframedFilterAnimationCurve> Create();
-
- KeyframedFilterAnimationCurve(const KeyframedFilterAnimationCurve&) = delete;
- ~KeyframedFilterAnimationCurve() override;
-
- KeyframedFilterAnimationCurve& operator=(
- const KeyframedFilterAnimationCurve&) = delete;
-
- void AddKeyframe(std::unique_ptr<FilterKeyframe> keyframe);
- void SetTimingFunction(std::unique_ptr<TimingFunction> timing_function) {
- timing_function_ = std::move(timing_function);
- }
- double scaled_duration() const { return scaled_duration_; }
- void set_scaled_duration(double scaled_duration) {
- scaled_duration_ = scaled_duration;
- }
-
- // AnimationCurve implementation
- base::TimeDelta Duration() const override;
- std::unique_ptr<AnimationCurve> Clone() const override;
-
- // FilterAnimationCurve implementation
- FilterOperations GetValue(base::TimeDelta t) const override;
- bool HasFilterThatMovesPixels() const override;
-
- private:
- KeyframedFilterAnimationCurve();
-
- // Always sorted in order of increasing time. No two keyframes have the
- // same time.
- std::vector<std::unique_ptr<FilterKeyframe>> keyframes_;
- std::unique_ptr<TimingFunction> timing_function_;
- double scaled_duration_;
-};
-
-class CC_ANIMATION_EXPORT KeyframedSizeAnimationCurve
- : public SizeAnimationCurve {
- public:
- // It is required that the keyframes be sorted by time.
- static std::unique_ptr<KeyframedSizeAnimationCurve> Create();
-
- KeyframedSizeAnimationCurve(const KeyframedSizeAnimationCurve&) = delete;
- ~KeyframedSizeAnimationCurve() override;
-
- KeyframedSizeAnimationCurve& operator=(const KeyframedSizeAnimationCurve&) =
- delete;
-
- void AddKeyframe(std::unique_ptr<SizeKeyframe> keyframe);
- void SetTimingFunction(std::unique_ptr<TimingFunction> timing_function) {
- timing_function_ = std::move(timing_function);
- }
- double scaled_duration() const { return scaled_duration_; }
- void set_scaled_duration(double scaled_duration) {
- scaled_duration_ = scaled_duration;
- }
-
- // AnimationCurve implementation
- base::TimeDelta Duration() const override;
- std::unique_ptr<AnimationCurve> Clone() const override;
-
- // SizeAnimationCurve implementation
- gfx::SizeF GetValue(base::TimeDelta t) const override;
-
- private:
- KeyframedSizeAnimationCurve();
-
- // Always sorted in order of increasing time. No two keyframes have the
- // same time.
- std::vector<std::unique_ptr<SizeKeyframe>> keyframes_;
- std::unique_ptr<TimingFunction> timing_function_;
- double scaled_duration_;
-};
-
-} // namespace cc
-
-#endif // CC_ANIMATION_KEYFRAMED_ANIMATION_CURVE_H_
diff --git a/chromium/cc/animation/keyframed_animation_curve_unittest.cc b/chromium/cc/animation/keyframed_animation_curve_unittest.cc
deleted file mode 100644
index ba2cfbac84c..00000000000
--- a/chromium/cc/animation/keyframed_animation_curve_unittest.cc
+++ /dev/null
@@ -1,1093 +0,0 @@
-// Copyright 2012 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/animation/keyframed_animation_curve.h"
-
-#include "cc/animation/transform_operations.h"
-#include "cc/test/geometry_test_utils.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/animation/tween.h"
-#include "ui/gfx/geometry/box_f.h"
-#include "ui/gfx/test/gfx_util.h"
-
-namespace cc {
-namespace {
-
-void ExpectTranslateX(SkScalar translate_x,
- const TransformOperations& operations) {
- EXPECT_FLOAT_EQ(translate_x, operations.Apply().matrix().get(0, 3));
-}
-
-void ExpectBrightness(double brightness, const FilterOperations& filter) {
- EXPECT_EQ(1u, filter.size());
- EXPECT_EQ(FilterOperation::BRIGHTNESS, filter.at(0).type());
- EXPECT_FLOAT_EQ(brightness, filter.at(0).amount());
-}
-
-// Tests that a color animation with one keyframe works as expected.
-TEST(KeyframedAnimationCurveTest, OneColorKeyFrame) {
- SkColor color = SkColorSetARGB(255, 255, 255, 255);
- std::unique_ptr<KeyframedColorAnimationCurve> curve(
- KeyframedColorAnimationCurve::Create());
- curve->AddKeyframe(ColorKeyframe::Create(base::TimeDelta(), color, nullptr));
-
- EXPECT_SKCOLOR_EQ(color,
- curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
- EXPECT_SKCOLOR_EQ(color, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
- EXPECT_SKCOLOR_EQ(color,
- curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
- EXPECT_SKCOLOR_EQ(color, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
- EXPECT_SKCOLOR_EQ(color, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
-}
-
-// Tests that a color animation with two keyframes works as expected.
-TEST(KeyframedAnimationCurveTest, TwoColorKeyFrame) {
- SkColor color_a = SkColorSetARGB(255, 255, 0, 0);
- SkColor color_b = SkColorSetARGB(255, 0, 255, 0);
- SkColor color_midpoint = gfx::Tween::ColorValueBetween(0.5, color_a, color_b);
- std::unique_ptr<KeyframedColorAnimationCurve> curve(
- KeyframedColorAnimationCurve::Create());
- curve->AddKeyframe(
- ColorKeyframe::Create(base::TimeDelta(), color_a, nullptr));
- curve->AddKeyframe(ColorKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
- color_b, nullptr));
-
- EXPECT_SKCOLOR_EQ(color_a,
- curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
- EXPECT_SKCOLOR_EQ(color_a,
- curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
- EXPECT_SKCOLOR_EQ(color_midpoint,
- curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
- EXPECT_SKCOLOR_EQ(color_b,
- curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
- EXPECT_SKCOLOR_EQ(color_b,
- curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
-}
-
-// Tests that a color animation with three keyframes works as expected.
-TEST(KeyframedAnimationCurveTest, ThreeColorKeyFrame) {
- SkColor color_a = SkColorSetARGB(255, 255, 0, 0);
- SkColor color_b = SkColorSetARGB(255, 0, 255, 0);
- SkColor color_c = SkColorSetARGB(255, 0, 0, 255);
- SkColor color_midpoint1 =
- gfx::Tween::ColorValueBetween(0.5, color_a, color_b);
- SkColor color_midpoint2 =
- gfx::Tween::ColorValueBetween(0.5, color_b, color_c);
- std::unique_ptr<KeyframedColorAnimationCurve> curve(
- KeyframedColorAnimationCurve::Create());
- curve->AddKeyframe(
- ColorKeyframe::Create(base::TimeDelta(), color_a, nullptr));
- curve->AddKeyframe(ColorKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
- color_b, nullptr));
- curve->AddKeyframe(ColorKeyframe::Create(base::TimeDelta::FromSecondsD(2.0),
- color_c, nullptr));
-
- EXPECT_SKCOLOR_EQ(color_a,
- curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
- EXPECT_SKCOLOR_EQ(color_a,
- curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
- EXPECT_SKCOLOR_EQ(color_midpoint1,
- curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
- EXPECT_SKCOLOR_EQ(color_b,
- curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
- EXPECT_SKCOLOR_EQ(color_midpoint2,
- curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
- EXPECT_SKCOLOR_EQ(color_c,
- curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
- EXPECT_SKCOLOR_EQ(color_c,
- curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
-}
-
-// Tests that a color animation with multiple keys at a given time works sanely.
-TEST(KeyframedAnimationCurveTest, RepeatedColorKeyFrame) {
- SkColor color_a = SkColorSetARGB(255, 64, 0, 0);
- SkColor color_b = SkColorSetARGB(255, 192, 0, 0);
-
- std::unique_ptr<KeyframedColorAnimationCurve> curve(
- KeyframedColorAnimationCurve::Create());
- curve->AddKeyframe(
- ColorKeyframe::Create(base::TimeDelta(), color_a, nullptr));
- curve->AddKeyframe(ColorKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
- color_a, nullptr));
- curve->AddKeyframe(ColorKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
- color_b, nullptr));
- curve->AddKeyframe(ColorKeyframe::Create(base::TimeDelta::FromSecondsD(2.0),
- color_b, nullptr));
-
- EXPECT_SKCOLOR_EQ(color_a,
- curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
- EXPECT_SKCOLOR_EQ(color_a,
- curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
- EXPECT_SKCOLOR_EQ(color_a,
- curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
-
- SkColor value = curve->GetValue(base::TimeDelta::FromSecondsD(1.0f));
- EXPECT_EQ(255u, SkColorGetA(value));
- int red_value = SkColorGetR(value);
- EXPECT_LE(64, red_value);
- EXPECT_GE(192, red_value);
-
- EXPECT_SKCOLOR_EQ(color_b,
- curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
- EXPECT_SKCOLOR_EQ(color_b,
- curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
- EXPECT_SKCOLOR_EQ(color_b,
- curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
-}
-
-// Tests that a float animation with one keyframe works as expected.
-TEST(KeyframedAnimationCurveTest, OneFloatKeyframe) {
- std::unique_ptr<KeyframedFloatAnimationCurve> curve(
- KeyframedFloatAnimationCurve::Create());
- curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 2.f, nullptr));
- EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
- EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
- EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
- EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
- EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
-}
-
-// Tests that a float animation with two keyframes works as expected.
-TEST(KeyframedAnimationCurveTest, TwoFloatKeyframe) {
- std::unique_ptr<KeyframedFloatAnimationCurve> curve(
- KeyframedFloatAnimationCurve::Create());
- curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 2.f, nullptr));
- curve->AddKeyframe(
- FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 4.f, nullptr));
- EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
- EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
- EXPECT_FLOAT_EQ(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
- EXPECT_FLOAT_EQ(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
- EXPECT_FLOAT_EQ(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
-}
-
-// Tests that a float animation with three keyframes works as expected.
-TEST(KeyframedAnimationCurveTest, ThreeFloatKeyframe) {
- std::unique_ptr<KeyframedFloatAnimationCurve> curve(
- KeyframedFloatAnimationCurve::Create());
- curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 2.f, nullptr));
- curve->AddKeyframe(
- FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 4.f, nullptr));
- curve->AddKeyframe(
- FloatKeyframe::Create(base::TimeDelta::FromSecondsD(2.0), 8.f, nullptr));
- EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
- EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
- EXPECT_FLOAT_EQ(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
- EXPECT_FLOAT_EQ(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
- EXPECT_FLOAT_EQ(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
- EXPECT_FLOAT_EQ(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
- EXPECT_FLOAT_EQ(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
-}
-
-// Tests that a float animation with multiple keys at a given time works sanely.
-TEST(KeyframedAnimationCurveTest, RepeatedFloatKeyTimes) {
- std::unique_ptr<KeyframedFloatAnimationCurve> curve(
- KeyframedFloatAnimationCurve::Create());
- curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 4.f, nullptr));
- curve->AddKeyframe(
- FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 4.f, nullptr));
- curve->AddKeyframe(
- FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 6.f, nullptr));
- curve->AddKeyframe(
- FloatKeyframe::Create(base::TimeDelta::FromSecondsD(2.0), 6.f, nullptr));
-
- EXPECT_FLOAT_EQ(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
- EXPECT_FLOAT_EQ(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
- EXPECT_FLOAT_EQ(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
-
- // There is a discontinuity at 1. Any value between 4 and 6 is valid.
- float value = curve->GetValue(base::TimeDelta::FromSecondsD(1.f));
- EXPECT_TRUE(value >= 4 && value <= 6);
-
- EXPECT_FLOAT_EQ(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
- EXPECT_FLOAT_EQ(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
- EXPECT_FLOAT_EQ(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
-}
-
-// Tests that a transform animation with one keyframe works as expected.
-TEST(KeyframedAnimationCurveTest, OneTransformKeyframe) {
- std::unique_ptr<KeyframedTransformAnimationCurve> curve(
- KeyframedTransformAnimationCurve::Create());
- TransformOperations operations;
- operations.AppendTranslate(2.f, 0.f, 0.f);
- curve->AddKeyframe(
- TransformKeyframe::Create(base::TimeDelta(), operations, nullptr));
-
- ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
- ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
- ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
- ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
- ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
-}
-
-// Tests that a transform animation with two keyframes works as expected.
-TEST(KeyframedAnimationCurveTest, TwoTransformKeyframe) {
- std::unique_ptr<KeyframedTransformAnimationCurve> curve(
- KeyframedTransformAnimationCurve::Create());
- TransformOperations operations1;
- operations1.AppendTranslate(2.f, 0.f, 0.f);
- TransformOperations operations2;
- operations2.AppendTranslate(4.f, 0.f, 0.f);
-
- curve->AddKeyframe(
- TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
- curve->AddKeyframe(TransformKeyframe::Create(
- base::TimeDelta::FromSecondsD(1.0), operations2, nullptr));
- ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
- ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
- ExpectTranslateX(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
- ExpectTranslateX(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
- ExpectTranslateX(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
-}
-
-// Tests that a transform animation with three keyframes works as expected.
-TEST(KeyframedAnimationCurveTest, ThreeTransformKeyframe) {
- std::unique_ptr<KeyframedTransformAnimationCurve> curve(
- KeyframedTransformAnimationCurve::Create());
- TransformOperations operations1;
- operations1.AppendTranslate(2.f, 0.f, 0.f);
- TransformOperations operations2;
- operations2.AppendTranslate(4.f, 0.f, 0.f);
- TransformOperations operations3;
- operations3.AppendTranslate(8.f, 0.f, 0.f);
- curve->AddKeyframe(
- TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
- curve->AddKeyframe(TransformKeyframe::Create(
- base::TimeDelta::FromSecondsD(1.0), operations2, nullptr));
- curve->AddKeyframe(TransformKeyframe::Create(
- base::TimeDelta::FromSecondsD(2.0), operations3, nullptr));
- ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
- ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
- ExpectTranslateX(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
- ExpectTranslateX(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
- ExpectTranslateX(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
- ExpectTranslateX(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
- ExpectTranslateX(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
-}
-
-// Tests that a transform animation with multiple keys at a given time works
-// sanely.
-TEST(KeyframedAnimationCurveTest, RepeatedTransformKeyTimes) {
- std::unique_ptr<KeyframedTransformAnimationCurve> curve(
- KeyframedTransformAnimationCurve::Create());
- // A step function.
- TransformOperations operations1;
- operations1.AppendTranslate(4.f, 0.f, 0.f);
- TransformOperations operations2;
- operations2.AppendTranslate(4.f, 0.f, 0.f);
- TransformOperations operations3;
- operations3.AppendTranslate(6.f, 0.f, 0.f);
- TransformOperations operations4;
- operations4.AppendTranslate(6.f, 0.f, 0.f);
- curve->AddKeyframe(
- TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
- curve->AddKeyframe(TransformKeyframe::Create(
- base::TimeDelta::FromSecondsD(1.0), operations2, nullptr));
- curve->AddKeyframe(TransformKeyframe::Create(
- base::TimeDelta::FromSecondsD(1.0), operations3, nullptr));
- curve->AddKeyframe(TransformKeyframe::Create(
- base::TimeDelta::FromSecondsD(2.0), operations4, nullptr));
-
- ExpectTranslateX(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
- ExpectTranslateX(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
- ExpectTranslateX(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
-
- // There is a discontinuity at 1. Any value between 4 and 6 is valid.
- gfx::Transform value =
- curve->GetValue(base::TimeDelta::FromSecondsD(1.f)).Apply();
- EXPECT_GE(value.matrix().get(0, 3), 4.f);
- EXPECT_LE(value.matrix().get(0, 3), 6.f);
-
- ExpectTranslateX(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
- ExpectTranslateX(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
- ExpectTranslateX(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
-}
-
-// Tests that a discrete transform animation (e.g. where one or more keyframes
-// is a non-invertible matrix) works as expected.
-TEST(KeyframedAnimationCurveTest, DiscreteLinearTransformAnimation) {
- gfx::Transform non_invertible_matrix(0, 0, 0, 0, 0, 0);
- gfx::Transform identity_matrix;
-
- std::unique_ptr<KeyframedTransformAnimationCurve> curve(
- KeyframedTransformAnimationCurve::Create());
- TransformOperations operations1;
- operations1.AppendMatrix(non_invertible_matrix);
- TransformOperations operations2;
- operations2.AppendMatrix(identity_matrix);
- TransformOperations operations3;
- operations3.AppendMatrix(non_invertible_matrix);
-
- curve->AddKeyframe(
- TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
- curve->AddKeyframe(TransformKeyframe::Create(
- base::TimeDelta::FromSecondsD(1.0), operations2, nullptr));
- curve->AddKeyframe(TransformKeyframe::Create(
- base::TimeDelta::FromSecondsD(2.0), operations3, nullptr));
-
- TransformOperations result;
-
- // Between 0 and 0.5 seconds, the first keyframe should be returned.
- result = curve->GetValue(base::TimeDelta::FromSecondsD(0.01f));
- EXPECT_TRANSFORMATION_MATRIX_EQ(non_invertible_matrix, result.Apply());
-
- result = curve->GetValue(base::TimeDelta::FromSecondsD(0.49f));
- EXPECT_TRANSFORMATION_MATRIX_EQ(non_invertible_matrix, result.Apply());
-
- // Between 0.5 and 1.5 seconds, the middle keyframe should be returned.
- result = curve->GetValue(base::TimeDelta::FromSecondsD(0.5f));
- EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, result.Apply());
-
- result = curve->GetValue(base::TimeDelta::FromSecondsD(1.49f));
- EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, result.Apply());
-
- // Between 1.5 and 2.0 seconds, the last keyframe should be returned.
- result = curve->GetValue(base::TimeDelta::FromSecondsD(1.5f));
- EXPECT_TRANSFORMATION_MATRIX_EQ(non_invertible_matrix, result.Apply());
-
- result = curve->GetValue(base::TimeDelta::FromSecondsD(2.0f));
- EXPECT_TRANSFORMATION_MATRIX_EQ(non_invertible_matrix, result.Apply());
-}
-
-TEST(KeyframedAnimationCurveTest, DiscreteCubicBezierTransformAnimation) {
- gfx::Transform non_invertible_matrix(0, 0, 0, 0, 0, 0);
- gfx::Transform identity_matrix;
-
- std::unique_ptr<KeyframedTransformAnimationCurve> curve(
- KeyframedTransformAnimationCurve::Create());
- TransformOperations operations1;
- operations1.AppendMatrix(non_invertible_matrix);
- TransformOperations operations2;
- operations2.AppendMatrix(identity_matrix);
- TransformOperations operations3;
- operations3.AppendMatrix(non_invertible_matrix);
-
- // The cubic-bezier here is a nice fairly strong ease-in curve, where 50%
- // progression is at approximately 85% of the time.
- curve->AddKeyframe(TransformKeyframe::Create(
- base::TimeDelta(), operations1,
- CubicBezierTimingFunction::Create(0.75f, 0.25f, 0.9f, 0.4f)));
- curve->AddKeyframe(TransformKeyframe::Create(
- base::TimeDelta::FromSecondsD(1.0), operations2,
- CubicBezierTimingFunction::Create(0.75f, 0.25f, 0.9f, 0.4f)));
- curve->AddKeyframe(TransformKeyframe::Create(
- base::TimeDelta::FromSecondsD(2.0), operations3,
- CubicBezierTimingFunction::Create(0.75f, 0.25f, 0.9f, 0.4f)));
-
- TransformOperations result;
-
- // Due to the cubic-bezier, the first keyframe is returned almost all the way
- // to 1 second.
- result = curve->GetValue(base::TimeDelta::FromSecondsD(0.01f));
- EXPECT_TRANSFORMATION_MATRIX_EQ(non_invertible_matrix, result.Apply());
-
- result = curve->GetValue(base::TimeDelta::FromSecondsD(0.8f));
- EXPECT_TRANSFORMATION_MATRIX_EQ(non_invertible_matrix, result.Apply());
-
- // Between ~0.85 and ~1.85 seconds, the middle keyframe should be returned.
- result = curve->GetValue(base::TimeDelta::FromSecondsD(0.85f));
- EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, result.Apply());
-
- result = curve->GetValue(base::TimeDelta::FromSecondsD(1.8f));
- EXPECT_TRANSFORMATION_MATRIX_EQ(identity_matrix, result.Apply());
-
- // Finally the last keyframe only takes effect after ~1.85 seconds.
- result = curve->GetValue(base::TimeDelta::FromSecondsD(1.85f));
- EXPECT_TRANSFORMATION_MATRIX_EQ(non_invertible_matrix, result.Apply());
-
- result = curve->GetValue(base::TimeDelta::FromSecondsD(2.0f));
- EXPECT_TRANSFORMATION_MATRIX_EQ(non_invertible_matrix, result.Apply());
-}
-
-// Tests that a filter animation with one keyframe works as expected.
-TEST(KeyframedAnimationCurveTest, OneFilterKeyframe) {
- std::unique_ptr<KeyframedFilterAnimationCurve> curve(
- KeyframedFilterAnimationCurve::Create());
- FilterOperations operations;
- operations.Append(FilterOperation::CreateBrightnessFilter(2.f));
- curve->AddKeyframe(
- FilterKeyframe::Create(base::TimeDelta(), operations, nullptr));
-
- ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
- ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
- ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
- ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
- ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
-}
-
-// Tests that a filter animation with two keyframes works as expected.
-TEST(KeyframedAnimationCurveTest, TwoFilterKeyframe) {
- std::unique_ptr<KeyframedFilterAnimationCurve> curve(
- KeyframedFilterAnimationCurve::Create());
- FilterOperations operations1;
- operations1.Append(FilterOperation::CreateBrightnessFilter(2.f));
- FilterOperations operations2;
- operations2.Append(FilterOperation::CreateBrightnessFilter(4.f));
-
- curve->AddKeyframe(
- FilterKeyframe::Create(base::TimeDelta(), operations1, nullptr));
- curve->AddKeyframe(FilterKeyframe::Create(base::TimeDelta::FromSecondsD(1.f),
- operations2, nullptr));
- ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
- ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
- ExpectBrightness(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
- ExpectBrightness(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
- ExpectBrightness(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
-}
-
-// Tests that a filter animation with three keyframes works as expected.
-TEST(KeyframedAnimationCurveTest, ThreeFilterKeyframe) {
- std::unique_ptr<KeyframedFilterAnimationCurve> curve(
- KeyframedFilterAnimationCurve::Create());
- FilterOperations operations1;
- operations1.Append(FilterOperation::CreateBrightnessFilter(2.f));
- FilterOperations operations2;
- operations2.Append(FilterOperation::CreateBrightnessFilter(4.f));
- FilterOperations operations3;
- operations3.Append(FilterOperation::CreateBrightnessFilter(8.f));
- curve->AddKeyframe(
- FilterKeyframe::Create(base::TimeDelta(), operations1, nullptr));
- curve->AddKeyframe(FilterKeyframe::Create(base::TimeDelta::FromSecondsD(1.f),
- operations2, nullptr));
- curve->AddKeyframe(FilterKeyframe::Create(base::TimeDelta::FromSecondsD(2.f),
- operations3, nullptr));
- ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
- ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
- ExpectBrightness(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
- ExpectBrightness(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
- ExpectBrightness(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
- ExpectBrightness(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
- ExpectBrightness(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
-}
-
-// Tests that a filter animation with multiple keys at a given time works
-// sanely.
-TEST(KeyframedAnimationCurveTest, RepeatedFilterKeyTimes) {
- std::unique_ptr<KeyframedFilterAnimationCurve> curve(
- KeyframedFilterAnimationCurve::Create());
- // A step function.
- FilterOperations operations1;
- operations1.Append(FilterOperation::CreateBrightnessFilter(4.f));
- FilterOperations operations2;
- operations2.Append(FilterOperation::CreateBrightnessFilter(4.f));
- FilterOperations operations3;
- operations3.Append(FilterOperation::CreateBrightnessFilter(6.f));
- FilterOperations operations4;
- operations4.Append(FilterOperation::CreateBrightnessFilter(6.f));
- curve->AddKeyframe(
- FilterKeyframe::Create(base::TimeDelta(), operations1, nullptr));
- curve->AddKeyframe(FilterKeyframe::Create(base::TimeDelta::FromSecondsD(1.f),
- operations2, nullptr));
- curve->AddKeyframe(FilterKeyframe::Create(base::TimeDelta::FromSecondsD(1.f),
- operations3, nullptr));
- curve->AddKeyframe(FilterKeyframe::Create(base::TimeDelta::FromSecondsD(2.f),
- operations4, nullptr));
-
- ExpectBrightness(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
- ExpectBrightness(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
- ExpectBrightness(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
-
- // There is a discontinuity at 1. Any value between 4 and 6 is valid.
- FilterOperations value = curve->GetValue(base::TimeDelta::FromSecondsD(1.f));
- EXPECT_EQ(1u, value.size());
- EXPECT_EQ(FilterOperation::BRIGHTNESS, value.at(0).type());
- EXPECT_GE(value.at(0).amount(), 4);
- EXPECT_LE(value.at(0).amount(), 6);
-
- ExpectBrightness(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
- ExpectBrightness(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
- ExpectBrightness(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
-}
-
-// Tests that the keyframes may be added out of order.
-TEST(KeyframedAnimationCurveTest, UnsortedKeyframes) {
- std::unique_ptr<KeyframedFloatAnimationCurve> curve(
- KeyframedFloatAnimationCurve::Create());
- curve->AddKeyframe(
- FloatKeyframe::Create(base::TimeDelta::FromSecondsD(2.f), 8.f, nullptr));
- curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 2.f, nullptr));
- curve->AddKeyframe(
- FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), 4.f, nullptr));
- EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
- EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
- EXPECT_FLOAT_EQ(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
- EXPECT_FLOAT_EQ(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
- EXPECT_FLOAT_EQ(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
- EXPECT_FLOAT_EQ(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
- EXPECT_FLOAT_EQ(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
-}
-
-// Tests that a linear timing function works as expected.
-TEST(KeyframedAnimationCurveTest, LinearTimingFunction) {
- std::unique_ptr<KeyframedFloatAnimationCurve> curve(
- KeyframedFloatAnimationCurve::Create());
- curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 0.f,
- LinearTimingFunction::Create()));
- curve->AddKeyframe(
- FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 1.f, nullptr));
-
- EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
- EXPECT_FLOAT_EQ(0.75f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f)));
-}
-
-// Tests that a cubic bezier timing function works as expected.
-TEST(KeyframedAnimationCurveTest, CubicBezierTimingFunction) {
- std::unique_ptr<KeyframedFloatAnimationCurve> curve(
- KeyframedFloatAnimationCurve::Create());
- curve->AddKeyframe(FloatKeyframe::Create(
- base::TimeDelta(), 0.f,
- CubicBezierTimingFunction::Create(0.25f, 0.f, 0.75f, 1.f)));
- curve->AddKeyframe(
- FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 1.f, nullptr));
-
- EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
- EXPECT_LT(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.25f)));
- EXPECT_GT(0.25f, curve->GetValue(base::TimeDelta::FromSecondsD(0.25f)));
- EXPECT_NEAR(curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)), 0.5f,
- 0.00015f);
- EXPECT_LT(0.75f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f)));
- EXPECT_GT(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f)));
- EXPECT_FLOAT_EQ(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
-}
-
-// Tests a step timing function if the change of values occur at the start.
-TEST(KeyframedAnimationCurveTest, StepsTimingFunctionStepAtStart) {
- std::unique_ptr<KeyframedFloatAnimationCurve> curve(
- KeyframedFloatAnimationCurve::Create());
- const int num_steps = 36;
- curve->AddKeyframe(FloatKeyframe::Create(
- base::TimeDelta(), 0.f,
- StepsTimingFunction::Create(num_steps,
- StepsTimingFunction::StepPosition::START)));
- curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
- num_steps, nullptr));
-
- const float time_threshold = 0.0001f;
-
- for (float i = 0.f; i < num_steps; i += 1.f) {
- const base::TimeDelta time1 =
- base::TimeDelta::FromSecondsD(i / num_steps - time_threshold);
- const base::TimeDelta time2 =
- base::TimeDelta::FromSecondsD(i / num_steps + time_threshold);
- EXPECT_FLOAT_EQ(std::ceil(i), curve->GetValue(time1));
- EXPECT_FLOAT_EQ(std::ceil(i) + 1.f, curve->GetValue(time2));
- }
- EXPECT_FLOAT_EQ(num_steps,
- curve->GetValue(base::TimeDelta::FromSecondsD(1.0)));
-
- for (float i = 0.5f; i <= num_steps; i += 1.0f) {
- const base::TimeDelta time = base::TimeDelta::FromSecondsD(i / num_steps);
- EXPECT_FLOAT_EQ(std::ceil(i), curve->GetValue(time));
- }
-}
-
-// Tests a step timing function if the change of values occur at the end.
-TEST(KeyframedAnimationCurveTest, StepsTimingFunctionStepAtEnd) {
- std::unique_ptr<KeyframedFloatAnimationCurve> curve(
- KeyframedFloatAnimationCurve::Create());
- const int num_steps = 36;
- curve->AddKeyframe(FloatKeyframe::Create(
- base::TimeDelta(), 0.f,
- StepsTimingFunction::Create(num_steps,
- StepsTimingFunction::StepPosition::END)));
- curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
- num_steps, nullptr));
-
- const float time_threshold = 0.0001f;
-
- EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta()));
- for (float i = 1.f; i <= num_steps; i += 1.f) {
- const base::TimeDelta time1 =
- base::TimeDelta::FromSecondsD(i / num_steps - time_threshold);
- const base::TimeDelta time2 =
- base::TimeDelta::FromSecondsD(i / num_steps + time_threshold);
- EXPECT_FLOAT_EQ(std::floor(i) - 1.f, curve->GetValue(time1));
- EXPECT_FLOAT_EQ(std::floor(i), curve->GetValue(time2));
- }
- EXPECT_FLOAT_EQ(num_steps,
- curve->GetValue(base::TimeDelta::FromSecondsD(1.0)));
-
- for (float i = 0.5f; i <= num_steps; i += 1.0f) {
- const base::TimeDelta time = base::TimeDelta::FromSecondsD(i / num_steps);
- EXPECT_FLOAT_EQ(std::floor(i), curve->GetValue(time));
- }
-}
-
-// Tests that animations that are translations are correctly identified.
-TEST(KeyframedAnimationCurveTest, IsTranslation) {
- std::unique_ptr<KeyframedTransformAnimationCurve> curve(
- KeyframedTransformAnimationCurve::Create());
-
- TransformOperations operations1;
- curve->AddKeyframe(
- TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
- operations1.AppendTranslate(2.0, 3.0, -1.0);
- TransformOperations operations2;
- operations2.AppendTranslate(4.0, 1.0, 2.0);
- curve->AddKeyframe(TransformKeyframe::Create(
- base::TimeDelta::FromSecondsD(1.f), operations2, nullptr));
-
- EXPECT_TRUE(curve->IsTranslation());
-
- TransformOperations operations3;
- operations3.AppendScale(2.f, 2.f, 2.f);
- curve->AddKeyframe(TransformKeyframe::Create(
- base::TimeDelta::FromSecondsD(2.f), operations3, nullptr));
-
- EXPECT_FALSE(curve->IsTranslation());
-
- TransformOperations operations4;
- operations3.AppendTranslate(2.f, 2.f, 2.f);
- curve->AddKeyframe(TransformKeyframe::Create(
- base::TimeDelta::FromSecondsD(3.f), operations4, nullptr));
-
- EXPECT_FALSE(curve->IsTranslation());
-}
-
-// Tests that maximum target scale is computed as expected.
-TEST(KeyframedAnimationCurveTest, MaximumTargetScale) {
- std::unique_ptr<KeyframedTransformAnimationCurve> curve(
- KeyframedTransformAnimationCurve::Create());
-
- TransformOperations operations1;
- curve->AddKeyframe(
- TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
- operations1.AppendScale(2.f, -3.f, 1.f);
- curve->AddKeyframe(TransformKeyframe::Create(
- base::TimeDelta::FromSecondsD(1.f), operations1,
- CubicBezierTimingFunction::CreatePreset(
- CubicBezierTimingFunction::EaseType::EASE)));
-
- float maximum_scale = 0.f;
- EXPECT_TRUE(curve->MaximumTargetScale(true, &maximum_scale));
- EXPECT_EQ(3.f, maximum_scale);
-
- TransformOperations operations2;
- operations2.AppendScale(6.f, 3.f, 2.f);
- curve->AddKeyframe(TransformKeyframe::Create(
- base::TimeDelta::FromSecondsD(2.f), operations2,
- CubicBezierTimingFunction::CreatePreset(
- CubicBezierTimingFunction::EaseType::EASE)));
-
- EXPECT_TRUE(curve->MaximumTargetScale(true, &maximum_scale));
- EXPECT_EQ(6.f, maximum_scale);
-
- TransformOperations operations3;
- operations3.AppendRotate(1.f, 0.f, 0.f, 90.f);
- curve->AddKeyframe(TransformKeyframe::Create(
- base::TimeDelta::FromSecondsD(3.f), operations3,
- CubicBezierTimingFunction::CreatePreset(
- CubicBezierTimingFunction::EaseType::EASE)));
-
- EXPECT_TRUE(curve->MaximumTargetScale(true, &maximum_scale));
- EXPECT_EQ(6.f, maximum_scale);
-
- TransformOperations operations4;
- operations4.AppendPerspective(3.f);
- curve->AddKeyframe(TransformKeyframe::Create(
- base::TimeDelta::FromSecondsD(4.f), operations4,
- CubicBezierTimingFunction::CreatePreset(
- CubicBezierTimingFunction::EaseType::EASE)));
-
- EXPECT_FALSE(curve->MaximumTargetScale(true, &maximum_scale));
-
- // The original scale is not used in computing the max.
- std::unique_ptr<KeyframedTransformAnimationCurve> curve2(
- KeyframedTransformAnimationCurve::Create());
-
- TransformOperations operations5;
- operations5.AppendScale(0.4f, 0.2f, 0.6f);
- curve2->AddKeyframe(TransformKeyframe::Create(
- base::TimeDelta(), operations5,
- CubicBezierTimingFunction::CreatePreset(
- CubicBezierTimingFunction::EaseType::EASE)));
- TransformOperations operations6;
- operations6.AppendScale(0.5f, 0.3f, -0.8f);
- curve2->AddKeyframe(TransformKeyframe::Create(
- base::TimeDelta::FromSecondsD(1.f), operations6,
- CubicBezierTimingFunction::CreatePreset(
- CubicBezierTimingFunction::EaseType::EASE)));
-
- EXPECT_TRUE(curve2->MaximumTargetScale(true, &maximum_scale));
- EXPECT_EQ(0.8f, maximum_scale);
-
- EXPECT_TRUE(curve2->MaximumTargetScale(false, &maximum_scale));
- EXPECT_EQ(0.6f, maximum_scale);
-}
-
-// Tests that starting animation scale is computed as expected.
-TEST(KeyframedAnimationCurveTest, AnimationStartScale) {
- std::unique_ptr<KeyframedTransformAnimationCurve> curve(
- KeyframedTransformAnimationCurve::Create());
-
- TransformOperations operations1;
- curve->AddKeyframe(
- TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
- operations1.AppendScale(2.f, -3.f, 1.f);
- curve->AddKeyframe(TransformKeyframe::Create(
- base::TimeDelta::FromSecondsD(1.f), operations1,
- CubicBezierTimingFunction::CreatePreset(
- CubicBezierTimingFunction::EaseType::EASE)));
-
- float start_scale = 0.f;
-
- // Forward direction
- EXPECT_TRUE(curve->AnimationStartScale(true, &start_scale));
- EXPECT_EQ(1.f, start_scale);
-
- // Backward direction
- EXPECT_TRUE(curve->AnimationStartScale(false, &start_scale));
- EXPECT_EQ(3.f, start_scale);
-
- TransformOperations operations2;
- operations2.AppendScale(6.f, 3.f, 2.f);
- curve->AddKeyframe(TransformKeyframe::Create(
- base::TimeDelta::FromSecondsD(2.f), operations2,
- CubicBezierTimingFunction::CreatePreset(
- CubicBezierTimingFunction::EaseType::EASE)));
-
- // Forward direction
- EXPECT_TRUE(curve->AnimationStartScale(true, &start_scale));
- EXPECT_EQ(1.f, start_scale);
-
- // Backward direction
- EXPECT_TRUE(curve->AnimationStartScale(false, &start_scale));
- EXPECT_EQ(6.f, start_scale);
-
- TransformOperations operations3;
- operations3.AppendRotate(1.f, 0.f, 0.f, 90.f);
- curve->AddKeyframe(TransformKeyframe::Create(
- base::TimeDelta::FromSecondsD(3.f), operations3,
- CubicBezierTimingFunction::CreatePreset(
- CubicBezierTimingFunction::EaseType::EASE)));
-
- EXPECT_TRUE(curve->AnimationStartScale(false, &start_scale));
- EXPECT_EQ(1.f, start_scale);
-
- TransformOperations operations4;
- operations4.AppendPerspective(90.f);
- curve->AddKeyframe(TransformKeyframe::Create(
- base::TimeDelta::FromSecondsD(4.f), operations4,
- CubicBezierTimingFunction::CreatePreset(
- CubicBezierTimingFunction::EaseType::EASE)));
-
- EXPECT_FALSE(curve->AnimationStartScale(false, &start_scale));
- EXPECT_EQ(0.f, start_scale);
-}
-
-// Tests that an animation with a curve timing function works as expected.
-TEST(KeyframedAnimationCurveTest, CurveTiming) {
- std::unique_ptr<KeyframedFloatAnimationCurve> curve(
- KeyframedFloatAnimationCurve::Create());
- curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 0.f, nullptr));
- curve->AddKeyframe(
- FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), 1.f, nullptr));
- curve->SetTimingFunction(
- CubicBezierTimingFunction::Create(0.75f, 0.f, 0.25f, 1.f));
- EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
- EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
- EXPECT_NEAR(0.05f, curve->GetValue(base::TimeDelta::FromSecondsD(0.25f)),
- 0.005f);
- EXPECT_FLOAT_EQ(0.5f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
- EXPECT_NEAR(0.95f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f)),
- 0.005f);
- EXPECT_FLOAT_EQ(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
- EXPECT_FLOAT_EQ(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
-}
-
-// Tests that an animation with a curve and keyframe timing function works as
-// expected.
-TEST(KeyframedAnimationCurveTest, CurveAndKeyframeTiming) {
- std::unique_ptr<KeyframedFloatAnimationCurve> curve(
- KeyframedFloatAnimationCurve::Create());
- curve->AddKeyframe(FloatKeyframe::Create(
- base::TimeDelta(), 0.f,
- CubicBezierTimingFunction::Create(0.35f, 0.f, 0.65f, 1.f)));
- curve->AddKeyframe(
- FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), 1.f, nullptr));
- // Curve timing function producing outputs outside of range [0,1].
- curve->SetTimingFunction(
- CubicBezierTimingFunction::Create(0.5f, -0.5f, 0.5f, 1.5f));
- EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
- EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
- EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(
- 0.25f))); // Clamped. c(.25) < 0
- EXPECT_NEAR(0.17f, curve->GetValue(base::TimeDelta::FromSecondsD(0.42f)),
- 0.005f); // c(.42)=.27, k(.27)=.17
- EXPECT_FLOAT_EQ(0.5f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
- EXPECT_NEAR(0.83f, curve->GetValue(base::TimeDelta::FromSecondsD(0.58f)),
- 0.005f); // c(.58)=.73, k(.73)=.83
- EXPECT_FLOAT_EQ(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(
- 0.75f))); // Clamped. c(.75) > 1
- EXPECT_FLOAT_EQ(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
- EXPECT_FLOAT_EQ(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
-}
-
-// Tests that a linear timing function works as expected for inputs outside of
-// range [0,1]
-TEST(KeyframedAnimationCurveTest, LinearTimingInputsOutsideZeroOneRange) {
- std::unique_ptr<KeyframedFloatAnimationCurve> curve(
- KeyframedFloatAnimationCurve::Create());
- curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 0.f, nullptr));
- curve->AddKeyframe(
- FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 2.f, nullptr));
- // Curve timing function producing timing outputs outside of range [0,1].
- curve->SetTimingFunction(
- CubicBezierTimingFunction::Create(0.5f, -0.5f, 0.5f, 1.5f));
-
- EXPECT_NEAR(-0.076f, curve->GetValue(base::TimeDelta::FromSecondsD(0.25f)),
- 0.001f);
- EXPECT_NEAR(2.076f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f)),
- 0.001f);
-}
-
-// If a curve cubic-bezier timing function produces timing outputs outside
-// the range [0, 1] then a keyframe cubic-bezier timing function
-// should consume that input properly (using end-point gradients).
-TEST(KeyframedAnimationCurveTest, CurveTimingInputsOutsideZeroOneRange) {
- std::unique_ptr<KeyframedFloatAnimationCurve> curve(
- KeyframedFloatAnimationCurve::Create());
- // Keyframe timing function with 0.5 gradients at each end.
- curve->AddKeyframe(FloatKeyframe::Create(
- base::TimeDelta(), 0.f,
- CubicBezierTimingFunction::Create(0.5f, 0.25f, 0.5f, 0.75f)));
- curve->AddKeyframe(
- FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), 1.f, nullptr));
- // Curve timing function producing timing outputs outside of range [0,1].
- curve->SetTimingFunction(
- CubicBezierTimingFunction::Create(0.5f, -0.5f, 0.5f, 1.5f));
-
- EXPECT_NEAR(-0.02f, curve->GetValue(base::TimeDelta::FromSecondsD(0.25f)),
- 0.002f); // c(.25)=-.04, -.04*0.5=-0.02
- EXPECT_NEAR(0.33f, curve->GetValue(base::TimeDelta::FromSecondsD(0.46f)),
- 0.002f); // c(.46)=.38, k(.38)=.33
-
- EXPECT_NEAR(0.67f, curve->GetValue(base::TimeDelta::FromSecondsD(0.54f)),
- 0.002f); // c(.54)=.62, k(.62)=.67
- EXPECT_NEAR(1.02f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f)),
- 0.002f); // c(.75)=1.04 1+.04*0.5=1.02
-}
-
-// Tests that a step timing function works as expected for inputs outside of
-// range [0,1]
-TEST(KeyframedAnimationCurveTest, StepsTimingStartInputsOutsideZeroOneRange) {
- std::unique_ptr<KeyframedFloatAnimationCurve> curve(
- KeyframedFloatAnimationCurve::Create());
- curve->AddKeyframe(
- FloatKeyframe::Create(base::TimeDelta(), 0.f,
- StepsTimingFunction::Create(
- 4, StepsTimingFunction::StepPosition::START)));
- curve->AddKeyframe(
- FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 2.f, nullptr));
- // Curve timing function producing timing outputs outside of range [0,1].
- curve->SetTimingFunction(
- CubicBezierTimingFunction::Create(0.5f, -0.5f, 0.5f, 1.5f));
-
- EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.25f)));
- EXPECT_FLOAT_EQ(2.5f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f)));
-}
-
-TEST(KeyframedAnimationCurveTest, StepsTimingEndInputsOutsideZeroOneRange) {
- std::unique_ptr<KeyframedFloatAnimationCurve> curve(
- KeyframedFloatAnimationCurve::Create());
- curve->AddKeyframe(FloatKeyframe::Create(
- base::TimeDelta(), 0.f,
- StepsTimingFunction::Create(4, StepsTimingFunction::StepPosition::END)));
- curve->AddKeyframe(
- FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 2.f, nullptr));
- // Curve timing function producing timing outputs outside of range [0,1].
- curve->SetTimingFunction(
- CubicBezierTimingFunction::Create(0.5f, -0.5f, 0.5f, 1.5f));
-
- EXPECT_FLOAT_EQ(-0.5f, curve->GetValue(base::TimeDelta::FromSecondsD(0.25f)));
- EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f)));
-}
-
-// Tests that an animation with a curve timing function and multiple keyframes
-// works as expected.
-TEST(KeyframedAnimationCurveTest, CurveTimingMultipleKeyframes) {
- std::unique_ptr<KeyframedFloatAnimationCurve> curve(
- KeyframedFloatAnimationCurve::Create());
- curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 0.f, nullptr));
- curve->AddKeyframe(
- FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), 1.f, nullptr));
- curve->AddKeyframe(
- FloatKeyframe::Create(base::TimeDelta::FromSecondsD(2.f), 3.f, nullptr));
- curve->AddKeyframe(
- FloatKeyframe::Create(base::TimeDelta::FromSecondsD(3.f), 6.f, nullptr));
- curve->AddKeyframe(
- FloatKeyframe::Create(base::TimeDelta::FromSecondsD(4.f), 9.f, nullptr));
- curve->SetTimingFunction(
- CubicBezierTimingFunction::Create(0.5f, 0.f, 0.5f, 1.f));
- EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
- EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
- EXPECT_NEAR(0.42f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)),
- 0.005f);
- EXPECT_NEAR(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.455f)),
- 0.005f);
- EXPECT_FLOAT_EQ(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
- EXPECT_NEAR(8.72f, curve->GetValue(base::TimeDelta::FromSecondsD(3.5f)),
- 0.01f);
- EXPECT_FLOAT_EQ(9.f, curve->GetValue(base::TimeDelta::FromSecondsD(4.f)));
- EXPECT_FLOAT_EQ(9.f, curve->GetValue(base::TimeDelta::FromSecondsD(5.f)));
-}
-
-// Tests that an animation with a curve timing function that overshoots works as
-// expected.
-TEST(KeyframedAnimationCurveTest, CurveTimingOvershootMultipeKeyframes) {
- std::unique_ptr<KeyframedFloatAnimationCurve> curve(
- KeyframedFloatAnimationCurve::Create());
- curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 0.f, nullptr));
- curve->AddKeyframe(
- FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 1.f, nullptr));
- curve->AddKeyframe(
- FloatKeyframe::Create(base::TimeDelta::FromSecondsD(2.0), 3.f, nullptr));
- curve->AddKeyframe(
- FloatKeyframe::Create(base::TimeDelta::FromSecondsD(3.0), 6.f, nullptr));
- curve->AddKeyframe(
- FloatKeyframe::Create(base::TimeDelta::FromSecondsD(4.0), 9.f, nullptr));
- // Curve timing function producing outputs outside of range [0,1].
- curve->SetTimingFunction(
- CubicBezierTimingFunction::Create(0.5f, -0.5f, 0.5f, 1.5f));
- EXPECT_LE(curve->GetValue(base::TimeDelta::FromSecondsD(1.f)),
- 0.f); // c(.25) < 0
- EXPECT_GE(curve->GetValue(base::TimeDelta::FromSecondsD(3.f)),
- 9.f); // c(.75) > 1
-}
-
-// Tests that a float animation with multiple keys works with scaled duration.
-TEST(KeyframedAnimationCurveTest, ScaledDuration) {
- std::unique_ptr<KeyframedFloatAnimationCurve> curve(
- KeyframedFloatAnimationCurve::Create());
- curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 0.f, nullptr));
- curve->AddKeyframe(
- FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), 1.f, nullptr));
- curve->AddKeyframe(
- FloatKeyframe::Create(base::TimeDelta::FromSecondsD(2.f), 3.f, nullptr));
- curve->AddKeyframe(
- FloatKeyframe::Create(base::TimeDelta::FromSecondsD(3.f), 6.f, nullptr));
- curve->AddKeyframe(
- FloatKeyframe::Create(base::TimeDelta::FromSecondsD(4.f), 9.f, nullptr));
- curve->SetTimingFunction(
- CubicBezierTimingFunction::Create(0.5f, 0.f, 0.5f, 1.f));
-
- const double scale = 1000.0;
- curve->set_scaled_duration(scale);
-
- EXPECT_DOUBLE_EQ(scale * 4, curve->Duration().InSecondsF());
-
- EXPECT_FLOAT_EQ(0.f,
- curve->GetValue(base::TimeDelta::FromSecondsD(scale * -1.f)));
- EXPECT_FLOAT_EQ(0.f,
- curve->GetValue(base::TimeDelta::FromSecondsD(scale * 0.f)));
- EXPECT_NEAR(0.42f,
- curve->GetValue(base::TimeDelta::FromSecondsD(scale * 1.f)),
- 0.005f);
- EXPECT_NEAR(1.f,
- curve->GetValue(base::TimeDelta::FromSecondsD(scale * 1.455f)),
- 0.005f);
- EXPECT_FLOAT_EQ(3.f,
- curve->GetValue(base::TimeDelta::FromSecondsD(scale * 2.f)));
- EXPECT_NEAR(8.72f,
- curve->GetValue(base::TimeDelta::FromSecondsD(scale * 3.5f)),
- 0.01f);
- EXPECT_FLOAT_EQ(9.f,
- curve->GetValue(base::TimeDelta::FromSecondsD(scale * 4.f)));
- EXPECT_FLOAT_EQ(9.f,
- curve->GetValue(base::TimeDelta::FromSecondsD(scale * 5.f)));
-}
-
-// Tests that a size animation with one keyframe works as expected.
-TEST(KeyframedAnimationCurveTest, OneSizeKeyFrame) {
- gfx::SizeF size = gfx::SizeF(100, 100);
- std::unique_ptr<KeyframedSizeAnimationCurve> curve(
- KeyframedSizeAnimationCurve::Create());
- curve->AddKeyframe(SizeKeyframe::Create(base::TimeDelta(), size, nullptr));
-
- EXPECT_SIZEF_EQ(size, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
- EXPECT_SIZEF_EQ(size, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
- EXPECT_SIZEF_EQ(size, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
- EXPECT_SIZEF_EQ(size, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
- EXPECT_SIZEF_EQ(size, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
-}
-
-// Tests that a size animation with two keyframes works as expected.
-TEST(KeyframedAnimationCurveTest, TwoSizeKeyFrame) {
- gfx::SizeF size_a = gfx::SizeF(100, 100);
- gfx::SizeF size_b = gfx::SizeF(100, 0);
- gfx::SizeF size_midpoint = gfx::Tween::SizeFValueBetween(0.5, size_a, size_b);
- std::unique_ptr<KeyframedSizeAnimationCurve> curve(
- KeyframedSizeAnimationCurve::Create());
- curve->AddKeyframe(SizeKeyframe::Create(base::TimeDelta(), size_a, nullptr));
- curve->AddKeyframe(SizeKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
- size_b, nullptr));
-
- EXPECT_SIZEF_EQ(size_a, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
- EXPECT_SIZEF_EQ(size_a, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
- EXPECT_SIZEF_EQ(size_midpoint,
- curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
- EXPECT_SIZEF_EQ(size_b, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
- EXPECT_SIZEF_EQ(size_b, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
-}
-
-// Tests that a size animation with three keyframes works as expected.
-TEST(KeyframedAnimationCurveTest, ThreeSizeKeyFrame) {
- gfx::SizeF size_a = gfx::SizeF(100, 100);
- gfx::SizeF size_b = gfx::SizeF(100, 0);
- gfx::SizeF size_c = gfx::SizeF(200, 0);
- gfx::SizeF size_midpoint1 =
- gfx::Tween::SizeFValueBetween(0.5, size_a, size_b);
- gfx::SizeF size_midpoint2 =
- gfx::Tween::SizeFValueBetween(0.5, size_b, size_c);
- std::unique_ptr<KeyframedSizeAnimationCurve> curve(
- KeyframedSizeAnimationCurve::Create());
- curve->AddKeyframe(SizeKeyframe::Create(base::TimeDelta(), size_a, nullptr));
- curve->AddKeyframe(SizeKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
- size_b, nullptr));
- curve->AddKeyframe(SizeKeyframe::Create(base::TimeDelta::FromSecondsD(2.0),
- size_c, nullptr));
-
- EXPECT_SIZEF_EQ(size_a, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
- EXPECT_SIZEF_EQ(size_a, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
- EXPECT_SIZEF_EQ(size_midpoint1,
- curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
- EXPECT_SIZEF_EQ(size_b, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
- EXPECT_SIZEF_EQ(size_midpoint2,
- curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
- EXPECT_SIZEF_EQ(size_c, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
- EXPECT_SIZEF_EQ(size_c, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
-}
-
-// Tests that a size animation with multiple keys at a given time works sanely.
-TEST(KeyframedAnimationCurveTest, RepeatedSizeKeyFrame) {
- gfx::SizeF size_a = gfx::SizeF(100, 64);
- gfx::SizeF size_b = gfx::SizeF(100, 192);
-
- std::unique_ptr<KeyframedSizeAnimationCurve> curve(
- KeyframedSizeAnimationCurve::Create());
- curve->AddKeyframe(SizeKeyframe::Create(base::TimeDelta(), size_a, nullptr));
- curve->AddKeyframe(SizeKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
- size_a, nullptr));
- curve->AddKeyframe(SizeKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
- size_b, nullptr));
- curve->AddKeyframe(SizeKeyframe::Create(base::TimeDelta::FromSecondsD(2.0),
- size_b, nullptr));
-
- EXPECT_SIZEF_EQ(size_a, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
- EXPECT_SIZEF_EQ(size_a, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
- EXPECT_SIZEF_EQ(size_a, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
-
- gfx::SizeF value = curve->GetValue(base::TimeDelta::FromSecondsD(1.0f));
- EXPECT_FLOAT_EQ(100.0f, value.width());
- EXPECT_LE(64.0f, value.height());
- EXPECT_GE(192.0f, value.height());
-
- EXPECT_SIZEF_EQ(size_b, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
- EXPECT_SIZEF_EQ(size_b, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
- EXPECT_SIZEF_EQ(size_b, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
-}
-
-} // namespace
-} // namespace cc
diff --git a/chromium/cc/animation/scroll_offset_animation_curve.cc b/chromium/cc/animation/scroll_offset_animation_curve.cc
index 8a67e0f0a39..5a645b4bad1 100644
--- a/chromium/cc/animation/scroll_offset_animation_curve.cc
+++ b/chromium/cc/animation/scroll_offset_animation_curve.cc
@@ -11,7 +11,7 @@
#include "base/check_op.h"
#include "base/memory/ptr_util.h"
#include "base/numerics/ranges.h"
-#include "cc/animation/timing_function.h"
+#include "ui/gfx/animation/keyframe/timing_function.h"
#include "ui/gfx/animation/tween.h"
const double kConstantDuration = 9.0;
@@ -32,6 +32,10 @@ const double kInverseDeltaSlope =
const double kInverseDeltaOffset =
kInverseDeltaMaxDuration - kInverseDeltaRampStartPx * kInverseDeltaSlope;
+using gfx::CubicBezierTimingFunction;
+using gfx::LinearTimingFunction;
+using gfx::TimingFunction;
+
namespace cc {
namespace {
@@ -136,7 +140,8 @@ ScrollOffsetAnimationCurve::ScrollOffsetAnimationCurve(
animation_type_(animation_type),
duration_behavior_(duration_behavior),
has_set_initial_value_(false) {
- DCHECK_EQ((animation_type == AnimationType::kEaseInOut),
+ DCHECK_EQ((animation_type == AnimationType::kEaseInOut ||
+ animation_type == AnimationType::kImpulse),
duration_behavior.has_value());
switch (animation_type) {
case AnimationType::kEaseInOut:
@@ -162,7 +167,8 @@ ScrollOffsetAnimationCurve::ScrollOffsetAnimationCurve(
animation_type_(animation_type),
duration_behavior_(duration_behavior),
has_set_initial_value_(false) {
- DCHECK_EQ((animation_type == AnimationType::kEaseInOut),
+ DCHECK_EQ((animation_type == AnimationType::kEaseInOut ||
+ animation_type == AnimationType::kImpulse),
duration_behavior.has_value());
}
@@ -314,14 +320,27 @@ base::TimeDelta ScrollOffsetAnimationCurve::Duration() const {
return total_animation_duration_;
}
-AnimationCurve::CurveType ScrollOffsetAnimationCurve::Type() const {
- return SCROLL_OFFSET;
+int ScrollOffsetAnimationCurve::Type() const {
+ return AnimationCurve::SCROLL_OFFSET;
+}
+
+const char* ScrollOffsetAnimationCurve::TypeName() const {
+ return "ScrollOffset";
}
-std::unique_ptr<AnimationCurve> ScrollOffsetAnimationCurve::Clone() const {
+std::unique_ptr<gfx::AnimationCurve> ScrollOffsetAnimationCurve::Clone() const {
return CloneToScrollOffsetAnimationCurve();
}
+void ScrollOffsetAnimationCurve::Tick(
+ base::TimeDelta t,
+ int property_id,
+ gfx::KeyframeModel* keyframe_model) const {
+ if (target_) {
+ target_->OnScrollOffsetAnimated(GetValue(t), property_id, keyframe_model);
+ }
+}
+
std::unique_ptr<ScrollOffsetAnimationCurve>
ScrollOffsetAnimationCurve::CloneToScrollOffsetAnimationCurve() const {
std::unique_ptr<TimingFunction> timing_function(
@@ -359,6 +378,11 @@ void ScrollOffsetAnimationCurve::UpdateTarget(
DCHECK_NE(animation_type_, AnimationType::kLinear)
<< "UpdateTarget is not supported on linear scroll animations.";
+ // UpdateTarget is still called for linear animations occasionally. This is
+ // tracked via crbug.com/1164008.
+ if (animation_type_ == AnimationType::kLinear)
+ return;
+
// If the new UpdateTarget actually happened before the previous one, keep
// |t| as the most recent, but reduce the duration of any generated
// animation.
@@ -399,11 +423,8 @@ void ScrollOffsetAnimationCurve::UpdateTarget(
return;
}
- base::TimeDelta new_duration =
- (animation_type_ == AnimationType::kEaseInOut)
- ? EaseInOutBoundedSegmentDuration(new_delta, t, delayed_by)
- : ImpulseSegmentDuration(new_delta, delayed_by);
-
+ const base::TimeDelta new_duration =
+ EaseInOutBoundedSegmentDuration(new_delta, t, delayed_by);
if (new_duration.InSecondsF() < kEpsilon) {
// The duration is (close to) 0, so stop the animation.
target_value_ = new_target;
@@ -417,23 +438,34 @@ void ScrollOffsetAnimationCurve::UpdateTarget(
double new_slope =
velocity * (new_duration.InSecondsF() / MaximumDimension(new_delta));
- if (animation_type_ == AnimationType::kEaseInOut) {
- timing_function_ = EaseInOutWithInitialSlope(new_slope);
- } else {
- DCHECK_EQ(animation_type_, AnimationType::kImpulse);
- if (IsNewTargetInOppositeDirection(current_position, target_value_,
- new_target)) {
- // Prevent any rubber-banding by setting the velocity (and subsequently,
- // the slope) to 0 when moving in the opposite direciton.
- new_slope = 0;
- }
- timing_function_ = ImpulseCurveWithInitialSlope(new_slope);
+ DCHECK(animation_type_ == AnimationType::kImpulse ||
+ animation_type_ == AnimationType::kEaseInOut);
+ if (animation_type_ == AnimationType::kImpulse &&
+ IsNewTargetInOppositeDirection(current_position, target_value_,
+ new_target)) {
+ // Prevent any rubber-banding by setting the velocity (and subsequently, the
+ // slope) to 0 when moving in the opposite direciton.
+ new_slope = 0;
}
+ timing_function_ = EaseInOutWithInitialSlope(new_slope);
initial_value_ = current_position;
target_value_ = new_target;
total_animation_duration_ = t + new_duration;
last_retarget_ = t;
}
+const ScrollOffsetAnimationCurve*
+ScrollOffsetAnimationCurve::ToScrollOffsetAnimationCurve(
+ const AnimationCurve* c) {
+ DCHECK_EQ(ScrollOffsetAnimationCurve::SCROLL_OFFSET, c->Type());
+ return static_cast<const ScrollOffsetAnimationCurve*>(c);
+}
+
+ScrollOffsetAnimationCurve*
+ScrollOffsetAnimationCurve::ToScrollOffsetAnimationCurve(AnimationCurve* c) {
+ DCHECK_EQ(ScrollOffsetAnimationCurve::SCROLL_OFFSET, c->Type());
+ return static_cast<ScrollOffsetAnimationCurve*>(c);
+}
+
} // namespace cc
diff --git a/chromium/cc/animation/scroll_offset_animation_curve.h b/chromium/cc/animation/scroll_offset_animation_curve.h
index 889cbcc453a..633ccf79b84 100644
--- a/chromium/cc/animation/scroll_offset_animation_curve.h
+++ b/chromium/cc/animation/scroll_offset_animation_curve.h
@@ -8,13 +8,15 @@
#include <memory>
#include "base/time/time.h"
-#include "cc/animation/animation_curve.h"
#include "cc/animation/animation_export.h"
+#include "ui/gfx/animation/keyframe/animation_curve.h"
#include "ui/gfx/geometry/scroll_offset.h"
-namespace cc {
-
+namespace gfx {
class TimingFunction;
+} // namespace gfx
+
+namespace cc {
// ScrollOffsetAnimationCurve computes scroll offset as a function of time
// during a scroll offset animation.
@@ -23,9 +25,18 @@ class TimingFunction;
// user input or programmatic scroll operations. For more information about
// scheduling and servicing scroll animations, see blink::ScrollAnimator and
// blink::ProgrammaticScrollAnimator.
-
-class CC_ANIMATION_EXPORT ScrollOffsetAnimationCurve : public AnimationCurve {
+class CC_ANIMATION_EXPORT ScrollOffsetAnimationCurve
+ : public gfx::AnimationCurve {
public:
+ class Target {
+ public:
+ ~Target() = default;
+
+ virtual void OnScrollOffsetAnimated(const gfx::ScrollOffset& value,
+ int target_property_id,
+ gfx::KeyframeModel* keyframe_model) = 0;
+ };
+
// Indicates how the animation duration should be computed for Ease-in-out
// style scroll animation curves.
enum class DurationBehavior {
@@ -39,6 +50,12 @@ class CC_ANIMATION_EXPORT ScrollOffsetAnimationCurve : public AnimationCurve {
INVERSE_DELTA
};
+ static const ScrollOffsetAnimationCurve* ToScrollOffsetAnimationCurve(
+ const AnimationCurve* c);
+
+ static ScrollOffsetAnimationCurve* ToScrollOffsetAnimationCurve(
+ AnimationCurve* c);
+
// There is inherent delay in input processing; it may take many milliseconds
// from the time of user input to when when we're actually able to handle it
// here. This delay is represented by the |delayed_by| value. The way we have
@@ -84,14 +101,21 @@ class CC_ANIMATION_EXPORT ScrollOffsetAnimationCurve : public AnimationCurve {
// AnimationCurve implementation
base::TimeDelta Duration() const override;
- CurveType Type() const override;
- std::unique_ptr<AnimationCurve> Clone() const override;
+ int Type() const override;
+ const char* TypeName() const override;
+ std::unique_ptr<gfx::AnimationCurve> Clone() const override;
std::unique_ptr<ScrollOffsetAnimationCurve>
CloneToScrollOffsetAnimationCurve() const;
-
+ void Tick(base::TimeDelta t,
+ int property_id,
+ gfx::KeyframeModel* keyframe_model) const override;
static void SetAnimationDurationForTesting(base::TimeDelta duration);
+ void set_target(Target* target) { target_ = target; }
private:
+ FRIEND_TEST_ALL_PREFIXES(ScrollOffsetAnimationCurveTest, ImpulseUpdateTarget);
+ FRIEND_TEST_ALL_PREFIXES(ScrollOffsetAnimationCurveTest,
+ ImpulseUpdateTargetSwitchDirections);
friend class ScrollOffsetAnimationCurveFactory;
enum class AnimationType { kLinear, kEaseInOut, kImpulse };
@@ -103,7 +127,7 @@ class CC_ANIMATION_EXPORT ScrollOffsetAnimationCurve : public AnimationCurve {
base::Optional<DurationBehavior> duration_behavior = base::nullopt);
ScrollOffsetAnimationCurve(
const gfx::ScrollOffset& target_value,
- std::unique_ptr<TimingFunction> timing_function,
+ std::unique_ptr<gfx::TimingFunction> timing_function,
AnimationType animation_type,
base::Optional<DurationBehavior> duration_behavior);
@@ -127,7 +151,7 @@ class CC_ANIMATION_EXPORT ScrollOffsetAnimationCurve : public AnimationCurve {
// Time from animation start to most recent UpdateTarget.
base::TimeDelta last_retarget_;
- std::unique_ptr<TimingFunction> timing_function_;
+ std::unique_ptr<gfx::TimingFunction> timing_function_;
AnimationType animation_type_;
// Only valid when |animation_type_| is EASE_IN_OUT.
@@ -136,6 +160,8 @@ class CC_ANIMATION_EXPORT ScrollOffsetAnimationCurve : public AnimationCurve {
bool has_set_initial_value_;
static base::Optional<double> animation_duration_for_testing_;
+
+ Target* target_ = nullptr;
};
} // namespace cc
diff --git a/chromium/cc/animation/scroll_offset_animation_curve_factory.cc b/chromium/cc/animation/scroll_offset_animation_curve_factory.cc
index 29f5cbc5d30..dcb9cb40662 100644
--- a/chromium/cc/animation/scroll_offset_animation_curve_factory.cc
+++ b/chromium/cc/animation/scroll_offset_animation_curve_factory.cc
@@ -4,9 +4,10 @@
#include "cc/animation/scroll_offset_animation_curve_factory.h"
+#include <memory>
#include "base/memory/ptr_util.h"
-#include "cc/animation/timing_function.h"
#include "cc/base/features.h"
+#include "ui/gfx/animation/keyframe/timing_function.h"
namespace cc {
namespace {
@@ -86,6 +87,7 @@ std::unique_ptr<ScrollOffsetAnimationCurve>
ScrollOffsetAnimationCurveFactory::CreateImpulseAnimation(
const gfx::ScrollOffset& target_value) {
return base::WrapUnique(new ScrollOffsetAnimationCurve(
- target_value, ScrollOffsetAnimationCurve::AnimationType::kImpulse));
+ target_value, ScrollOffsetAnimationCurve::AnimationType::kImpulse,
+ ScrollOffsetAnimationCurve::DurationBehavior::INVERSE_DELTA));
}
} // namespace cc
diff --git a/chromium/cc/animation/scroll_offset_animation_curve_unittest.cc b/chromium/cc/animation/scroll_offset_animation_curve_unittest.cc
index f0e8c423aa0..bbfb91218bc 100644
--- a/chromium/cc/animation/scroll_offset_animation_curve_unittest.cc
+++ b/chromium/cc/animation/scroll_offset_animation_curve_unittest.cc
@@ -5,9 +5,9 @@
#include "cc/animation/scroll_offset_animation_curve.h"
#include "cc/animation/scroll_offset_animation_curve_factory.h"
-#include "cc/animation/timing_function.h"
#include "cc/test/geometry_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/animation/keyframe/timing_function.h"
using DurationBehavior = cc::ScrollOffsetAnimationCurve::DurationBehavior;
@@ -21,6 +21,8 @@ namespace {
// This is the value of the default Impulse bezier curve when t = 0.5
constexpr double halfway_through_default_impulse_curve = 0.874246;
+} // namespace
+
TEST(ScrollOffsetAnimationCurveTest, DeltaBasedDuration) {
gfx::ScrollOffset target_value(100.f, 200.f);
std::unique_ptr<ScrollOffsetAnimationCurve> curve(
@@ -75,7 +77,6 @@ TEST(ScrollOffsetAnimationCurveTest, GetValue) {
EXPECT_GT(curve->Duration().InSecondsF(), 0);
EXPECT_LT(curve->Duration().InSecondsF(), 0.1);
- EXPECT_EQ(AnimationCurve::SCROLL_OFFSET, curve->Type());
EXPECT_EQ(duration, curve->Duration());
EXPECT_VECTOR2DF_EQ(initial_value,
@@ -104,30 +105,25 @@ TEST(ScrollOffsetAnimationCurveTest, Clone) {
curve->SetInitialValue(initial_value);
base::TimeDelta duration = curve->Duration();
- std::unique_ptr<AnimationCurve> clone(curve->Clone());
+ std::unique_ptr<gfx::AnimationCurve> clone(curve->Clone());
- EXPECT_EQ(AnimationCurve::SCROLL_OFFSET, clone->Type());
EXPECT_EQ(duration, clone->Duration());
- EXPECT_VECTOR2DF_EQ(initial_value,
- clone->ToScrollOffsetAnimationCurve()->GetValue(
- base::TimeDelta::FromSecondsD(-1.0)));
- EXPECT_VECTOR2DF_EQ(
- initial_value,
- clone->ToScrollOffsetAnimationCurve()->GetValue(base::TimeDelta()));
- EXPECT_VECTOR2DF_NEAR(
- gfx::ScrollOffset(6.f, 30.f),
- clone->ToScrollOffsetAnimationCurve()->GetValue(duration * 0.5f),
- 0.00025);
+ ScrollOffsetAnimationCurve* cloned_curve =
+ ScrollOffsetAnimationCurve::ToScrollOffsetAnimationCurve(clone.get());
+
+ EXPECT_VECTOR2DF_EQ(initial_value, cloned_curve->GetValue(
+ base::TimeDelta::FromSecondsD(-1.0)));
+ EXPECT_VECTOR2DF_EQ(initial_value, cloned_curve->GetValue(base::TimeDelta()));
+ EXPECT_VECTOR2DF_NEAR(gfx::ScrollOffset(6.f, 30.f),
+ cloned_curve->GetValue(duration * 0.5f), 0.00025);
+ EXPECT_VECTOR2DF_EQ(target_value, cloned_curve->GetValue(duration));
EXPECT_VECTOR2DF_EQ(
- target_value, clone->ToScrollOffsetAnimationCurve()->GetValue(duration));
- EXPECT_VECTOR2DF_EQ(target_value,
- clone->ToScrollOffsetAnimationCurve()->GetValue(
- duration + base::TimeDelta::FromSecondsD(1.f)));
+ target_value,
+ cloned_curve->GetValue(duration + base::TimeDelta::FromSecondsD(1.f)));
// Verify that the timing function was cloned correctly.
- gfx::ScrollOffset value =
- clone->ToScrollOffsetAnimationCurve()->GetValue(duration * 0.25f);
+ gfx::ScrollOffset value = cloned_curve->GetValue(duration * 0.25f);
EXPECT_NEAR(3.0333f, value.x(), 0.0002f);
EXPECT_NEAR(37.4168f, value.y(), 0.0002f);
}
@@ -208,8 +204,8 @@ TEST(ScrollOffsetAnimationCurveTest, ImpulseUpdateTarget) {
gfx::Vector2dF new_delta =
new_target_value.DeltaFrom(distance_halfway_through_initial_animation);
base::TimeDelta updated_segment_duration =
- ScrollOffsetAnimationCurve::ImpulseSegmentDuration(new_delta,
- base::TimeDelta());
+ curve->EaseInOutBoundedSegmentDuration(new_delta, base::TimeDelta(),
+ base::TimeDelta());
base::TimeDelta overall_duration = time_of_update + updated_segment_duration;
EXPECT_NEAR(overall_duration.InSecondsF(), curve->Duration().InSecondsF(),
@@ -257,25 +253,26 @@ TEST(ScrollOffsetAnimationCurveTest, ImpulseUpdateTargetSwitchDirections) {
curve->UpdateTarget(base::TimeDelta::FromSecondsD(initial_duration / 2),
updated_target);
- double updated_duration =
- ScrollOffsetAnimationCurve::ImpulseSegmentDuration(
- gfx::Vector2dF(updated_initial_value.x(), updated_initial_value.y()),
- base::TimeDelta())
- .InSecondsF();
-
EXPECT_NEAR(
initial_target_value.y() * halfway_through_default_impulse_curve,
curve->GetValue(base::TimeDelta::FromSecondsD(initial_duration / 2.0))
.y(),
0.01f);
- EXPECT_NEAR(
- updated_initial_value.y() * (1.0 - halfway_through_default_impulse_curve),
- curve
- ->GetValue(base::TimeDelta::FromSecondsD(initial_duration / 2.0 +
- updated_duration / 2.0))
- .y(),
- 0.01f);
+ // Once the impulse style curve is updated, it turns to an ease-in ease-out
+ // type curve.
+ double updated_duration = curve
+ ->EaseInOutBoundedSegmentDuration(
+ gfx::Vector2dF(updated_initial_value.x(),
+ updated_initial_value.y()),
+ base::TimeDelta(), base::TimeDelta())
+ .InSecondsF();
+ EXPECT_NEAR(updated_initial_value.y() * 0.5,
+ curve
+ ->GetValue(base::TimeDelta::FromSecondsD(
+ initial_duration / 2.0 + updated_duration / 2.0))
+ .y(),
+ 0.01f);
EXPECT_NEAR(0.0,
curve
->GetValue(base::TimeDelta::FromSecondsD(
@@ -453,5 +450,4 @@ TEST(ScrollOffsetAnimationCurveTest, UpdateTargetZeroLastSegmentDuration) {
EXPECT_NEAR(expected_duration, curve->Duration().InSecondsF(), 0.0002f);
}
-} // namespace
} // namespace cc
diff --git a/chromium/cc/animation/scroll_offset_animations_impl.cc b/chromium/cc/animation/scroll_offset_animations_impl.cc
index 498992120c9..73fc4ed2935 100644
--- a/chromium/cc/animation/scroll_offset_animations_impl.cc
+++ b/chromium/cc/animation/scroll_offset_animations_impl.cc
@@ -4,6 +4,8 @@
#include "cc/animation/scroll_offset_animations_impl.h"
+#include <utility>
+
#include "base/trace_event/trace_event.h"
#include "base/trace_event/traced_value.h"
#include "cc/animation/animation.h"
@@ -12,7 +14,7 @@
#include "cc/animation/animation_timeline.h"
#include "cc/animation/element_animations.h"
#include "cc/animation/scroll_offset_animation_curve_factory.h"
-#include "cc/animation/timing_function.h"
+#include "ui/gfx/animation/keyframe/timing_function.h"
namespace cc {
@@ -69,14 +71,15 @@ void ScrollOffsetAnimationsImpl::MouseWheelScrollAnimationCreate(
void ScrollOffsetAnimationsImpl::ScrollAnimationCreateInternal(
ElementId element_id,
- std::unique_ptr<AnimationCurve> curve,
+ std::unique_ptr<gfx::AnimationCurve> curve,
base::TimeDelta animation_start_offset) {
TRACE_EVENT_INSTANT1("cc", "ScrollAnimationCreate", TRACE_EVENT_SCOPE_THREAD,
"Duration", curve->Duration().InMillisecondsF());
std::unique_ptr<KeyframeModel> keyframe_model = KeyframeModel::Create(
std::move(curve), AnimationIdProvider::NextKeyframeModelId(),
- AnimationIdProvider::NextGroupId(), TargetProperty::SCROLL_OFFSET);
+ AnimationIdProvider::NextGroupId(),
+ KeyframeModel::TargetPropertyId(TargetProperty::SCROLL_OFFSET));
keyframe_model->set_time_offset(animation_start_offset);
keyframe_model->SetIsImplOnly();
@@ -111,7 +114,8 @@ bool ScrollOffsetAnimationsImpl::ScrollAnimationUpdateTarget(
return true;
ScrollOffsetAnimationCurve* curve =
- keyframe_model->curve()->ToScrollOffsetAnimationCurve();
+ ScrollOffsetAnimationCurve::ToScrollOffsetAnimationCurve(
+ keyframe_model->curve());
gfx::ScrollOffset new_target =
gfx::ScrollOffsetWithDelta(curve->target_value(), scroll_delta);
@@ -164,14 +168,15 @@ void ScrollOffsetAnimationsImpl::ScrollAnimationApplyAdjustment(
}
std::unique_ptr<ScrollOffsetAnimationCurve> new_curve =
- keyframe_model->curve()
- ->ToScrollOffsetAnimationCurve()
+ ScrollOffsetAnimationCurve::ToScrollOffsetAnimationCurve(
+ keyframe_model->curve())
->CloneToScrollOffsetAnimationCurve();
new_curve->ApplyAdjustment(adjustment);
std::unique_ptr<KeyframeModel> new_keyframe_model = KeyframeModel::Create(
std::move(new_curve), AnimationIdProvider::NextKeyframeModelId(),
- AnimationIdProvider::NextGroupId(), TargetProperty::SCROLL_OFFSET);
+ AnimationIdProvider::NextGroupId(),
+ KeyframeModel::TargetPropertyId(TargetProperty::SCROLL_OFFSET));
new_keyframe_model->set_start_time(keyframe_model->start_time());
new_keyframe_model->SetIsImplOnly();
new_keyframe_model->set_affects_active_elements(false);
diff --git a/chromium/cc/animation/scroll_offset_animations_impl.h b/chromium/cc/animation/scroll_offset_animations_impl.h
index c2aa77e4f2c..50a78945fcf 100644
--- a/chromium/cc/animation/scroll_offset_animations_impl.h
+++ b/chromium/cc/animation/scroll_offset_animations_impl.h
@@ -5,6 +5,8 @@
#ifndef CC_ANIMATION_SCROLL_OFFSET_ANIMATIONS_IMPL_H_
#define CC_ANIMATION_SCROLL_OFFSET_ANIMATIONS_IMPL_H_
+#include <memory>
+
#include "base/memory/ref_counted.h"
#include "cc/animation/animation_delegate.h"
#include "cc/animation/scroll_offset_animation_curve.h"
@@ -69,11 +71,11 @@ class CC_ANIMATION_EXPORT ScrollOffsetAnimationsImpl
void NotifyAnimationAborted(base::TimeTicks monotonic_time,
int target_property,
int group) override {}
- void NotifyAnimationTakeover(base::TimeTicks monotonic_time,
- int target_property,
- base::TimeTicks animation_start_time,
- std::unique_ptr<AnimationCurve> curve) override {
- }
+ void NotifyAnimationTakeover(
+ base::TimeTicks monotonic_time,
+ int target_property,
+ base::TimeTicks animation_start_time,
+ std::unique_ptr<gfx::AnimationCurve> curve) override {}
void NotifyLocalTimeUpdated(
base::Optional<base::TimeDelta> local_time) override {}
@@ -82,7 +84,7 @@ class CC_ANIMATION_EXPORT ScrollOffsetAnimationsImpl
private:
void ScrollAnimationCreateInternal(ElementId element_id,
- std::unique_ptr<AnimationCurve> curve,
+ std::unique_ptr<gfx::AnimationCurve> curve,
base::TimeDelta animation_start_offset);
void ReattachScrollOffsetAnimationIfNeeded(ElementId element_id);
diff --git a/chromium/cc/animation/scroll_timeline.h b/chromium/cc/animation/scroll_timeline.h
index c79001fb825..fbdbc46783f 100644
--- a/chromium/cc/animation/scroll_timeline.h
+++ b/chromium/cc/animation/scroll_timeline.h
@@ -5,6 +5,7 @@
#ifndef CC_ANIMATION_SCROLL_TIMELINE_H_
#define CC_ANIMATION_SCROLL_TIMELINE_H_
+#include <vector>
#include "base/optional.h"
#include "base/time/time.h"
#include "cc/animation/animation_export.h"
@@ -124,14 +125,22 @@ inline ScrollTimeline* ToScrollTimeline(AnimationTimeline* timeline) {
template <typename T>
double ComputeProgress(double current_offset, const T& resolved_offsets) {
DCHECK_GE(resolved_offsets.size(), 2u);
+ // When start offset is greater than end offset, current time is calculated
+ // outside of this method.
+ DCHECK(resolved_offsets[0] < resolved_offsets[resolved_offsets.size() - 1]);
DCHECK(current_offset < resolved_offsets[resolved_offsets.size() - 1]);
- // Look for scroll offset that contains the current offset.
+ // 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.
unsigned int offset_id;
- for (offset_id = 1; offset_id < resolved_offsets.size() &&
- resolved_offsets[offset_id] <= current_offset;
- offset_id++) {
+ for (offset_id = resolved_offsets.size() - 1;
+ offset_id > 0 && !(resolved_offsets[offset_id - 1] <= current_offset &&
+ current_offset < resolved_offsets[offset_id]);
+ offset_id--) {
}
- DCHECK(offset_id < resolved_offsets.size());
+ DCHECK_GE(offset_id, 1u);
// Weight of each offset within time range is distributed equally.
double offset_distance = 1.0 / (resolved_offsets.size() - 1);
// Progress of the current offset within its offset range.
diff --git a/chromium/cc/animation/scroll_timeline_unittest.cc b/chromium/cc/animation/scroll_timeline_unittest.cc
index 15589ae2f18..4ee60fc6bd4 100644
--- a/chromium/cc/animation/scroll_timeline_unittest.cc
+++ b/chromium/cc/animation/scroll_timeline_unittest.cc
@@ -205,6 +205,51 @@ TEST_F(ScrollTimelineTest, MultipleScrollOffsetsCurrentTimeCalculations) {
time_range, vertical_timeline->CurrentTime(scroll_tree(), false));
}
+TEST_F(ScrollTimelineTest, OverlappingScrollOffsets) {
+ double time_range = 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, time_range);
+
+ // Offset is less than start offset ==> current time is 0.
+ SetScrollOffset(&property_trees(), scroller_id(), gfx::ScrollOffset(0, 300));
+ EXPECT_SCROLL_TIMELINE_TIME_NEAR(
+ 0, vertical_timeline->CurrentTime(scroll_tree(), false));
+
+ // Offset is greater than end offset ==> current time is time_range.
+ SetScrollOffset(&property_trees(), scroller_id(), gfx::ScrollOffset(0, 360));
+ EXPECT_SCROLL_TIMELINE_TIME_NEAR(
+ time_range, vertical_timeline->CurrentTime(scroll_tree(), false));
+
+ scroll_offsets = {0.0, 400.0, 200.0};
+
+ vertical_timeline = ScrollTimeline::Create(
+ scroller_id(), ScrollTimeline::ScrollDown, scroll_offsets, time_range);
+
+ SetScrollOffset(&property_trees(), scroller_id(), gfx::ScrollOffset(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(
+ time_range * 0.5 * 0.25,
+ vertical_timeline->CurrentTime(scroll_tree(), false));
+
+ scroll_offsets = {200.0, 0.0, 400.0};
+
+ vertical_timeline = ScrollTimeline::Create(
+ scroller_id(), ScrollTimeline::ScrollDown, scroll_offsets, time_range);
+
+ SetScrollOffset(&property_trees(), scroller_id(), gfx::ScrollOffset(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(
+ time_range * (0.5 + 0.5 * 0.75),
+ vertical_timeline->CurrentTime(scroll_tree(), false));
+}
+
TEST_F(ScrollTimelineTest, CurrentTimeIsAdjustedForTimeRange) {
double time_range = content_size().height() - container_size().height();
diff --git a/chromium/cc/animation/timing_function.cc b/chromium/cc/animation/timing_function.cc
deleted file mode 100644
index 8906be4d9f7..00000000000
--- a/chromium/cc/animation/timing_function.cc
+++ /dev/null
@@ -1,182 +0,0 @@
-// Copyright 2012 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/animation/timing_function.h"
-
-#include <cmath>
-#include <memory>
-
-#include "base/check_op.h"
-#include "base/memory/ptr_util.h"
-#include "base/notreached.h"
-
-namespace cc {
-
-TimingFunction::TimingFunction() = default;
-
-TimingFunction::~TimingFunction() = default;
-
-std::unique_ptr<CubicBezierTimingFunction>
-CubicBezierTimingFunction::CreatePreset(EaseType ease_type) {
- // These numbers come from
- // http://www.w3.org/TR/css3-transitions/#transition-timing-function_tag.
- switch (ease_type) {
- case EaseType::EASE:
- return base::WrapUnique(
- new CubicBezierTimingFunction(ease_type, 0.25, 0.1, 0.25, 1.0));
- case EaseType::EASE_IN:
- return base::WrapUnique(
- new CubicBezierTimingFunction(ease_type, 0.42, 0.0, 1.0, 1.0));
- case EaseType::EASE_OUT:
- return base::WrapUnique(
- new CubicBezierTimingFunction(ease_type, 0.0, 0.0, 0.58, 1.0));
- case EaseType::EASE_IN_OUT:
- return base::WrapUnique(
- new CubicBezierTimingFunction(ease_type, 0.42, 0.0, 0.58, 1));
- default:
- NOTREACHED();
- return nullptr;
- }
-}
-std::unique_ptr<CubicBezierTimingFunction>
-CubicBezierTimingFunction::Create(double x1, double y1, double x2, double y2) {
- return base::WrapUnique(
- new CubicBezierTimingFunction(EaseType::CUSTOM, x1, y1, x2, y2));
-}
-
-CubicBezierTimingFunction::CubicBezierTimingFunction(EaseType ease_type,
- double x1,
- double y1,
- double x2,
- double y2)
- : bezier_(x1, y1, x2, y2), ease_type_(ease_type) {}
-
-CubicBezierTimingFunction::~CubicBezierTimingFunction() = default;
-
-TimingFunction::Type CubicBezierTimingFunction::GetType() const {
- return Type::CUBIC_BEZIER;
-}
-
-double CubicBezierTimingFunction::GetValue(double x) const {
- return bezier_.Solve(x);
-}
-
-double CubicBezierTimingFunction::Velocity(double x) const {
- return bezier_.Slope(x);
-}
-
-std::unique_ptr<TimingFunction> CubicBezierTimingFunction::Clone() const {
- return base::WrapUnique(new CubicBezierTimingFunction(*this));
-}
-
-std::unique_ptr<StepsTimingFunction> StepsTimingFunction::Create(
- int steps,
- StepPosition step_position) {
- return base::WrapUnique(new StepsTimingFunction(steps, step_position));
-}
-
-StepsTimingFunction::StepsTimingFunction(int steps, StepPosition step_position)
- : steps_(steps), step_position_(step_position) {}
-
-StepsTimingFunction::~StepsTimingFunction() = default;
-
-TimingFunction::Type StepsTimingFunction::GetType() const {
- return Type::STEPS;
-}
-
-double StepsTimingFunction::GetValue(double t) const {
- return GetPreciseValue(t, TimingFunction::LimitDirection::RIGHT);
-}
-
-std::unique_ptr<TimingFunction> StepsTimingFunction::Clone() const {
- return base::WrapUnique(new StepsTimingFunction(*this));
-}
-
-double StepsTimingFunction::Velocity(double x) const {
- return 0;
-}
-
-double StepsTimingFunction::GetPreciseValue(double t,
- LimitDirection direction) const {
- const double steps = static_cast<double>(steps_);
- double current_step = std::floor((steps * t) + GetStepsStartOffset());
- // Adjust step if using a left limit at a discontinuous step boundary.
- if (direction == LimitDirection::LEFT &&
- steps * t - std::floor(steps * t) == 0) {
- current_step -= 1;
- }
- // Jumps may differ from steps based on the number of end-point
- // discontinuities, which may be 0, 1 or 2.
- int jumps = NumberOfJumps();
- if (t >= 0 && current_step < 0)
- current_step = 0;
- if (t <= 1 && current_step > jumps)
- current_step = jumps;
- return current_step / jumps;
-}
-
-int StepsTimingFunction::NumberOfJumps() const {
- switch (step_position_) {
- case StepPosition::END:
- case StepPosition::START:
- case StepPosition::JUMP_END:
- case StepPosition::JUMP_START:
- return steps_;
-
- case StepPosition::JUMP_BOTH:
- return steps_ + 1;
-
- case StepPosition::JUMP_NONE:
- DCHECK_GT(steps_, 1);
- return steps_ - 1;
-
- default:
- NOTREACHED();
- return steps_;
- }
-}
-
-float StepsTimingFunction::GetStepsStartOffset() const {
- switch (step_position_) {
- case StepPosition::JUMP_BOTH:
- case StepPosition::JUMP_START:
- case StepPosition::START:
- return 1;
-
- case StepPosition::JUMP_END:
- case StepPosition::JUMP_NONE:
- case StepPosition::END:
- return 0;
-
- default:
- NOTREACHED();
- return 1;
- }
-}
-
-std::unique_ptr<LinearTimingFunction> LinearTimingFunction::Create() {
- return base::WrapUnique(new LinearTimingFunction());
-}
-
-LinearTimingFunction::LinearTimingFunction() = default;
-
-LinearTimingFunction::~LinearTimingFunction() = default;
-
-TimingFunction::Type LinearTimingFunction::GetType() const {
- return Type::LINEAR;
-}
-
-std::unique_ptr<TimingFunction> LinearTimingFunction::Clone() const {
- return base::WrapUnique(new LinearTimingFunction(*this));
-}
-
-double LinearTimingFunction::Velocity(double x) const {
- return 0;
-}
-
-double LinearTimingFunction::GetValue(double t) const {
- return t;
-}
-
-} // namespace cc
diff --git a/chromium/cc/animation/timing_function.h b/chromium/cc/animation/timing_function.h
deleted file mode 100644
index 4422a4a6f7d..00000000000
--- a/chromium/cc/animation/timing_function.h
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright 2012 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_ANIMATION_TIMING_FUNCTION_H_
-#define CC_ANIMATION_TIMING_FUNCTION_H_
-
-#include <memory>
-
-#include "cc/animation/animation_export.h"
-#include "ui/gfx/geometry/cubic_bezier.h"
-
-namespace cc {
-
-// See http://www.w3.org/TR/css3-transitions/.
-class CC_ANIMATION_EXPORT TimingFunction {
- public:
- virtual ~TimingFunction();
-
- TimingFunction& operator=(const TimingFunction&) = delete;
-
- // Note that LINEAR is a nullptr TimingFunction (for now).
- enum class Type { LINEAR, CUBIC_BEZIER, STEPS };
-
- // Which limit to apply at a discontinuous boundary.
- enum class LimitDirection { LEFT, RIGHT };
-
- virtual Type GetType() const = 0;
- virtual double GetValue(double t) const = 0;
- virtual double Velocity(double time) const = 0;
- virtual std::unique_ptr<TimingFunction> Clone() const = 0;
-
- protected:
- TimingFunction();
-};
-
-class CC_ANIMATION_EXPORT CubicBezierTimingFunction : public TimingFunction {
- public:
- enum class EaseType { EASE, EASE_IN, EASE_OUT, EASE_IN_OUT, CUSTOM };
-
- static std::unique_ptr<CubicBezierTimingFunction> CreatePreset(
- EaseType ease_type);
- static std::unique_ptr<CubicBezierTimingFunction> Create(double x1,
- double y1,
- double x2,
- double y2);
- ~CubicBezierTimingFunction() override;
-
- CubicBezierTimingFunction& operator=(const CubicBezierTimingFunction&) =
- delete;
-
- // TimingFunction implementation.
- Type GetType() const override;
- double GetValue(double time) const override;
- double Velocity(double time) const override;
- std::unique_ptr<TimingFunction> Clone() const override;
-
- EaseType ease_type() const { return ease_type_; }
- const gfx::CubicBezier& bezier() const { return bezier_; }
-
- private:
- CubicBezierTimingFunction(EaseType ease_type,
- double x1,
- double y1,
- double x2,
- double y2);
-
- gfx::CubicBezier bezier_;
- EaseType ease_type_;
-};
-
-class CC_ANIMATION_EXPORT StepsTimingFunction : public TimingFunction {
- public:
- // step-timing-function values
- // https://drafts.csswg.org/css-easing-1/#typedef-step-timing-function
- enum class StepPosition {
- START, // Discontinuity at progress = 0.
- // Alias for jump-start. Maintaining a separate enumerated value
- // for serialization.
- END, // Discontinuity at progress = 1.
- // Alias for jump-end. Maintaining a separate enumerated value
- // for serialization.
- JUMP_BOTH, // Discontinuities at progress = 0 and 1.
- JUMP_END, // Discontinuity at progress = 1.
- JUMP_NONE, // Continuous at progress = 0 and 1.
- JUMP_START // Discontinuity at progress = 0.
- };
-
- static std::unique_ptr<StepsTimingFunction> Create(
- int steps,
- StepPosition step_position);
- ~StepsTimingFunction() override;
-
- StepsTimingFunction& operator=(const StepsTimingFunction&) = delete;
-
- // TimingFunction implementation.
- Type GetType() const override;
- double GetValue(double t) const override;
- std::unique_ptr<TimingFunction> Clone() const override;
- double Velocity(double time) const override;
-
- int steps() const { return steps_; }
- StepPosition step_position() const { return step_position_; }
- double GetPreciseValue(double t, LimitDirection limit_direction) const;
-
- private:
- StepsTimingFunction(int steps, StepPosition step_position);
-
- // The number of jumps is the number of discontinuities in the timing
- // function. There is a subtle distinction between the number of steps and
- // jumps. The number of steps is the number of intervals in the timing
- // function. The number of jumps differs from the number of steps when either
- // both or neither end point has a discontinuity.
- // https://drafts.csswg.org/css-easing-1/#step-easing-functions
- int NumberOfJumps() const;
-
- float GetStepsStartOffset() const;
-
- int steps_;
- StepPosition step_position_;
-};
-
-class CC_ANIMATION_EXPORT LinearTimingFunction : public TimingFunction {
- public:
- static std::unique_ptr<LinearTimingFunction> Create();
- ~LinearTimingFunction() override;
-
- // TimingFunction implementation.
- Type GetType() const override;
- double GetValue(double t) const override;
- std::unique_ptr<TimingFunction> Clone() const override;
- double Velocity(double time) const override;
-
- private:
- LinearTimingFunction();
-};
-
-} // namespace cc
-
-#endif // CC_ANIMATION_TIMING_FUNCTION_H_
diff --git a/chromium/cc/animation/transform_operation.cc b/chromium/cc/animation/transform_operation.cc
deleted file mode 100644
index cbc222b5fec..00000000000
--- a/chromium/cc/animation/transform_operation.cc
+++ /dev/null
@@ -1,514 +0,0 @@
-// Copyright 2013 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 <limits>
-#include <utility>
-
-#include "base/check_op.h"
-#include "base/notreached.h"
-#include "base/numerics/math_constants.h"
-#include "base/numerics/ranges.h"
-#include "cc/animation/transform_operation.h"
-#include "cc/animation/transform_operations.h"
-#include "ui/gfx/geometry/angle_conversions.h"
-#include "ui/gfx/geometry/box_f.h"
-#include "ui/gfx/geometry/vector3d_f.h"
-#include "ui/gfx/transform_util.h"
-
-namespace {
-const SkScalar kAngleEpsilon = 1e-4f;
-}
-
-namespace cc {
-
-bool TransformOperation::IsIdentity() const {
- return matrix.IsIdentity();
-}
-
-static bool IsOperationIdentity(const TransformOperation* operation) {
- return !operation || operation->IsIdentity();
-}
-
-static bool ShareSameAxis(const TransformOperation* from,
- const TransformOperation* to,
- SkScalar* axis_x,
- SkScalar* axis_y,
- SkScalar* axis_z,
- SkScalar* angle_from) {
- if (IsOperationIdentity(from) && IsOperationIdentity(to))
- return false;
-
- if (IsOperationIdentity(from) && !IsOperationIdentity(to)) {
- *axis_x = to->rotate.axis.x;
- *axis_y = to->rotate.axis.y;
- *axis_z = to->rotate.axis.z;
- *angle_from = 0;
- return true;
- }
-
- if (!IsOperationIdentity(from) && IsOperationIdentity(to)) {
- *axis_x = from->rotate.axis.x;
- *axis_y = from->rotate.axis.y;
- *axis_z = from->rotate.axis.z;
- *angle_from = from->rotate.angle;
- return true;
- }
-
- SkScalar length_2 = from->rotate.axis.x * from->rotate.axis.x +
- from->rotate.axis.y * from->rotate.axis.y +
- from->rotate.axis.z * from->rotate.axis.z;
- SkScalar other_length_2 = to->rotate.axis.x * to->rotate.axis.x +
- to->rotate.axis.y * to->rotate.axis.y +
- to->rotate.axis.z * to->rotate.axis.z;
-
- if (length_2 <= kAngleEpsilon || other_length_2 <= kAngleEpsilon)
- return false;
-
- SkScalar dot = to->rotate.axis.x * from->rotate.axis.x +
- to->rotate.axis.y * from->rotate.axis.y +
- to->rotate.axis.z * from->rotate.axis.z;
- SkScalar error =
- SkScalarAbs(SK_Scalar1 - (dot * dot) / (length_2 * other_length_2));
- bool result = error < kAngleEpsilon;
- if (result) {
- *axis_x = to->rotate.axis.x;
- *axis_y = to->rotate.axis.y;
- *axis_z = to->rotate.axis.z;
- // If the axes are pointing in opposite directions, we need to reverse
- // the angle.
- *angle_from = dot > 0 ? from->rotate.angle : -from->rotate.angle;
- }
- return result;
-}
-
-static SkScalar BlendSkScalars(SkScalar from, SkScalar to, SkScalar progress) {
- return from * (1 - progress) + to * progress;
-}
-
-void TransformOperation::Bake() {
- matrix.MakeIdentity();
- switch (type) {
- case TransformOperation::TRANSFORM_OPERATION_TRANSLATE:
- matrix.Translate3d(translate.x, translate.y, translate.z);
- break;
- case TransformOperation::TRANSFORM_OPERATION_ROTATE:
- matrix.RotateAbout(
- gfx::Vector3dF(rotate.axis.x, rotate.axis.y, rotate.axis.z),
- rotate.angle);
- break;
- case TransformOperation::TRANSFORM_OPERATION_SCALE:
- matrix.Scale3d(scale.x, scale.y, scale.z);
- break;
- case TransformOperation::TRANSFORM_OPERATION_SKEWX:
- case TransformOperation::TRANSFORM_OPERATION_SKEWY:
- case TransformOperation::TRANSFORM_OPERATION_SKEW:
- matrix.Skew(skew.x, skew.y);
- break;
- case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE:
- matrix.ApplyPerspectiveDepth(perspective_depth);
- break;
- case TransformOperation::TRANSFORM_OPERATION_MATRIX:
- case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
- break;
- }
-}
-
-bool TransformOperation::ApproximatelyEqual(const TransformOperation& other,
- SkScalar tolerance) const {
- DCHECK_LE(0, tolerance);
- if (type != other.type)
- return false;
- switch (type) {
- case TransformOperation::TRANSFORM_OPERATION_TRANSLATE:
- return base::IsApproximatelyEqual(translate.x, other.translate.x,
- tolerance) &&
- base::IsApproximatelyEqual(translate.y, other.translate.y,
- tolerance) &&
- base::IsApproximatelyEqual(translate.z, other.translate.z,
- tolerance);
- case TransformOperation::TRANSFORM_OPERATION_ROTATE:
- return base::IsApproximatelyEqual(rotate.axis.x, other.rotate.axis.x,
- tolerance) &&
- base::IsApproximatelyEqual(rotate.axis.y, other.rotate.axis.y,
- tolerance) &&
- base::IsApproximatelyEqual(rotate.axis.z, other.rotate.axis.z,
- tolerance) &&
- base::IsApproximatelyEqual(rotate.angle, other.rotate.angle,
- tolerance);
- case TransformOperation::TRANSFORM_OPERATION_SCALE:
- return base::IsApproximatelyEqual(scale.x, other.scale.x, tolerance) &&
- base::IsApproximatelyEqual(scale.y, other.scale.y, tolerance) &&
- base::IsApproximatelyEqual(scale.z, other.scale.z, tolerance);
- case TransformOperation::TRANSFORM_OPERATION_SKEWX:
- case TransformOperation::TRANSFORM_OPERATION_SKEWY:
- case TransformOperation::TRANSFORM_OPERATION_SKEW:
- return base::IsApproximatelyEqual(skew.x, other.skew.x, tolerance) &&
- base::IsApproximatelyEqual(skew.y, other.skew.y, tolerance);
- case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE:
- return base::IsApproximatelyEqual(perspective_depth,
- other.perspective_depth, tolerance);
- case TransformOperation::TRANSFORM_OPERATION_MATRIX:
- // TODO(vollick): we could expose a tolerance on gfx::Transform, but it's
- // complex since we need a different tolerance per component. Driving this
- // with a single tolerance will take some care. For now, we will check
- // exact equality where the tolerance is 0.0f, otherwise we will use the
- // unparameterized version of gfx::Transform::ApproximatelyEqual.
- if (tolerance == 0.0f)
- return matrix == other.matrix;
- else
- return matrix.ApproximatelyEqual(other.matrix);
- case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
- return other.matrix.IsIdentity();
- }
- NOTREACHED();
- return false;
-}
-
-bool TransformOperation::BlendTransformOperations(
- const TransformOperation* from,
- const TransformOperation* to,
- SkScalar progress,
- TransformOperation* result) {
- if (IsOperationIdentity(from) && IsOperationIdentity(to))
- return true;
-
- TransformOperation::Type interpolation_type =
- TransformOperation::TRANSFORM_OPERATION_IDENTITY;
- if (IsOperationIdentity(to))
- interpolation_type = from->type;
- else
- interpolation_type = to->type;
- result->type = interpolation_type;
-
- switch (interpolation_type) {
- case TransformOperation::TRANSFORM_OPERATION_TRANSLATE: {
- SkScalar from_x = IsOperationIdentity(from) ? 0 : from->translate.x;
- SkScalar from_y = IsOperationIdentity(from) ? 0 : from->translate.y;
- SkScalar from_z = IsOperationIdentity(from) ? 0 : from->translate.z;
- SkScalar to_x = IsOperationIdentity(to) ? 0 : to->translate.x;
- SkScalar to_y = IsOperationIdentity(to) ? 0 : to->translate.y;
- SkScalar to_z = IsOperationIdentity(to) ? 0 : to->translate.z;
- result->translate.x = BlendSkScalars(from_x, to_x, progress),
- result->translate.y = BlendSkScalars(from_y, to_y, progress),
- result->translate.z = BlendSkScalars(from_z, to_z, progress),
- result->Bake();
- break;
- }
- case TransformOperation::TRANSFORM_OPERATION_ROTATE: {
- SkScalar axis_x = 0;
- SkScalar axis_y = 0;
- SkScalar axis_z = 1;
- SkScalar from_angle = 0;
- SkScalar to_angle = IsOperationIdentity(to) ? 0 : to->rotate.angle;
- if (ShareSameAxis(from, to, &axis_x, &axis_y, &axis_z, &from_angle)) {
- result->rotate.axis.x = axis_x;
- result->rotate.axis.y = axis_y;
- result->rotate.axis.z = axis_z;
- result->rotate.angle = BlendSkScalars(from_angle, to_angle, progress);
- result->Bake();
- } else {
- if (!IsOperationIdentity(to))
- result->matrix = to->matrix;
- gfx::Transform from_matrix;
- if (!IsOperationIdentity(from))
- from_matrix = from->matrix;
- if (!result->matrix.Blend(from_matrix, progress))
- return false;
- }
- break;
- }
- case TransformOperation::TRANSFORM_OPERATION_SCALE: {
- SkScalar from_x = IsOperationIdentity(from) ? 1 : from->scale.x;
- SkScalar from_y = IsOperationIdentity(from) ? 1 : from->scale.y;
- SkScalar from_z = IsOperationIdentity(from) ? 1 : from->scale.z;
- SkScalar to_x = IsOperationIdentity(to) ? 1 : to->scale.x;
- SkScalar to_y = IsOperationIdentity(to) ? 1 : to->scale.y;
- SkScalar to_z = IsOperationIdentity(to) ? 1 : to->scale.z;
- result->scale.x = BlendSkScalars(from_x, to_x, progress);
- result->scale.y = BlendSkScalars(from_y, to_y, progress);
- result->scale.z = BlendSkScalars(from_z, to_z, progress);
- result->Bake();
- break;
- }
- case TransformOperation::TRANSFORM_OPERATION_SKEWX:
- case TransformOperation::TRANSFORM_OPERATION_SKEWY:
- case TransformOperation::TRANSFORM_OPERATION_SKEW: {
- SkScalar from_x = IsOperationIdentity(from) ? 0 : from->skew.x;
- SkScalar from_y = IsOperationIdentity(from) ? 0 : from->skew.y;
- SkScalar to_x = IsOperationIdentity(to) ? 0 : to->skew.x;
- SkScalar to_y = IsOperationIdentity(to) ? 0 : to->skew.y;
- result->skew.x = BlendSkScalars(from_x, to_x, progress);
- result->skew.y = BlendSkScalars(from_y, to_y, progress);
- result->Bake();
- break;
- }
- case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE: {
- SkScalar from_perspective_depth =
- IsOperationIdentity(from) ? std::numeric_limits<SkScalar>::max()
- : from->perspective_depth;
- SkScalar to_perspective_depth = IsOperationIdentity(to)
- ? std::numeric_limits<SkScalar>::max()
- : to->perspective_depth;
- if (from_perspective_depth == 0.f || to_perspective_depth == 0.f)
- return false;
-
- SkScalar blended_perspective_depth = BlendSkScalars(
- 1.f / from_perspective_depth, 1.f / to_perspective_depth, progress);
-
- if (blended_perspective_depth == 0.f)
- return false;
-
- result->perspective_depth = 1.f / blended_perspective_depth;
- result->Bake();
- break;
- }
- case TransformOperation::TRANSFORM_OPERATION_MATRIX: {
- if (!IsOperationIdentity(to))
- result->matrix = to->matrix;
- gfx::Transform from_matrix;
- if (!IsOperationIdentity(from))
- from_matrix = from->matrix;
- if (!result->matrix.Blend(from_matrix, progress))
- return false;
- break;
- }
- case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
- // Do nothing.
- break;
- }
-
- return true;
-}
-
-// If p = (px, py) is a point in the plane being rotated about (0, 0, nz), this
-// function computes the angles we would have to rotate from p to get to
-// (length(p), 0), (-length(p), 0), (0, length(p)), (0, -length(p)). If nz is
-// negative, these angles will need to be reversed.
-static void FindCandidatesInPlane(float px,
- float py,
- float nz,
- double* candidates,
- int* num_candidates) {
- double phi = atan2(px, py);
- *num_candidates = 4;
- candidates[0] = phi;
- for (int i = 1; i < *num_candidates; ++i)
- candidates[i] = candidates[i - 1] + base::kPiDouble / 2;
- if (nz < 0.f) {
- for (int i = 0; i < *num_candidates; ++i)
- candidates[i] *= -1.f;
- }
-}
-
-static void BoundingBoxForArc(const gfx::Point3F& point,
- const TransformOperation* from,
- const TransformOperation* to,
- SkScalar min_progress,
- SkScalar max_progress,
- gfx::BoxF* box) {
- const TransformOperation* exemplar = from ? from : to;
- gfx::Vector3dF axis(exemplar->rotate.axis.x,
- exemplar->rotate.axis.y,
- exemplar->rotate.axis.z);
-
- const bool x_is_zero = axis.x() == 0.f;
- const bool y_is_zero = axis.y() == 0.f;
- const bool z_is_zero = axis.z() == 0.f;
-
- // We will have at most 6 angles to test (excluding from->angle and
- // to->angle).
- static const int kMaxNumCandidates = 6;
- double candidates[kMaxNumCandidates];
- int num_candidates = kMaxNumCandidates;
-
- if (x_is_zero && y_is_zero && z_is_zero)
- return;
-
- SkScalar from_angle = from ? from->rotate.angle : 0.f;
- SkScalar to_angle = to ? to->rotate.angle : 0.f;
-
- // If the axes of rotation are pointing in opposite directions, we need to
- // flip one of the angles. Note, if both |from| and |to| exist, then axis will
- // correspond to |from|.
- if (from && to) {
- gfx::Vector3dF other_axis(
- to->rotate.axis.x, to->rotate.axis.y, to->rotate.axis.z);
- if (gfx::DotProduct(axis, other_axis) < 0.f)
- to_angle *= -1.f;
- }
-
- float min_degrees =
- SkScalarToFloat(BlendSkScalars(from_angle, to_angle, min_progress));
- float max_degrees =
- SkScalarToFloat(BlendSkScalars(from_angle, to_angle, max_progress));
- if (max_degrees < min_degrees)
- std::swap(min_degrees, max_degrees);
-
- gfx::Transform from_transform;
- from_transform.RotateAbout(axis, min_degrees);
- gfx::Transform to_transform;
- to_transform.RotateAbout(axis, max_degrees);
-
- *box = gfx::BoxF();
-
- gfx::Point3F point_rotated_from = point;
- from_transform.TransformPoint(&point_rotated_from);
- gfx::Point3F point_rotated_to = point;
- to_transform.TransformPoint(&point_rotated_to);
-
- box->set_origin(point_rotated_from);
- box->ExpandTo(point_rotated_to);
-
- if (x_is_zero && y_is_zero) {
- FindCandidatesInPlane(
- point.x(), point.y(), axis.z(), candidates, &num_candidates);
- } else if (x_is_zero && z_is_zero) {
- FindCandidatesInPlane(
- point.z(), point.x(), axis.y(), candidates, &num_candidates);
- } else if (y_is_zero && z_is_zero) {
- FindCandidatesInPlane(
- point.y(), point.z(), axis.x(), candidates, &num_candidates);
- } else {
- gfx::Vector3dF normal = axis;
- normal.Scale(1.f / normal.Length());
-
- // First, find center of rotation.
- gfx::Point3F origin;
- gfx::Vector3dF to_point = point - origin;
- gfx::Point3F center =
- origin + gfx::ScaleVector3d(normal, gfx::DotProduct(to_point, normal));
-
- // Now we need to find two vectors in the plane of rotation. One pointing
- // towards point and another, perpendicular vector in the plane.
- gfx::Vector3dF v1 = point - center;
- float v1_length = v1.Length();
- if (v1_length == 0.f)
- return;
-
- v1.Scale(1.f / v1_length);
- gfx::Vector3dF v2 = gfx::CrossProduct(normal, v1);
- // v1 is the basis vector in the direction of the point.
- // i.e. with a rotation of 0, v1 is our +x vector.
- // v2 is a perpenticular basis vector of our plane (+y).
-
- // Take the parametric equation of a circle.
- // x = r*cos(t); y = r*sin(t);
- // We can treat that as a circle on the plane v1xv2.
- // From that we get the parametric equations for a circle on the
- // plane in 3d space of:
- // x(t) = r*cos(t)*v1.x + r*sin(t)*v2.x + cx
- // y(t) = r*cos(t)*v1.y + r*sin(t)*v2.y + cy
- // z(t) = r*cos(t)*v1.z + r*sin(t)*v2.z + cz
- // Taking the derivative of (x, y, z) and solving for 0 gives us our
- // maximum/minimum x, y, z values.
- // x'(t) = r*cos(t)*v2.x - r*sin(t)*v1.x = 0
- // tan(t) = v2.x/v1.x
- // t = atan2(v2.x, v1.x) + n*pi;
- candidates[0] = atan2(v2.x(), v1.x());
- candidates[1] = candidates[0] + base::kPiDouble;
- candidates[2] = atan2(v2.y(), v1.y());
- candidates[3] = candidates[2] + base::kPiDouble;
- candidates[4] = atan2(v2.z(), v1.z());
- candidates[5] = candidates[4] + base::kPiDouble;
- }
-
- double min_radians = gfx::DegToRad(min_degrees);
- double max_radians = gfx::DegToRad(max_degrees);
-
- for (int i = 0; i < num_candidates; ++i) {
- double radians = candidates[i];
- while (radians < min_radians)
- radians += 2.0 * base::kPiDouble;
- while (radians > max_radians)
- radians -= 2.0 * base::kPiDouble;
- if (radians < min_radians)
- continue;
-
- gfx::Transform rotation;
- rotation.RotateAbout(axis, gfx::RadToDeg(radians));
- gfx::Point3F rotated = point;
- rotation.TransformPoint(&rotated);
-
- box->ExpandTo(rotated);
- }
-}
-
-bool TransformOperation::BlendedBoundsForBox(const gfx::BoxF& box,
- const TransformOperation* from,
- const TransformOperation* to,
- SkScalar min_progress,
- SkScalar max_progress,
- gfx::BoxF* bounds) {
- bool is_identity_from = IsOperationIdentity(from);
- bool is_identity_to = IsOperationIdentity(to);
- if (is_identity_from && is_identity_to) {
- *bounds = box;
- return true;
- }
-
- TransformOperation::Type interpolation_type =
- TransformOperation::TRANSFORM_OPERATION_IDENTITY;
- if (is_identity_to)
- interpolation_type = from->type;
- else
- interpolation_type = to->type;
-
- switch (interpolation_type) {
- case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
- *bounds = box;
- return true;
- case TransformOperation::TRANSFORM_OPERATION_TRANSLATE:
- case TransformOperation::TRANSFORM_OPERATION_SKEWX:
- case TransformOperation::TRANSFORM_OPERATION_SKEWY:
- case TransformOperation::TRANSFORM_OPERATION_SKEW:
- case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE:
- case TransformOperation::TRANSFORM_OPERATION_SCALE: {
- TransformOperation from_operation;
- TransformOperation to_operation;
- if (!BlendTransformOperations(from, to, min_progress, &from_operation) ||
- !BlendTransformOperations(from, to, max_progress, &to_operation))
- return false;
-
- *bounds = box;
- from_operation.matrix.TransformBox(bounds);
-
- gfx::BoxF to_box = box;
- to_operation.matrix.TransformBox(&to_box);
- bounds->ExpandTo(to_box);
-
- return true;
- }
- case TransformOperation::TRANSFORM_OPERATION_ROTATE: {
- SkScalar axis_x = 0;
- SkScalar axis_y = 0;
- SkScalar axis_z = 1;
- SkScalar from_angle = 0;
- if (!ShareSameAxis(from, to, &axis_x, &axis_y, &axis_z, &from_angle))
- return false;
-
- bool first_point = true;
- for (int i = 0; i < 8; ++i) {
- gfx::Point3F corner = box.origin();
- corner += gfx::Vector3dF(i & 1 ? box.width() : 0.f,
- i & 2 ? box.height() : 0.f,
- i & 4 ? box.depth() : 0.f);
- gfx::BoxF box_for_arc;
- BoundingBoxForArc(
- corner, from, to, min_progress, max_progress, &box_for_arc);
- if (first_point)
- *bounds = box_for_arc;
- else
- bounds->Union(box_for_arc);
- first_point = false;
- }
- return true;
- }
- case TransformOperation::TRANSFORM_OPERATION_MATRIX:
- return false;
- }
- NOTREACHED();
- return false;
-}
-
-} // namespace cc
diff --git a/chromium/cc/animation/transform_operation.h b/chromium/cc/animation/transform_operation.h
deleted file mode 100644
index b09accd6320..00000000000
--- a/chromium/cc/animation/transform_operation.h
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2013 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_ANIMATION_TRANSFORM_OPERATION_H_
-#define CC_ANIMATION_TRANSFORM_OPERATION_H_
-
-#include "cc/animation/animation_export.h"
-#include "ui/gfx/transform.h"
-
-namespace gfx {
-class BoxF;
-}
-
-namespace cc {
-
-struct CC_ANIMATION_EXPORT TransformOperation {
- enum Type {
- TRANSFORM_OPERATION_TRANSLATE,
- TRANSFORM_OPERATION_ROTATE,
- TRANSFORM_OPERATION_SCALE,
- TRANSFORM_OPERATION_SKEWX,
- TRANSFORM_OPERATION_SKEWY,
- TRANSFORM_OPERATION_SKEW,
- TRANSFORM_OPERATION_PERSPECTIVE,
- TRANSFORM_OPERATION_MATRIX,
- TRANSFORM_OPERATION_IDENTITY
- };
-
- TransformOperation() : type(TRANSFORM_OPERATION_IDENTITY) {}
-
- Type type;
- gfx::Transform matrix;
-
- union {
- SkScalar perspective_depth;
-
- struct {
- SkScalar x, y;
- } skew;
-
- struct {
- SkScalar x, y, z;
- } scale;
-
- struct {
- SkScalar x, y, z;
- } translate;
-
- struct {
- struct {
- SkScalar x, y, z;
- } axis;
-
- SkScalar angle;
- } rotate;
- };
-
- bool IsIdentity() const;
-
- // Sets |matrix| based on type and the union values.
- void Bake();
-
- bool ApproximatelyEqual(const TransformOperation& other,
- SkScalar tolerance) const;
-
- static bool BlendTransformOperations(const TransformOperation* from,
- const TransformOperation* to,
- SkScalar progress,
- TransformOperation* result);
-
- static bool BlendedBoundsForBox(const gfx::BoxF& box,
- const TransformOperation* from,
- const TransformOperation* to,
- SkScalar min_progress,
- SkScalar max_progress,
- gfx::BoxF* bounds);
-};
-
-} // namespace cc
-
-#endif // CC_ANIMATION_TRANSFORM_OPERATION_H_
diff --git a/chromium/cc/animation/transform_operations.cc b/chromium/cc/animation/transform_operations.cc
deleted file mode 100644
index 2f627f5af10..00000000000
--- a/chromium/cc/animation/transform_operations.cc
+++ /dev/null
@@ -1,387 +0,0 @@
-// Copyright 2013 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/animation/transform_operations.h"
-
-#include <stddef.h>
-
-#include <algorithm>
-#include <utility>
-
-#include "cc/base/math_util.h"
-#include "ui/gfx/animation/tween.h"
-#include "ui/gfx/geometry/angle_conversions.h"
-#include "ui/gfx/geometry/box_f.h"
-#include "ui/gfx/geometry/vector3d_f.h"
-#include "ui/gfx/transform_util.h"
-
-namespace cc {
-
-TransformOperations::TransformOperations() {}
-
-TransformOperations::TransformOperations(const TransformOperations& other) {
- operations_ = other.operations_;
-}
-
-TransformOperations::~TransformOperations() = default;
-
-TransformOperations& TransformOperations::operator=(
- const TransformOperations& other) {
- operations_ = other.operations_;
- return *this;
-}
-
-gfx::Transform TransformOperations::Apply() const {
- return ApplyRemaining(0);
-}
-
-gfx::Transform TransformOperations::ApplyRemaining(size_t start) const {
- gfx::Transform to_return;
- for (size_t i = start; i < operations_.size(); i++) {
- to_return.PreconcatTransform(operations_[i].matrix);
- }
- return to_return;
-}
-
-// TODO(crbug.com/914397): Consolidate blink and cc implementations of transform
-// interpolation.
-TransformOperations TransformOperations::Blend(const TransformOperations& from,
- SkScalar progress) const {
- TransformOperations to_return;
- if (!BlendInternal(from, progress, &to_return)) {
- // If the matrices cannot be blended, fallback to discrete animation logic.
- // See https://drafts.csswg.org/css-transforms/#matrix-interpolation
- to_return = progress < 0.5 ? from : *this;
- }
- return to_return;
-}
-
-bool TransformOperations::BlendedBoundsForBox(const gfx::BoxF& box,
- const TransformOperations& from,
- SkScalar min_progress,
- SkScalar max_progress,
- gfx::BoxF* bounds) const {
- *bounds = box;
-
- bool from_identity = from.IsIdentity();
- bool to_identity = IsIdentity();
- if (from_identity && to_identity)
- return true;
-
- if (!MatchesTypes(from))
- return false;
-
- size_t num_operations = std::max(from_identity ? 0 : from.operations_.size(),
- to_identity ? 0 : operations_.size());
-
- // Because we are squashing all of the matrices together when applying
- // them to the animation, we must apply them in reverse order when
- // not squashing them.
- for (size_t i = 0; i < num_operations; ++i) {
- size_t operation_index = num_operations - 1 - i;
- gfx::BoxF bounds_for_operation;
- const TransformOperation* from_op =
- from_identity ? nullptr : &from.operations_[operation_index];
- const TransformOperation* to_op =
- to_identity ? nullptr : &operations_[operation_index];
- if (!TransformOperation::BlendedBoundsForBox(*bounds, from_op, to_op,
- min_progress, max_progress,
- &bounds_for_operation)) {
- return false;
- }
- *bounds = bounds_for_operation;
- }
-
- return true;
-}
-
-bool TransformOperations::PreservesAxisAlignment() const {
- for (auto& operation : operations_) {
- switch (operation.type) {
- case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
- case TransformOperation::TRANSFORM_OPERATION_TRANSLATE:
- case TransformOperation::TRANSFORM_OPERATION_SCALE:
- continue;
- case TransformOperation::TRANSFORM_OPERATION_MATRIX:
- if (!operation.matrix.IsIdentity() &&
- !operation.matrix.IsScaleOrTranslation())
- return false;
- continue;
- case TransformOperation::TRANSFORM_OPERATION_ROTATE:
- case TransformOperation::TRANSFORM_OPERATION_SKEWX:
- case TransformOperation::TRANSFORM_OPERATION_SKEWY:
- case TransformOperation::TRANSFORM_OPERATION_SKEW:
- case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE:
- return false;
- }
- }
- return true;
-}
-
-bool TransformOperations::IsTranslation() const {
- for (auto& operation : operations_) {
- switch (operation.type) {
- case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
- case TransformOperation::TRANSFORM_OPERATION_TRANSLATE:
- continue;
- case TransformOperation::TRANSFORM_OPERATION_MATRIX:
- if (!operation.matrix.IsIdentityOrTranslation())
- return false;
- continue;
- case TransformOperation::TRANSFORM_OPERATION_ROTATE:
- case TransformOperation::TRANSFORM_OPERATION_SCALE:
- case TransformOperation::TRANSFORM_OPERATION_SKEWX:
- case TransformOperation::TRANSFORM_OPERATION_SKEWY:
- case TransformOperation::TRANSFORM_OPERATION_SKEW:
- case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE:
- return false;
- }
- }
- return true;
-}
-
-static SkScalar TanDegrees(double degrees) {
- return SkDoubleToScalar(std::tan(gfx::DegToRad(degrees)));
-}
-
-bool TransformOperations::ScaleComponent(SkScalar* scale) const {
- SkScalar operations_scale = 1.f;
- for (auto& operation : operations_) {
- switch (operation.type) {
- case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
- case TransformOperation::TRANSFORM_OPERATION_TRANSLATE:
- case TransformOperation::TRANSFORM_OPERATION_ROTATE:
- continue;
- case TransformOperation::TRANSFORM_OPERATION_MATRIX: {
- if (operation.matrix.HasPerspective())
- return false;
- gfx::Vector2dF scale_components =
- MathUtil::ComputeTransform2dScaleComponents(operation.matrix, 1.f);
- operations_scale *=
- std::max(scale_components.x(), scale_components.y());
- break;
- }
- case TransformOperation::TRANSFORM_OPERATION_SKEWX:
- case TransformOperation::TRANSFORM_OPERATION_SKEWY:
- case TransformOperation::TRANSFORM_OPERATION_SKEW: {
- SkScalar x_component = TanDegrees(operation.skew.x);
- SkScalar y_component = TanDegrees(operation.skew.y);
- SkScalar x_scale = std::sqrt(x_component * x_component + 1);
- SkScalar y_scale = std::sqrt(y_component * y_component + 1);
- operations_scale *= std::max(x_scale, y_scale);
- break;
- }
- case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE:
- return false;
- case TransformOperation::TRANSFORM_OPERATION_SCALE:
- operations_scale *= std::max(
- std::abs(operation.scale.x),
- std::max(std::abs(operation.scale.y), std::abs(operation.scale.z)));
- }
- }
- *scale = operations_scale;
- return true;
-}
-
-bool TransformOperations::MatchesTypes(const TransformOperations& other) const {
- if (operations_.size() == 0 || other.operations_.size() == 0)
- return true;
-
- if (operations_.size() != other.operations_.size())
- return false;
-
- for (size_t i = 0; i < operations_.size(); ++i) {
- if (operations_[i].type != other.operations_[i].type)
- return false;
- }
-
- return true;
-}
-
-size_t TransformOperations::MatchingPrefixLength(
- const TransformOperations& other) const {
- size_t num_operations =
- std::min(operations_.size(), other.operations_.size());
- for (size_t i = 0; i < num_operations; ++i) {
- if (operations_[i].type != other.operations_[i].type) {
- // Remaining operations in each operations list require matrix/matrix3d
- // interpolation.
- return i;
- }
- }
- // If the operations match to the length of the shorter list, then pad its
- // length with the matching identity operations.
- // https://drafts.csswg.org/css-transforms/#transform-function-lists
- return std::max(operations_.size(), other.operations_.size());
-}
-
-bool TransformOperations::CanBlendWith(
- const TransformOperations& other) const {
- TransformOperations dummy;
- return BlendInternal(other, 0.5, &dummy);
-}
-
-void TransformOperations::AppendTranslate(SkScalar x, SkScalar y, SkScalar z) {
- TransformOperation to_add;
- to_add.matrix.Translate3d(x, y, z);
- to_add.type = TransformOperation::TRANSFORM_OPERATION_TRANSLATE;
- to_add.translate.x = x;
- to_add.translate.y = y;
- to_add.translate.z = z;
- operations_.push_back(to_add);
- decomposed_transforms_.clear();
-}
-
-void TransformOperations::AppendRotate(SkScalar x,
- SkScalar y,
- SkScalar z,
- SkScalar degrees) {
- TransformOperation to_add;
- to_add.type = TransformOperation::TRANSFORM_OPERATION_ROTATE;
- to_add.rotate.axis.x = x;
- to_add.rotate.axis.y = y;
- to_add.rotate.axis.z = z;
- to_add.rotate.angle = degrees;
- to_add.Bake();
- operations_.push_back(to_add);
- decomposed_transforms_.clear();
-}
-
-void TransformOperations::AppendScale(SkScalar x, SkScalar y, SkScalar z) {
- TransformOperation to_add;
- to_add.type = TransformOperation::TRANSFORM_OPERATION_SCALE;
- to_add.scale.x = x;
- to_add.scale.y = y;
- to_add.scale.z = z;
- to_add.Bake();
- operations_.push_back(to_add);
- decomposed_transforms_.clear();
-}
-
-void TransformOperations::AppendSkewX(SkScalar x) {
- TransformOperation to_add;
- to_add.type = TransformOperation::TRANSFORM_OPERATION_SKEWX;
- to_add.skew.x = x;
- to_add.skew.y = 0;
- to_add.Bake();
- operations_.push_back(to_add);
- decomposed_transforms_.clear();
-}
-
-void TransformOperations::AppendSkewY(SkScalar y) {
- TransformOperation to_add;
- to_add.type = TransformOperation::TRANSFORM_OPERATION_SKEWY;
- to_add.skew.x = 0;
- to_add.skew.y = y;
- to_add.Bake();
- operations_.push_back(to_add);
- decomposed_transforms_.clear();
-}
-
-void TransformOperations::AppendSkew(SkScalar x, SkScalar y) {
- TransformOperation to_add;
- to_add.type = TransformOperation::TRANSFORM_OPERATION_SKEW;
- to_add.skew.x = x;
- to_add.skew.y = y;
- to_add.Bake();
- operations_.push_back(to_add);
- decomposed_transforms_.clear();
-}
-
-void TransformOperations::AppendPerspective(SkScalar depth) {
- TransformOperation to_add;
- to_add.type = TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE;
- to_add.perspective_depth = depth;
- to_add.Bake();
- operations_.push_back(to_add);
- decomposed_transforms_.clear();
-}
-
-void TransformOperations::AppendMatrix(const gfx::Transform& matrix) {
- TransformOperation to_add;
- to_add.matrix = matrix;
- to_add.type = TransformOperation::TRANSFORM_OPERATION_MATRIX;
- operations_.push_back(to_add);
- decomposed_transforms_.clear();
-}
-
-void TransformOperations::AppendIdentity() {
- operations_.push_back(TransformOperation());
-}
-
-void TransformOperations::Append(const TransformOperation& operation) {
- operations_.push_back(operation);
- decomposed_transforms_.clear();
-}
-
-bool TransformOperations::IsIdentity() const {
- for (auto& operation : operations_) {
- if (!operation.IsIdentity())
- return false;
- }
- return true;
-}
-
-bool TransformOperations::ApproximatelyEqual(const TransformOperations& other,
- SkScalar tolerance) const {
- if (size() != other.size())
- return false;
- for (size_t i = 0; i < operations_.size(); ++i) {
- if (!operations_[i].ApproximatelyEqual(other.operations_[i], tolerance))
- return false;
- }
- return true;
-}
-
-bool TransformOperations::BlendInternal(const TransformOperations& from,
- SkScalar progress,
- TransformOperations* result) const {
- bool from_identity = from.IsIdentity();
- bool to_identity = IsIdentity();
- if (from_identity && to_identity)
- return true;
-
- size_t matching_prefix_length = MatchingPrefixLength(from);
- size_t from_size = from_identity ? 0 : from.operations_.size();
- size_t to_size = to_identity ? 0 : operations_.size();
- size_t num_operations = std::max(from_size, to_size);
-
- for (size_t i = 0; i < matching_prefix_length; ++i) {
- TransformOperation blended;
- if (!TransformOperation::BlendTransformOperations(
- i >= from_size ? nullptr : &from.operations_[i],
- i >= to_size ? nullptr : &operations_[i], progress, &blended)) {
- return false;
- }
- result->Append(blended);
- }
-
- if (matching_prefix_length < num_operations) {
- if (!ComputeDecomposedTransform(matching_prefix_length) ||
- !from.ComputeDecomposedTransform(matching_prefix_length)) {
- return false;
- }
- gfx::DecomposedTransform matrix_transform = gfx::BlendDecomposedTransforms(
- *decomposed_transforms_[matching_prefix_length].get(),
- *from.decomposed_transforms_[matching_prefix_length].get(), progress);
- result->AppendMatrix(ComposeTransform(matrix_transform));
- }
- return true;
-}
-
-bool TransformOperations::ComputeDecomposedTransform(
- size_t start_offset) const {
- auto it = decomposed_transforms_.find(start_offset);
- if (it == decomposed_transforms_.end()) {
- std::unique_ptr<gfx::DecomposedTransform> decomposed_transform =
- std::make_unique<gfx::DecomposedTransform>();
- gfx::Transform transform = ApplyRemaining(start_offset);
- if (!gfx::DecomposeTransform(decomposed_transform.get(), transform))
- return false;
- decomposed_transforms_[start_offset] = std::move(decomposed_transform);
- }
- return true;
-}
-
-} // namespace cc
diff --git a/chromium/cc/animation/transform_operations.h b/chromium/cc/animation/transform_operations.h
deleted file mode 100644
index 31d50342f45..00000000000
--- a/chromium/cc/animation/transform_operations.h
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright 2013 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_ANIMATION_TRANSFORM_OPERATIONS_H_
-#define CC_ANIMATION_TRANSFORM_OPERATIONS_H_
-
-#include <memory>
-#include <unordered_map>
-#include <vector>
-
-#include "base/check_op.h"
-#include "base/gtest_prod_util.h"
-#include "cc/animation/animation_export.h"
-#include "cc/animation/transform_operation.h"
-#include "ui/gfx/transform.h"
-
-namespace gfx {
-class BoxF;
-struct DecomposedTransform;
-}
-
-namespace cc {
-
-// Transform operations are a decomposed transformation matrix. It can be
-// applied to obtain a gfx::Transform at any time, and can be blended
-// intelligently with other transform operations, so long as they represent the
-// same decomposition. For example, if we have a transform that is made up of
-// a rotation followed by skew, it can be blended intelligently with another
-// transform made up of a rotation followed by a skew. Blending is possible if
-// we have two dissimilar sets of transform operations, but the effect may not
-// be what was intended. For more information, see the comments for the blend
-// function below.
-class CC_ANIMATION_EXPORT TransformOperations {
- public:
- TransformOperations();
- TransformOperations(const TransformOperations& other);
- ~TransformOperations();
-
- TransformOperations& operator=(const TransformOperations& other);
-
- // Returns a transformation matrix representing these transform operations.
- gfx::Transform Apply() const;
-
- // Returns a transformation matrix representing the set of transform
- // operations from index |start| to the end of the list.
- gfx::Transform ApplyRemaining(size_t start) const;
-
- // Given another set of transform operations and a progress in the range
- // [0, 1], returns a transformation matrix representing the intermediate
- // value. If this->MatchesTypes(from), then each of the operations are
- // blended separately and then combined. Otherwise, the two sets of
- // transforms are baked to matrices (using apply), and the matrices are
- // then decomposed and interpolated. For more information, see
- // http://www.w3.org/TR/2011/WD-css3-2d-transforms-20111215/#matrix-decomposition.
- //
- // If either of the matrices are non-decomposable for the blend, Blend applies
- // discrete interpolation between them based on the progress value.
- TransformOperations Blend(const TransformOperations& from,
- SkScalar progress) const;
-
- // Sets |bounds| be the bounding box for the region within which |box| will
- // exist when it is transformed by the result of calling Blend on |from| and
- // with progress in the range [min_progress, max_progress]. If this region
- // cannot be computed, returns false.
- bool BlendedBoundsForBox(const gfx::BoxF& box,
- const TransformOperations& from,
- SkScalar min_progress,
- SkScalar max_progress,
- gfx::BoxF* bounds) const;
-
- // Returns true if these operations are only translations.
- bool IsTranslation() const;
-
- // Returns false if the operations affect 2d axis alignment.
- bool PreservesAxisAlignment() const;
-
- // Returns true if this operation and its descendants have the same types
- // as other and its descendants.
- bool MatchesTypes(const TransformOperations& other) const;
-
- // Returns the number of matching transform operations at the start of the
- // transform lists. If one list is shorter but pairwise compatible, it will be
- // extended with matching identity operators per spec
- // (https://drafts.csswg.org/css-transforms/#interpolation-of-transforms).
- size_t MatchingPrefixLength(const TransformOperations& other) const;
-
- // Returns true if these operations can be blended. It will only return
- // false if we must resort to matrix interpolation, and matrix interpolation
- // fails (this can happen if either matrix cannot be decomposed).
- bool CanBlendWith(const TransformOperations& other) const;
-
- // If none of these operations have a perspective component, sets |scale| to
- // be the product of the scale component of every operation. Otherwise,
- // returns false.
- bool ScaleComponent(SkScalar* scale) const;
-
- void AppendTranslate(SkScalar x, SkScalar y, SkScalar z);
- void AppendRotate(SkScalar x, SkScalar y, SkScalar z, SkScalar degrees);
- void AppendScale(SkScalar x, SkScalar y, SkScalar z);
- void AppendSkewX(SkScalar x);
- void AppendSkewY(SkScalar y);
- void AppendSkew(SkScalar x, SkScalar y);
- void AppendPerspective(SkScalar depth);
- void AppendMatrix(const gfx::Transform& matrix);
- void AppendIdentity();
- void Append(const TransformOperation& operation);
- bool IsIdentity() const;
-
- size_t size() const { return operations_.size(); }
-
- const TransformOperation& at(size_t index) const {
- DCHECK_LT(index, size());
- return operations_[index];
- }
- TransformOperation& at(size_t index) {
- DCHECK_LT(index, size());
- return operations_[index];
- }
-
- bool ApproximatelyEqual(const TransformOperations& other,
- SkScalar tolerance) const;
-
- private:
- FRIEND_TEST_ALL_PREFIXES(TransformOperationsTest, TestDecompositionCache);
-
- bool BlendInternal(const TransformOperations& from,
- SkScalar progress,
- TransformOperations* result) const;
-
- std::vector<TransformOperation> operations_;
-
- bool ComputeDecomposedTransform(size_t start_offset) const;
-
- // For efficiency, we cache the decomposed transforms.
- mutable std::unordered_map<size_t, std::unique_ptr<gfx::DecomposedTransform>>
- decomposed_transforms_;
-};
-
-} // namespace cc
-
-#endif // CC_ANIMATION_TRANSFORM_OPERATIONS_H_
diff --git a/chromium/cc/animation/transform_operations_unittest.cc b/chromium/cc/animation/transform_operations_unittest.cc
deleted file mode 100644
index bdebd3c4be7..00000000000
--- a/chromium/cc/animation/transform_operations_unittest.cc
+++ /dev/null
@@ -1,1831 +0,0 @@
-// Copyright 2013 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/animation/transform_operations.h"
-
-#include <stddef.h>
-
-#include <limits>
-#include <utility>
-#include <vector>
-
-#include "base/stl_util.h"
-#include "cc/test/geometry_test_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/animation/tween.h"
-#include "ui/gfx/geometry/box_f.h"
-#include "ui/gfx/geometry/rect_conversions.h"
-#include "ui/gfx/geometry/vector3d_f.h"
-
-namespace cc {
-namespace {
-
-void ExpectTransformOperationEqual(const TransformOperation& lhs,
- const TransformOperation& rhs) {
- EXPECT_EQ(lhs.type, rhs.type);
- EXPECT_TRANSFORMATION_MATRIX_EQ(lhs.matrix, rhs.matrix);
- switch (lhs.type) {
- case TransformOperation::TRANSFORM_OPERATION_TRANSLATE:
- EXPECT_FLOAT_EQ(lhs.translate.x, rhs.translate.x);
- EXPECT_FLOAT_EQ(lhs.translate.y, rhs.translate.y);
- EXPECT_FLOAT_EQ(lhs.translate.z, rhs.translate.z);
- break;
- case TransformOperation::TRANSFORM_OPERATION_ROTATE:
- EXPECT_FLOAT_EQ(lhs.rotate.axis.x, rhs.rotate.axis.x);
- EXPECT_FLOAT_EQ(lhs.rotate.axis.y, rhs.rotate.axis.y);
- EXPECT_FLOAT_EQ(lhs.rotate.axis.z, rhs.rotate.axis.z);
- EXPECT_FLOAT_EQ(lhs.rotate.angle, rhs.rotate.angle);
- break;
- case TransformOperation::TRANSFORM_OPERATION_SCALE:
- EXPECT_FLOAT_EQ(lhs.scale.x, rhs.scale.x);
- EXPECT_FLOAT_EQ(lhs.scale.y, rhs.scale.y);
- EXPECT_FLOAT_EQ(lhs.scale.z, rhs.scale.z);
- break;
- case TransformOperation::TRANSFORM_OPERATION_SKEWX:
- case TransformOperation::TRANSFORM_OPERATION_SKEWY:
- case TransformOperation::TRANSFORM_OPERATION_SKEW:
- EXPECT_FLOAT_EQ(lhs.skew.x, rhs.skew.x);
- EXPECT_FLOAT_EQ(lhs.skew.y, rhs.skew.y);
- break;
- case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE:
- EXPECT_FLOAT_EQ(lhs.perspective_depth, rhs.perspective_depth);
- break;
- case TransformOperation::TRANSFORM_OPERATION_MATRIX:
- case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
- break;
- }
-}
-
-TEST(TransformOperationTest, TransformTypesAreUnique) {
- std::vector<std::unique_ptr<TransformOperations>> transforms;
-
- std::unique_ptr<TransformOperations> to_add(
- std::make_unique<TransformOperations>());
- to_add->AppendTranslate(1, 0, 0);
- transforms.push_back(std::move(to_add));
-
- to_add = std::make_unique<TransformOperations>();
- to_add->AppendRotate(0, 0, 1, 2);
- transforms.push_back(std::move(to_add));
-
- to_add = std::make_unique<TransformOperations>();
- to_add->AppendScale(2, 2, 2);
- transforms.push_back(std::move(to_add));
-
- to_add = std::make_unique<TransformOperations>();
- to_add->AppendSkew(1, 0);
- transforms.push_back(std::move(to_add));
-
- to_add = std::make_unique<TransformOperations>();
- to_add->AppendPerspective(800);
- transforms.push_back(std::move(to_add));
-
- for (size_t i = 0; i < transforms.size(); ++i) {
- for (size_t j = 0; j < transforms.size(); ++j) {
- bool matches_type = transforms[i]->MatchesTypes(*transforms[j]);
- EXPECT_TRUE((i == j && matches_type) || !matches_type);
- }
- }
-}
-
-TEST(TransformOperationTest, MatchingPrefixSameLength) {
- TransformOperations translates;
- translates.AppendTranslate(1, 0, 0);
- translates.AppendTranslate(1, 0, 0);
- translates.AppendTranslate(1, 0, 0);
-
- TransformOperations skews;
- skews.AppendSkew(0, 2);
- skews.AppendSkew(0, 2);
- skews.AppendSkew(0, 2);
-
- TransformOperations translates2;
- translates2.AppendTranslate(0, 2, 0);
- translates2.AppendTranslate(0, 2, 0);
- translates2.AppendTranslate(0, 2, 0);
-
- TransformOperations mixed;
- mixed.AppendTranslate(0, 2, 0);
- mixed.AppendScale(2, 1, 1);
- mixed.AppendSkew(0, 2);
-
- TransformOperations translates3 = translates2;
-
- EXPECT_EQ(0UL, translates.MatchingPrefixLength(skews));
- EXPECT_EQ(3UL, translates.MatchingPrefixLength(translates2));
- EXPECT_EQ(3UL, translates.MatchingPrefixLength(translates3));
- EXPECT_EQ(1UL, translates.MatchingPrefixLength(mixed));
-}
-
-TEST(TransformOperationTest, MatchingPrefixDifferentLength) {
- TransformOperations translates;
- translates.AppendTranslate(1, 0, 0);
- translates.AppendTranslate(1, 0, 0);
- translates.AppendTranslate(1, 0, 0);
-
- TransformOperations skews;
- skews.AppendSkew(2, 0);
- skews.AppendSkew(2, 0);
-
- TransformOperations translates2;
- translates2.AppendTranslate(0, 2, 0);
- translates2.AppendTranslate(0, 2, 0);
-
- TransformOperations none;
-
- EXPECT_EQ(0UL, translates.MatchingPrefixLength(skews));
- // Pad the length of the shorter list provided all previous operation-
- // pairs match per spec
- // (https://drafts.csswg.org/css-transforms/#interpolation-of-transforms).
- EXPECT_EQ(3UL, translates.MatchingPrefixLength(translates2));
- EXPECT_EQ(3UL, translates.MatchingPrefixLength(none));
-}
-
-std::vector<std::unique_ptr<TransformOperations>> GetIdentityOperations() {
- std::vector<std::unique_ptr<TransformOperations>> operations;
- std::unique_ptr<TransformOperations> to_add(
- std::make_unique<TransformOperations>());
- operations.push_back(std::move(to_add));
-
- to_add = std::make_unique<TransformOperations>();
- to_add->AppendTranslate(0, 0, 0);
- operations.push_back(std::move(to_add));
-
- to_add = std::make_unique<TransformOperations>();
- to_add->AppendTranslate(0, 0, 0);
- to_add->AppendTranslate(0, 0, 0);
- operations.push_back(std::move(to_add));
-
- to_add = std::make_unique<TransformOperations>();
- to_add->AppendScale(1, 1, 1);
- operations.push_back(std::move(to_add));
-
- to_add = std::make_unique<TransformOperations>();
- to_add->AppendScale(1, 1, 1);
- to_add->AppendScale(1, 1, 1);
- operations.push_back(std::move(to_add));
-
- to_add = std::make_unique<TransformOperations>();
- to_add->AppendSkew(0, 0);
- operations.push_back(std::move(to_add));
-
- to_add = std::make_unique<TransformOperations>();
- to_add->AppendSkew(0, 0);
- to_add->AppendSkew(0, 0);
- operations.push_back(std::move(to_add));
-
- to_add = std::make_unique<TransformOperations>();
- to_add->AppendRotate(0, 0, 1, 0);
- operations.push_back(std::move(to_add));
-
- to_add = std::make_unique<TransformOperations>();
- to_add->AppendRotate(0, 0, 1, 0);
- to_add->AppendRotate(0, 0, 1, 0);
- operations.push_back(std::move(to_add));
-
- to_add = std::make_unique<TransformOperations>();
- to_add->AppendMatrix(gfx::Transform());
- operations.push_back(std::move(to_add));
-
- to_add = std::make_unique<TransformOperations>();
- to_add->AppendMatrix(gfx::Transform());
- to_add->AppendMatrix(gfx::Transform());
- operations.push_back(std::move(to_add));
-
- return operations;
-}
-
-TEST(TransformOperationTest, MatchingPrefixLengthOrder) {
- TransformOperations mix_order_identity;
- mix_order_identity.AppendTranslate(0, 0, 0);
- mix_order_identity.AppendScale(1, 1, 1);
- mix_order_identity.AppendTranslate(0, 0, 0);
-
- TransformOperations mix_order_one;
- mix_order_one.AppendTranslate(0, 1, 0);
- mix_order_one.AppendScale(2, 1, 3);
- mix_order_one.AppendTranslate(1, 0, 0);
-
- TransformOperations mix_order_two;
- mix_order_two.AppendTranslate(0, 1, 0);
- mix_order_two.AppendTranslate(1, 0, 0);
- mix_order_two.AppendScale(2, 1, 3);
-
- EXPECT_EQ(3UL, mix_order_identity.MatchingPrefixLength(mix_order_one));
- EXPECT_EQ(1UL, mix_order_identity.MatchingPrefixLength(mix_order_two));
- EXPECT_EQ(1UL, mix_order_one.MatchingPrefixLength(mix_order_two));
-}
-
-TEST(TransformOperationTest, NoneAlwaysMatches) {
- std::vector<std::unique_ptr<TransformOperations>> operations =
- GetIdentityOperations();
-
- TransformOperations none_operation;
- for (size_t i = 0; i < operations.size(); ++i)
- EXPECT_EQ(operations[i]->size(),
- operations[i]->MatchingPrefixLength(none_operation));
-}
-
-TEST(TransformOperationTest, ApplyTranslate) {
- SkScalar x = 1;
- SkScalar y = 2;
- SkScalar z = 3;
- TransformOperations operations;
- operations.AppendTranslate(x, y, z);
- gfx::Transform expected;
- expected.Translate3d(x, y, z);
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operations.Apply());
-}
-
-TEST(TransformOperationTest, ApplyRotate) {
- SkScalar x = 1;
- SkScalar y = 2;
- SkScalar z = 3;
- SkScalar degrees = 80;
- TransformOperations operations;
- operations.AppendRotate(x, y, z, degrees);
- gfx::Transform expected;
- expected.RotateAbout(gfx::Vector3dF(x, y, z), degrees);
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operations.Apply());
-}
-
-TEST(TransformOperationTest, ApplyScale) {
- SkScalar x = 1;
- SkScalar y = 2;
- SkScalar z = 3;
- TransformOperations operations;
- operations.AppendScale(x, y, z);
- gfx::Transform expected;
- expected.Scale3d(x, y, z);
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operations.Apply());
-}
-
-TEST(TransformOperationTest, ApplySkew) {
- SkScalar x = 1;
- SkScalar y = 2;
- TransformOperations operations;
- operations.AppendSkew(x, y);
- gfx::Transform expected;
- expected.Skew(x, y);
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operations.Apply());
-}
-
-TEST(TransformOperationTest, ApplyPerspective) {
- SkScalar depth = 800;
- TransformOperations operations;
- operations.AppendPerspective(depth);
- gfx::Transform expected;
- expected.ApplyPerspectiveDepth(depth);
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected, operations.Apply());
-}
-
-TEST(TransformOperationTest, ApplyMatrix) {
- SkScalar dx = 1;
- SkScalar dy = 2;
- SkScalar dz = 3;
- gfx::Transform expected_matrix;
- expected_matrix.Translate3d(dx, dy, dz);
- TransformOperations matrix_transform;
- matrix_transform.AppendMatrix(expected_matrix);
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected_matrix, matrix_transform.Apply());
-}
-
-TEST(TransformOperationTest, ApplyOrder) {
- SkScalar sx = 2;
- SkScalar sy = 4;
- SkScalar sz = 8;
-
- SkScalar dx = 1;
- SkScalar dy = 2;
- SkScalar dz = 3;
-
- TransformOperations operations;
- operations.AppendScale(sx, sy, sz);
- operations.AppendTranslate(dx, dy, dz);
-
- gfx::Transform expected_scale_matrix;
- expected_scale_matrix.Scale3d(sx, sy, sz);
-
- gfx::Transform expected_translate_matrix;
- expected_translate_matrix.Translate3d(dx, dy, dz);
-
- gfx::Transform expected_combined_matrix = expected_scale_matrix;
- expected_combined_matrix.PreconcatTransform(expected_translate_matrix);
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected_combined_matrix, operations.Apply());
-}
-
-TEST(TransformOperationTest, BlendOrder) {
- SkScalar sx1 = 2;
- SkScalar sy1 = 4;
- SkScalar sz1 = 8;
-
- SkScalar dx1 = 1;
- SkScalar dy1 = 2;
- SkScalar dz1 = 3;
-
- SkScalar sx2 = 4;
- SkScalar sy2 = 8;
- SkScalar sz2 = 16;
-
- SkScalar dx2 = 10;
- SkScalar dy2 = 20;
- SkScalar dz2 = 30;
-
- SkScalar sx3 = 2;
- SkScalar sy3 = 1;
- SkScalar sz3 = 1;
-
- TransformOperations operations_from;
- operations_from.AppendScale(sx1, sy1, sz1);
- operations_from.AppendTranslate(dx1, dy1, dz1);
-
- TransformOperations operations_to;
- operations_to.AppendScale(sx2, sy2, sz2);
- operations_to.AppendTranslate(dx2, dy2, dz2);
-
- gfx::Transform scale_from;
- scale_from.Scale3d(sx1, sy1, sz1);
- gfx::Transform translate_from;
- translate_from.Translate3d(dx1, dy1, dz1);
-
- gfx::Transform scale_to;
- scale_to.Scale3d(sx2, sy2, sz2);
- gfx::Transform translate_to;
- translate_to.Translate3d(dx2, dy2, dz2);
-
- SkScalar progress = 0.25f;
-
- TransformOperations operations_expected;
- operations_expected.AppendScale(
- gfx::Tween::FloatValueBetween(progress, sx1, sx2),
- gfx::Tween::FloatValueBetween(progress, sy1, sy2),
- gfx::Tween::FloatValueBetween(progress, sz1, sz2));
-
- operations_expected.AppendTranslate(
- gfx::Tween::FloatValueBetween(progress, dx1, dx2),
- gfx::Tween::FloatValueBetween(progress, dy1, dy2),
- gfx::Tween::FloatValueBetween(progress, dz1, dz2));
-
- gfx::Transform blended_scale = scale_to;
- blended_scale.Blend(scale_from, progress);
-
- gfx::Transform blended_translate = translate_to;
- blended_translate.Blend(translate_from, progress);
-
- gfx::Transform expected = blended_scale;
- expected.PreconcatTransform(blended_translate);
-
- TransformOperations blended = operations_to.Blend(operations_from, progress);
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected, blended.Apply());
- EXPECT_TRANSFORMATION_MATRIX_EQ(operations_expected.Apply(), blended.Apply());
- EXPECT_EQ(operations_expected.size(), blended.size());
- for (size_t i = 0; i < operations_expected.size(); ++i) {
- TransformOperation expected_op = operations_expected.at(i);
- TransformOperation blended_op = blended.at(i);
- SCOPED_TRACE(i);
- ExpectTransformOperationEqual(expected_op, blended_op);
- }
-
- TransformOperations base_operations_expected = operations_expected;
-
- // Create a mismatch in number of operations. Pairwise interpolation is still
- // used when the operations match up to the length of the shorter list.
- operations_to.AppendScale(sx3, sy3, sz3);
-
- gfx::Transform appended_scale;
- appended_scale.Scale3d(sx3, sy3, sz3);
-
- gfx::Transform blended_append_scale = appended_scale;
- blended_append_scale.Blend(gfx::Transform(), progress);
- expected.PreconcatTransform(blended_append_scale);
-
- operations_expected.AppendScale(
- gfx::Tween::FloatValueBetween(progress, 1, sx3),
- gfx::Tween::FloatValueBetween(progress, 1, sy3),
- gfx::Tween::FloatValueBetween(progress, 1, sz3));
-
- blended = operations_to.Blend(operations_from, progress);
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected, blended.Apply());
- EXPECT_TRANSFORMATION_MATRIX_EQ(operations_expected.Apply(), blended.Apply());
- EXPECT_EQ(operations_expected.size(), blended.size());
- for (size_t i = 0; i < operations_expected.size(); ++i) {
- TransformOperation expected_op = operations_expected.at(i);
- TransformOperation blended_op = blended.at(i);
- SCOPED_TRACE(i);
- ExpectTransformOperationEqual(expected_op, blended_op);
- }
-
- // Create a mismatch, forcing matrix interpolation for the last operator pair.
- operations_from.AppendRotate(0, 0, 1, 90);
-
- blended = operations_to.Blend(operations_from, progress);
-
- gfx::Transform transform_from;
- transform_from.RotateAboutZAxis(90);
- gfx::Transform transform_to;
- transform_to.Scale3d(sx3, sy3, sz3);
- gfx::Transform blended_matrix = transform_to;
- blended_matrix.Blend(transform_from, progress);
-
- expected = blended_scale;
- expected.PreconcatTransform(blended_translate);
- expected.PreconcatTransform(blended_matrix);
-
- operations_expected = base_operations_expected;
- operations_expected.AppendMatrix(blended_matrix);
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected, blended.Apply());
- EXPECT_TRANSFORMATION_MATRIX_EQ(operations_expected.Apply(), blended.Apply());
- EXPECT_EQ(operations_expected.size(), blended.size());
- for (size_t i = 0; i < operations_expected.size(); ++i) {
- TransformOperation expected_op = operations_expected.at(i);
- TransformOperation blended_op = blended.at(i);
- SCOPED_TRACE(i);
- ExpectTransformOperationEqual(expected_op, blended_op);
- }
-}
-
-static void CheckProgress(SkScalar progress,
- const gfx::Transform& from_matrix,
- const gfx::Transform& to_matrix,
- const TransformOperations& from_transform,
- const TransformOperations& to_transform) {
- gfx::Transform expected_matrix = to_matrix;
- expected_matrix.Blend(from_matrix, progress);
- EXPECT_TRANSFORMATION_MATRIX_EQ(
- expected_matrix, to_transform.Blend(from_transform, progress).Apply());
-}
-
-TEST(TransformOperationTest, BlendProgress) {
- SkScalar sx = 2;
- SkScalar sy = 4;
- SkScalar sz = 8;
- TransformOperations operations_from;
- operations_from.AppendScale(sx, sy, sz);
-
- gfx::Transform matrix_from;
- matrix_from.Scale3d(sx, sy, sz);
-
- sx = 4;
- sy = 8;
- sz = 16;
- TransformOperations operations_to;
- operations_to.AppendScale(sx, sy, sz);
-
- gfx::Transform matrix_to;
- matrix_to.Scale3d(sx, sy, sz);
-
- CheckProgress(-1, matrix_from, matrix_to, operations_from, operations_to);
- CheckProgress(0, matrix_from, matrix_to, operations_from, operations_to);
- CheckProgress(0.25f, matrix_from, matrix_to, operations_from, operations_to);
- CheckProgress(0.5f, matrix_from, matrix_to, operations_from, operations_to);
- CheckProgress(1, matrix_from, matrix_to, operations_from, operations_to);
- CheckProgress(2, matrix_from, matrix_to, operations_from, operations_to);
-}
-
-TEST(TransformOperationTest, BlendWhenTypesDoNotMatch) {
- SkScalar sx1 = 2;
- SkScalar sy1 = 4;
- SkScalar sz1 = 8;
-
- SkScalar dx1 = 1;
- SkScalar dy1 = 2;
- SkScalar dz1 = 3;
-
- SkScalar sx2 = 4;
- SkScalar sy2 = 8;
- SkScalar sz2 = 16;
-
- SkScalar dx2 = 10;
- SkScalar dy2 = 20;
- SkScalar dz2 = 30;
-
- TransformOperations operations_from;
- operations_from.AppendScale(sx1, sy1, sz1);
- operations_from.AppendTranslate(dx1, dy1, dz1);
-
- TransformOperations operations_to;
- operations_to.AppendTranslate(dx2, dy2, dz2);
- operations_to.AppendScale(sx2, sy2, sz2);
-
- gfx::Transform from;
- from.Scale3d(sx1, sy1, sz1);
- from.Translate3d(dx1, dy1, dz1);
-
- gfx::Transform to;
- to.Translate3d(dx2, dy2, dz2);
- to.Scale3d(sx2, sy2, sz2);
-
- SkScalar progress = 0.25f;
-
- gfx::Transform expected = to;
- expected.Blend(from, progress);
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(
- expected, operations_to.Blend(operations_from, progress).Apply());
-}
-
-TEST(TransformOperationTest, LargeRotationsWithSameAxis) {
- TransformOperations operations_from;
- operations_from.AppendRotate(0, 0, 1, 0);
-
- TransformOperations operations_to;
- operations_to.AppendRotate(0, 0, 2, 360);
-
- SkScalar progress = 0.5f;
-
- gfx::Transform expected;
- expected.RotateAbout(gfx::Vector3dF(0, 0, 1), 180);
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(
- expected, operations_to.Blend(operations_from, progress).Apply());
-}
-
-TEST(TransformOperationTest, LargeRotationsWithSameAxisInDifferentDirection) {
- TransformOperations operations_from;
- operations_from.AppendRotate(0, 0, 1, 180);
-
- TransformOperations operations_to;
- operations_to.AppendRotate(0, 0, -1, 180);
-
- SkScalar progress = 0.5f;
-
- gfx::Transform expected;
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(
- expected, operations_to.Blend(operations_from, progress).Apply());
-}
-
-TEST(TransformOperationTest, LargeRotationsWithDifferentAxes) {
- TransformOperations operations_from;
- operations_from.AppendRotate(0, 0, 1, 175);
-
- TransformOperations operations_to;
- operations_to.AppendRotate(0, 1, 0, 175);
-
- SkScalar progress = 0.5f;
- gfx::Transform matrix_from;
- matrix_from.RotateAbout(gfx::Vector3dF(0, 0, 1), 175);
-
- gfx::Transform matrix_to;
- matrix_to.RotateAbout(gfx::Vector3dF(0, 1, 0), 175);
-
- gfx::Transform expected = matrix_to;
- expected.Blend(matrix_from, progress);
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(
- expected, operations_to.Blend(operations_from, progress).Apply());
-}
-
-TEST(TransformOperationTest, RotationFromZeroDegDifferentAxes) {
- TransformOperations operations_from;
- operations_from.AppendRotate(0, 0, 1, 0);
-
- TransformOperations operations_to;
- operations_to.AppendRotate(0, 1, 0, 450);
-
- SkScalar progress = 0.5f;
- gfx::Transform expected;
- expected.RotateAbout(gfx::Vector3dF(0, 1, 0), 225);
- EXPECT_TRANSFORMATION_MATRIX_EQ(
- expected, operations_to.Blend(operations_from, progress).Apply());
-}
-
-TEST(TransformOperationTest, RotationFromZeroDegSameAxes) {
- TransformOperations operations_from;
- operations_from.AppendRotate(0, 0, 1, 0);
-
- TransformOperations operations_to;
- operations_to.AppendRotate(0, 0, 1, 450);
-
- SkScalar progress = 0.5f;
- gfx::Transform expected;
- expected.RotateAbout(gfx::Vector3dF(0, 0, 1), 225);
- EXPECT_TRANSFORMATION_MATRIX_EQ(
- expected, operations_to.Blend(operations_from, progress).Apply());
-}
-
-TEST(TransformOperationTest, RotationToZeroDegDifferentAxes) {
- TransformOperations operations_from;
- operations_from.AppendRotate(0, 1, 0, 450);
-
- TransformOperations operations_to;
- operations_to.AppendRotate(0, 0, 1, 0);
-
- SkScalar progress = 0.5f;
- gfx::Transform expected;
- expected.RotateAbout(gfx::Vector3dF(0, 1, 0), 225);
- EXPECT_TRANSFORMATION_MATRIX_EQ(
- expected, operations_to.Blend(operations_from, progress).Apply());
-}
-
-TEST(TransformOperationTest, RotationToZeroDegSameAxes) {
- TransformOperations operations_from;
- operations_from.AppendRotate(0, 0, 1, 450);
-
- TransformOperations operations_to;
- operations_to.AppendRotate(0, 0, 1, 0);
-
- SkScalar progress = 0.5f;
- gfx::Transform expected;
- expected.RotateAbout(gfx::Vector3dF(0, 0, 1), 225);
- EXPECT_TRANSFORMATION_MATRIX_EQ(
- expected, operations_to.Blend(operations_from, progress).Apply());
-}
-
-TEST(TransformOperationTest, BlendRotationFromIdentity) {
- std::vector<std::unique_ptr<TransformOperations>> identity_operations =
- GetIdentityOperations();
-
- for (size_t i = 0; i < identity_operations.size(); ++i) {
- TransformOperations operations;
- operations.AppendRotate(0, 0, 1, 90);
-
- SkScalar progress = 0.5f;
-
- gfx::Transform expected;
- expected.RotateAbout(gfx::Vector3dF(0, 0, 1), 45);
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(
- expected, operations.Blend(*identity_operations[i], progress).Apply());
-
- progress = -0.5f;
-
- expected.MakeIdentity();
- expected.RotateAbout(gfx::Vector3dF(0, 0, 1), -45);
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(
- expected, operations.Blend(*identity_operations[i], progress).Apply());
-
- progress = 1.5f;
-
- expected.MakeIdentity();
- expected.RotateAbout(gfx::Vector3dF(0, 0, 1), 135);
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(
- expected, operations.Blend(*identity_operations[i], progress).Apply());
- }
-}
-
-TEST(TransformOperationTest, BlendTranslationFromIdentity) {
- std::vector<std::unique_ptr<TransformOperations>> identity_operations =
- GetIdentityOperations();
-
- for (size_t i = 0; i < identity_operations.size(); ++i) {
- TransformOperations operations;
- operations.AppendTranslate(2, 2, 2);
-
- SkScalar progress = 0.5f;
-
- gfx::Transform expected;
- expected.Translate3d(1, 1, 1);
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(
- expected, operations.Blend(*identity_operations[i], progress).Apply());
-
- progress = -0.5f;
-
- expected.MakeIdentity();
- expected.Translate3d(-1, -1, -1);
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(
- expected, operations.Blend(*identity_operations[i], progress).Apply());
-
- progress = 1.5f;
-
- expected.MakeIdentity();
- expected.Translate3d(3, 3, 3);
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(
- expected, operations.Blend(*identity_operations[i], progress).Apply());
- }
-}
-
-TEST(TransformOperationTest, BlendScaleFromIdentity) {
- std::vector<std::unique_ptr<TransformOperations>> identity_operations =
- GetIdentityOperations();
-
- for (size_t i = 0; i < identity_operations.size(); ++i) {
- TransformOperations operations;
- operations.AppendScale(3, 3, 3);
-
- SkScalar progress = 0.5f;
-
- gfx::Transform expected;
- expected.Scale3d(2, 2, 2);
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(
- expected, operations.Blend(*identity_operations[i], progress).Apply());
-
- progress = -0.5f;
-
- expected.MakeIdentity();
- expected.Scale3d(0, 0, 0);
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(
- expected, operations.Blend(*identity_operations[i], progress).Apply());
-
- progress = 1.5f;
-
- expected.MakeIdentity();
- expected.Scale3d(4, 4, 4);
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(
- expected, operations.Blend(*identity_operations[i], progress).Apply());
- }
-}
-
-TEST(TransformOperationTest, BlendSkewFromEmpty) {
- TransformOperations empty_operation;
-
- TransformOperations operations;
- operations.AppendSkew(2, 2);
-
- SkScalar progress = 0.5f;
-
- gfx::Transform expected;
- expected.Skew(1, 1);
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(
- expected, operations.Blend(empty_operation, progress).Apply());
-
- progress = -0.5f;
-
- expected.MakeIdentity();
- expected.Skew(-1, -1);
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(
- expected, operations.Blend(empty_operation, progress).Apply());
-
- progress = 1.5f;
-
- expected.MakeIdentity();
- expected.Skew(3, 3);
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(
- expected, operations.Blend(empty_operation, progress).Apply());
-}
-
-TEST(TransformOperationTest, BlendPerspectiveFromIdentity) {
- std::vector<std::unique_ptr<TransformOperations>> identity_operations =
- GetIdentityOperations();
-
- for (size_t i = 0; i < identity_operations.size(); ++i) {
- TransformOperations operations;
- operations.AppendPerspective(1000);
-
- SkScalar progress = 0.5f;
-
- gfx::Transform expected;
- expected.ApplyPerspectiveDepth(2000);
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(
- expected, operations.Blend(*identity_operations[i], progress).Apply());
- }
-}
-
-TEST(TransformOperationTest, BlendRotationToIdentity) {
- std::vector<std::unique_ptr<TransformOperations>> identity_operations =
- GetIdentityOperations();
-
- for (size_t i = 0; i < identity_operations.size(); ++i) {
- TransformOperations operations;
- operations.AppendRotate(0, 0, 1, 90);
-
- SkScalar progress = 0.5f;
-
- gfx::Transform expected;
- expected.RotateAbout(gfx::Vector3dF(0, 0, 1), 45);
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(
- expected, identity_operations[i]->Blend(operations, progress).Apply());
- }
-}
-
-TEST(TransformOperationTest, BlendTranslationToIdentity) {
- std::vector<std::unique_ptr<TransformOperations>> identity_operations =
- GetIdentityOperations();
-
- for (size_t i = 0; i < identity_operations.size(); ++i) {
- TransformOperations operations;
- operations.AppendTranslate(2, 2, 2);
-
- SkScalar progress = 0.5f;
-
- gfx::Transform expected;
- expected.Translate3d(1, 1, 1);
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(
- expected, identity_operations[i]->Blend(operations, progress).Apply());
- }
-}
-
-TEST(TransformOperationTest, BlendScaleToIdentity) {
- std::vector<std::unique_ptr<TransformOperations>> identity_operations =
- GetIdentityOperations();
-
- for (size_t i = 0; i < identity_operations.size(); ++i) {
- TransformOperations operations;
- operations.AppendScale(3, 3, 3);
-
- SkScalar progress = 0.5f;
-
- gfx::Transform expected;
- expected.Scale3d(2, 2, 2);
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(
- expected, identity_operations[i]->Blend(operations, progress).Apply());
- }
-}
-
-TEST(TransformOperationTest, BlendSkewToEmpty) {
- TransformOperations empty_operation;
-
- TransformOperations operations;
- operations.AppendSkew(2, 2);
-
- SkScalar progress = 0.5f;
-
- gfx::Transform expected;
- expected.Skew(1, 1);
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(
- expected, empty_operation.Blend(operations, progress).Apply());
-}
-
-TEST(TransformOperationTest, BlendPerspectiveToIdentity) {
- std::vector<std::unique_ptr<TransformOperations>> identity_operations =
- GetIdentityOperations();
-
- for (size_t i = 0; i < identity_operations.size(); ++i) {
- TransformOperations operations;
- operations.AppendPerspective(1000);
-
- SkScalar progress = 0.5f;
-
- gfx::Transform expected;
- expected.ApplyPerspectiveDepth(2000);
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(
- expected, identity_operations[i]->Blend(operations, progress).Apply());
- }
-}
-
-TEST(TransformOperationTest, ExtrapolatePerspectiveBlending) {
- TransformOperations operations1;
- operations1.AppendPerspective(1000);
-
- TransformOperations operations2;
- operations2.AppendPerspective(500);
-
- gfx::Transform expected;
- expected.ApplyPerspectiveDepth(400);
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected,
- operations1.Blend(operations2, -0.5).Apply());
-
- expected.MakeIdentity();
- expected.ApplyPerspectiveDepth(2000);
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected,
- operations1.Blend(operations2, 1.5).Apply());
-}
-
-TEST(TransformOperationTest, ExtrapolateMatrixBlending) {
- gfx::Transform transform1;
- transform1.Translate3d(1, 1, 1);
- TransformOperations operations1;
- operations1.AppendMatrix(transform1);
-
- gfx::Transform transform2;
- transform2.Translate3d(3, 3, 3);
- TransformOperations operations2;
- operations2.AppendMatrix(transform2);
-
- gfx::Transform expected;
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected,
- operations1.Blend(operations2, 1.5).Apply());
-
- expected.Translate3d(4, 4, 4);
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected,
- operations1.Blend(operations2, -0.5).Apply());
-}
-
-TEST(TransformOperationTest, NonDecomposableBlend) {
- TransformOperations non_decomposible_transform;
- gfx::Transform non_decomposible_matrix(0, 0, 0, 0, 0, 0);
- non_decomposible_transform.AppendMatrix(non_decomposible_matrix);
-
- TransformOperations identity_transform;
- gfx::Transform identity_matrix;
- identity_transform.AppendMatrix(identity_matrix);
-
- // Before the half-way point, we should return the 'from' matrix.
- EXPECT_TRANSFORMATION_MATRIX_EQ(
- non_decomposible_matrix,
- identity_transform.Blend(non_decomposible_transform, 0.0f).Apply());
- EXPECT_TRANSFORMATION_MATRIX_EQ(
- non_decomposible_matrix,
- identity_transform.Blend(non_decomposible_transform, 0.49f).Apply());
-
- // After the half-way point, we should return the 'to' matrix.
- EXPECT_TRANSFORMATION_MATRIX_EQ(
- identity_matrix,
- identity_transform.Blend(non_decomposible_transform, 0.5f).Apply());
- EXPECT_TRANSFORMATION_MATRIX_EQ(
- identity_matrix,
- identity_transform.Blend(non_decomposible_transform, 1.0f).Apply());
-}
-
-TEST(TransformOperationTest, BlendedBoundsWhenTypesDoNotMatch) {
- TransformOperations operations_from;
- operations_from.AppendScale(2.0, 4.0, 8.0);
- operations_from.AppendTranslate(1.0, 2.0, 3.0);
-
- TransformOperations operations_to;
- operations_to.AppendTranslate(10.0, 20.0, 30.0);
- operations_to.AppendScale(4.0, 8.0, 16.0);
-
- gfx::BoxF box(1.f, 1.f, 1.f);
- gfx::BoxF bounds;
-
- SkScalar min_progress = 0.f;
- SkScalar max_progress = 1.f;
-
- EXPECT_FALSE(operations_to.BlendedBoundsForBox(
- box, operations_from, min_progress, max_progress, &bounds));
-}
-
-TEST(TransformOperationTest, BlendedBoundsForIdentity) {
- TransformOperations operations_from;
- operations_from.AppendIdentity();
- TransformOperations operations_to;
- operations_to.AppendIdentity();
-
- gfx::BoxF box(1.f, 2.f, 3.f);
- gfx::BoxF bounds;
-
- SkScalar min_progress = 0.f;
- SkScalar max_progress = 1.f;
-
- EXPECT_TRUE(operations_to.BlendedBoundsForBox(
- box, operations_from, min_progress, max_progress, &bounds));
- EXPECT_EQ(box.ToString(), bounds.ToString());
-}
-
-TEST(TransformOperationTest, BlendedBoundsForTranslate) {
- TransformOperations operations_from;
- operations_from.AppendTranslate(3.0, -4.0, 2.0);
- TransformOperations operations_to;
- operations_to.AppendTranslate(7.0, 4.0, -2.0);
-
- gfx::BoxF box(1.f, 2.f, 3.f, 4.f, 4.f, 4.f);
- gfx::BoxF bounds;
-
- SkScalar min_progress = -0.5f;
- SkScalar max_progress = 1.5f;
- EXPECT_TRUE(operations_to.BlendedBoundsForBox(
- box, operations_from, min_progress, max_progress, &bounds));
- EXPECT_EQ(gfx::BoxF(2.f, -6.f, -1.f, 12.f, 20.f, 12.f).ToString(),
- bounds.ToString());
-
- min_progress = 0.f;
- max_progress = 1.f;
- EXPECT_TRUE(operations_to.BlendedBoundsForBox(
- box, operations_from, min_progress, max_progress, &bounds));
- EXPECT_EQ(gfx::BoxF(4.f, -2.f, 1.f, 8.f, 12.f, 8.f).ToString(),
- bounds.ToString());
-
- TransformOperations identity;
- EXPECT_TRUE(operations_to.BlendedBoundsForBox(
- box, identity, min_progress, max_progress, &bounds));
- EXPECT_EQ(gfx::BoxF(1.f, 2.f, 1.f, 11.f, 8.f, 6.f).ToString(),
- bounds.ToString());
-
- EXPECT_TRUE(identity.BlendedBoundsForBox(
- box, operations_from, min_progress, max_progress, &bounds));
- EXPECT_EQ(gfx::BoxF(1.f, -2.f, 3.f, 7.f, 8.f, 6.f).ToString(),
- bounds.ToString());
-}
-
-TEST(TransformOperationTest, BlendedBoundsForScale) {
- TransformOperations operations_from;
- operations_from.AppendScale(3.0, 0.5, 2.0);
- TransformOperations operations_to;
- operations_to.AppendScale(7.0, 4.0, -2.0);
-
- gfx::BoxF box(1.f, 2.f, 3.f, 4.f, 4.f, 4.f);
- gfx::BoxF bounds;
-
- SkScalar min_progress = -0.5f;
- SkScalar max_progress = 1.5f;
- EXPECT_TRUE(operations_to.BlendedBoundsForBox(
- box, operations_from, min_progress, max_progress, &bounds));
- EXPECT_EQ(gfx::BoxF(1.f, -7.5f, -28.f, 44.f, 42.f, 56.f).ToString(),
- bounds.ToString());
-
- min_progress = 0.f;
- max_progress = 1.f;
- EXPECT_TRUE(operations_to.BlendedBoundsForBox(
- box, operations_from, min_progress, max_progress, &bounds));
- EXPECT_EQ(gfx::BoxF(3.f, 1.f, -14.f, 32.f, 23.f, 28.f).ToString(),
- bounds.ToString());
-
- TransformOperations identity;
- EXPECT_TRUE(operations_to.BlendedBoundsForBox(
- box, identity, min_progress, max_progress, &bounds));
- EXPECT_EQ(gfx::BoxF(1.f, 2.f, -14.f, 34.f, 22.f, 21.f).ToString(),
- bounds.ToString());
-
- EXPECT_TRUE(identity.BlendedBoundsForBox(
- box, operations_from, min_progress, max_progress, &bounds));
- EXPECT_EQ(gfx::BoxF(1.f, 1.f, 3.f, 14.f, 5.f, 11.f).ToString(),
- bounds.ToString());
-}
-
-TEST(TransformOperationTest, BlendedBoundsWithZeroScale) {
- TransformOperations zero_scale;
- zero_scale.AppendScale(0.0, 0.0, 0.0);
- TransformOperations non_zero_scale;
- non_zero_scale.AppendScale(2.0, -4.0, 5.0);
-
- gfx::BoxF box(1.f, 2.f, 3.f, 4.f, 4.f, 4.f);
- gfx::BoxF bounds;
-
- SkScalar min_progress = 0.f;
- SkScalar max_progress = 1.f;
- EXPECT_TRUE(zero_scale.BlendedBoundsForBox(
- box, non_zero_scale, min_progress, max_progress, &bounds));
- EXPECT_EQ(gfx::BoxF(0.f, -24.f, 0.f, 10.f, 24.f, 35.f).ToString(),
- bounds.ToString());
-
- EXPECT_TRUE(non_zero_scale.BlendedBoundsForBox(
- box, zero_scale, min_progress, max_progress, &bounds));
- EXPECT_EQ(gfx::BoxF(0.f, -24.f, 0.f, 10.f, 24.f, 35.f).ToString(),
- bounds.ToString());
-
- EXPECT_TRUE(zero_scale.BlendedBoundsForBox(
- box, zero_scale, min_progress, max_progress, &bounds));
- EXPECT_EQ(gfx::BoxF().ToString(), bounds.ToString());
-}
-
-TEST(TransformOperationTest, BlendedBoundsForRotationTrivial) {
- TransformOperations operations_from;
- operations_from.AppendRotate(0.f, 0.f, 1.f, 0.f);
- TransformOperations operations_to;
- operations_to.AppendRotate(0.f, 0.f, 1.f, 360.f);
-
- float sqrt_2 = sqrt(2.f);
- gfx::BoxF box(
- -sqrt_2, -sqrt_2, 0.f, sqrt_2, sqrt_2, 0.f);
- gfx::BoxF bounds;
-
- // Since we're rotating 360 degrees, any box with dimensions between 0 and
- // 2 * sqrt(2) should give the same result.
- float sizes[] = { 0.f, 0.1f, sqrt_2, 2.f * sqrt_2 };
- for (size_t i = 0; i < base::size(sizes); ++i) {
- box.set_size(sizes[i], sizes[i], 0.f);
- SkScalar min_progress = 0.f;
- SkScalar max_progress = 1.f;
- EXPECT_TRUE(operations_to.BlendedBoundsForBox(
- box, operations_from, min_progress, max_progress, &bounds));
- EXPECT_EQ(gfx::BoxF(-2.f, -2.f, 0.f, 4.f, 4.f, 0.f).ToString(),
- bounds.ToString());
- }
-}
-
-TEST(TransformOperationTest, BlendedBoundsForRotationAllExtrema) {
- // If the normal is out of the plane, we can have up to 6 extrema (a min/max
- // in each dimension) between the endpoints of the arc. This test ensures that
- // we consider all 6.
- TransformOperations operations_from;
- operations_from.AppendRotate(1.f, 1.f, 1.f, 30.f);
- TransformOperations operations_to;
- operations_to.AppendRotate(1.f, 1.f, 1.f, 390.f);
-
- gfx::BoxF box(1.f, 0.f, 0.f, 0.f, 0.f, 0.f);
- gfx::BoxF bounds;
-
- float min = -1.f / 3.f;
- float max = 1.f;
- float size = max - min;
- EXPECT_TRUE(operations_to.BlendedBoundsForBox(
- box, operations_from, 0.f, 1.f, &bounds));
- EXPECT_EQ(gfx::BoxF(min, min, min, size, size, size).ToString(),
- bounds.ToString());
-}
-
-TEST(TransformOperationTest, BlendedBoundsForRotationDifferentAxes) {
- // We can handle rotations about a single axis. If the axes are different,
- // we revert to matrix interpolation for which inflated bounds cannot be
- // computed.
- TransformOperations operations_from;
- operations_from.AppendRotate(1.f, 1.f, 1.f, 30.f);
- TransformOperations operations_to_same;
- operations_to_same.AppendRotate(1.f, 1.f, 1.f, 390.f);
- TransformOperations operations_to_opposite;
- operations_to_opposite.AppendRotate(-1.f, -1.f, -1.f, 390.f);
- TransformOperations operations_to_different;
- operations_to_different.AppendRotate(1.f, 3.f, 1.f, 390.f);
-
- gfx::BoxF box(1.f, 0.f, 0.f, 0.f, 0.f, 0.f);
- gfx::BoxF bounds;
-
- EXPECT_TRUE(operations_to_same.BlendedBoundsForBox(
- box, operations_from, 0.f, 1.f, &bounds));
- EXPECT_TRUE(operations_to_opposite.BlendedBoundsForBox(
- box, operations_from, 0.f, 1.f, &bounds));
- EXPECT_FALSE(operations_to_different.BlendedBoundsForBox(
- box, operations_from, 0.f, 1.f, &bounds));
-}
-
-TEST(TransformOperationTest, BlendedBoundsForRotationPointOnAxis) {
- // Checks that if the point to rotate is sitting on the axis of rotation, that
- // it does not get affected.
- TransformOperations operations_from;
- operations_from.AppendRotate(1.f, 1.f, 1.f, 30.f);
- TransformOperations operations_to;
- operations_to.AppendRotate(1.f, 1.f, 1.f, 390.f);
-
- gfx::BoxF box(1.f, 1.f, 1.f, 0.f, 0.f, 0.f);
- gfx::BoxF bounds;
-
- EXPECT_TRUE(operations_to.BlendedBoundsForBox(
- box, operations_from, 0.f, 1.f, &bounds));
- EXPECT_EQ(box.ToString(), bounds.ToString());
-}
-
-TEST(TransformOperationTest, BlendedBoundsForRotationProblematicAxes) {
- // Zeros in the components of the axis of rotation turned out to be tricky to
- // deal with in practice. This function tests some potentially problematic
- // axes to ensure sane behavior.
-
- // Some common values used in the expected boxes.
- float dim1 = 0.292893f;
- float dim2 = sqrt(2.f);
- float dim3 = 2.f * dim2;
-
- struct {
- float x;
- float y;
- float z;
- gfx::BoxF expected;
- } tests[] = {{0.f, 0.f, 0.f, gfx::BoxF(1.f, 1.f, 1.f, 0.f, 0.f, 0.f)},
- {1.f, 0.f, 0.f, gfx::BoxF(1.f, -dim2, -dim2, 0.f, dim3, dim3)},
- {0.f, 1.f, 0.f, gfx::BoxF(-dim2, 1.f, -dim2, dim3, 0.f, dim3)},
- {0.f, 0.f, 1.f, gfx::BoxF(-dim2, -dim2, 1.f, dim3, dim3, 0.f)},
- {1.f, 1.f, 0.f, gfx::BoxF(dim1, dim1, -1.f, dim2, dim2, 2.f)},
- {0.f, 1.f, 1.f, gfx::BoxF(-1.f, dim1, dim1, 2.f, dim2, dim2)},
- {1.f, 0.f, 1.f, gfx::BoxF(dim1, -1.f, dim1, dim2, 2.f, dim2)}};
-
- for (size_t i = 0; i < base::size(tests); ++i) {
- float x = tests[i].x;
- float y = tests[i].y;
- float z = tests[i].z;
- TransformOperations operations_from;
- operations_from.AppendRotate(x, y, z, 0.f);
- TransformOperations operations_to;
- operations_to.AppendRotate(x, y, z, 360.f);
- gfx::BoxF box(1.f, 1.f, 1.f, 0.f, 0.f, 0.f);
- gfx::BoxF bounds;
-
- EXPECT_TRUE(operations_to.BlendedBoundsForBox(
- box, operations_from, 0.f, 1.f, &bounds));
- EXPECT_EQ(tests[i].expected.ToString(), bounds.ToString());
- }
-}
-
-static void ExpectBoxesApproximatelyEqual(const gfx::BoxF& lhs,
- const gfx::BoxF& rhs,
- float tolerance) {
- EXPECT_NEAR(lhs.x(), rhs.x(), tolerance);
- EXPECT_NEAR(lhs.y(), rhs.y(), tolerance);
- EXPECT_NEAR(lhs.z(), rhs.z(), tolerance);
- EXPECT_NEAR(lhs.width(), rhs.width(), tolerance);
- EXPECT_NEAR(lhs.height(), rhs.height(), tolerance);
- EXPECT_NEAR(lhs.depth(), rhs.depth(), tolerance);
-}
-
-static void EmpiricallyTestBounds(const TransformOperations& from,
- const TransformOperations& to,
- SkScalar min_progress,
- SkScalar max_progress,
- bool test_containment_only) {
- gfx::BoxF box(200.f, 500.f, 100.f, 100.f, 300.f, 200.f);
- gfx::BoxF bounds;
- EXPECT_TRUE(
- to.BlendedBoundsForBox(box, from, min_progress, max_progress, &bounds));
-
- bool first_time = true;
- gfx::BoxF empirical_bounds;
- static const size_t kNumSteps = 10;
- for (size_t step = 0; step < kNumSteps; ++step) {
- float t = step / (kNumSteps - 1.f);
- t = gfx::Tween::FloatValueBetween(t, min_progress, max_progress);
- gfx::Transform partial_transform = to.Blend(from, t).Apply();
- gfx::BoxF transformed = box;
- partial_transform.TransformBox(&transformed);
-
- if (first_time) {
- empirical_bounds = transformed;
- first_time = false;
- } else {
- empirical_bounds.Union(transformed);
- }
- }
-
- if (test_containment_only) {
- gfx::BoxF unified_bounds = bounds;
- unified_bounds.Union(empirical_bounds);
- // Convert to the screen space rects these boxes represent.
- gfx::Rect bounds_rect = ToEnclosingRect(
- gfx::RectF(bounds.x(), bounds.y(), bounds.width(), bounds.height()));
- gfx::Rect unified_bounds_rect =
- ToEnclosingRect(gfx::RectF(unified_bounds.x(),
- unified_bounds.y(),
- unified_bounds.width(),
- unified_bounds.height()));
- EXPECT_EQ(bounds_rect.ToString(), unified_bounds_rect.ToString());
- } else {
- // Our empirical estimate will be a little rough since we're only doing
- // 100 samples.
- static const float kTolerance = 1e-2f;
- ExpectBoxesApproximatelyEqual(empirical_bounds, bounds, kTolerance);
- }
-}
-
-static void EmpiricallyTestBoundsEquality(const TransformOperations& from,
- const TransformOperations& to,
- SkScalar min_progress,
- SkScalar max_progress) {
- EmpiricallyTestBounds(from, to, min_progress, max_progress, false);
-}
-
-static void EmpiricallyTestBoundsContainment(const TransformOperations& from,
- const TransformOperations& to,
- SkScalar min_progress,
- SkScalar max_progress) {
- EmpiricallyTestBounds(from, to, min_progress, max_progress, true);
-}
-
-TEST(TransformOperationTest, BlendedBoundsForRotationEmpiricalTests) {
- // Sets up various axis angle combinations, computes the bounding box and
- // empirically tests that the transformed bounds are indeed contained by the
- // computed bounding box.
-
- struct {
- float x;
- float y;
- float z;
- } axes[] = {{1.f, 1.f, 1.f},
- {-1.f, -1.f, -1.f},
- {-1.f, 2.f, 3.f},
- {1.f, -2.f, 3.f},
- {1.f, 2.f, -3.f},
- {0.f, 0.f, 0.f},
- {1.f, 0.f, 0.f},
- {0.f, 1.f, 0.f},
- {0.f, 0.f, 1.f},
- {1.f, 1.f, 0.f},
- {0.f, 1.f, 1.f},
- {1.f, 0.f, 1.f},
- {-1.f, 0.f, 0.f},
- {0.f, -1.f, 0.f},
- {0.f, 0.f, -1.f},
- {-1.f, -1.f, 0.f},
- {0.f, -1.f, -1.f},
- {-1.f, 0.f, -1.f}};
-
- struct {
- float theta_from;
- float theta_to;
- } angles[] = {{5.f, 10.f},
- {10.f, 5.f},
- {0.f, 360.f},
- {20.f, 180.f},
- {-20.f, -180.f},
- {180.f, -220.f},
- {220.f, 320.f}};
-
- // We can go beyond the range [0, 1] (the bezier might slide out of this range
- // at either end), but since the first and last knots are at (0, 0) and (1, 1)
- // we will never go within it, so these tests are sufficient.
- struct {
- float min_progress;
- float max_progress;
- } progress[] = {
- {0.f, 1.f}, {-.25f, 1.25f},
- };
-
- for (size_t i = 0; i < base::size(axes); ++i) {
- for (size_t j = 0; j < base::size(angles); ++j) {
- for (size_t k = 0; k < base::size(progress); ++k) {
- float x = axes[i].x;
- float y = axes[i].y;
- float z = axes[i].z;
- TransformOperations operations_from;
- operations_from.AppendRotate(x, y, z, angles[j].theta_from);
- TransformOperations operations_to;
- operations_to.AppendRotate(x, y, z, angles[j].theta_to);
- EmpiricallyTestBoundsContainment(operations_from,
- operations_to,
- progress[k].min_progress,
- progress[k].max_progress);
- }
- }
- }
-}
-
-TEST(TransformOperationTest, PerspectiveMatrixAndTransformBlendingEquivalency) {
- TransformOperations from_operations;
- from_operations.AppendPerspective(200);
-
- TransformOperations to_operations;
- to_operations.AppendPerspective(1000);
-
- gfx::Transform from_transform;
- from_transform.ApplyPerspectiveDepth(200);
-
- gfx::Transform to_transform;
- to_transform.ApplyPerspectiveDepth(1000);
-
- static const int steps = 20;
- for (int i = 0; i < steps; ++i) {
- double progress = static_cast<double>(i) / (steps - 1);
-
- gfx::Transform blended_matrix = to_transform;
- EXPECT_TRUE(blended_matrix.Blend(from_transform, progress));
-
- gfx::Transform blended_transform =
- to_operations.Blend(from_operations, progress).Apply();
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(blended_matrix, blended_transform);
- }
-}
-
-TEST(TransformOperationTest, BlendedBoundsForPerspective) {
- struct {
- float from_depth;
- float to_depth;
- } perspective_depths[] = {
- {600.f, 400.f},
- {800.f, 1000.f},
- {800.f, std::numeric_limits<float>::infinity()},
- };
-
- struct {
- float min_progress;
- float max_progress;
- } progress[] = {
- {0.f, 1.f}, {-0.1f, 1.1f},
- };
-
- for (size_t i = 0; i < base::size(perspective_depths); ++i) {
- for (size_t j = 0; j < base::size(progress); ++j) {
- TransformOperations operations_from;
- operations_from.AppendPerspective(perspective_depths[i].from_depth);
- TransformOperations operations_to;
- operations_to.AppendPerspective(perspective_depths[i].to_depth);
- EmpiricallyTestBoundsEquality(operations_from,
- operations_to,
- progress[j].min_progress,
- progress[j].max_progress);
- }
- }
-}
-
-TEST(TransformOperationTest, BlendedBoundsForSkew) {
- struct {
- float from_x;
- float from_y;
- float to_x;
- float to_y;
- } skews[] = {
- {1.f, 0.5f, 0.5f, 1.f}, {2.f, 1.f, 0.5f, 0.5f},
- };
-
- struct {
- float min_progress;
- float max_progress;
- } progress[] = {
- {0.f, 1.f}, {-0.1f, 1.1f},
- };
-
- for (size_t i = 0; i < base::size(skews); ++i) {
- for (size_t j = 0; j < base::size(progress); ++j) {
- TransformOperations operations_from;
- operations_from.AppendSkew(skews[i].from_x, skews[i].from_y);
- TransformOperations operations_to;
- operations_to.AppendSkew(skews[i].to_x, skews[i].to_y);
- EmpiricallyTestBoundsEquality(operations_from,
- operations_to,
- progress[j].min_progress,
- progress[j].max_progress);
- }
- }
-}
-
-TEST(TransformOperationTest, NonCommutativeRotations) {
- TransformOperations operations_from;
- operations_from.AppendRotate(1.0, 0.0, 0.0, 0.0);
- operations_from.AppendRotate(0.0, 1.0, 0.0, 0.0);
- TransformOperations operations_to;
- operations_to.AppendRotate(1.0, 0.0, 0.0, 45.0);
- operations_to.AppendRotate(0.0, 1.0, 0.0, 135.0);
-
- gfx::BoxF box(0, 0, 0, 1, 1, 1);
- gfx::BoxF bounds;
-
- SkScalar min_progress = 0.0f;
- SkScalar max_progress = 1.0f;
- EXPECT_TRUE(operations_to.BlendedBoundsForBox(
- box, operations_from, min_progress, max_progress, &bounds));
- gfx::Transform blended_transform =
- operations_to.Blend(operations_from, max_progress).Apply();
- gfx::Point3F blended_point(0.9f, 0.9f, 0.0f);
- blended_transform.TransformPoint(&blended_point);
- gfx::BoxF expanded_bounds = bounds;
- expanded_bounds.ExpandTo(blended_point);
- EXPECT_EQ(bounds.ToString(), expanded_bounds.ToString());
-}
-
-TEST(TransformOperationTest, BlendedBoundsForSequence) {
- TransformOperations operations_from;
- operations_from.AppendTranslate(1.0, -5.0, 1.0);
- operations_from.AppendScale(-1.0, 2.0, 3.0);
- operations_from.AppendTranslate(2.0, 4.0, -1.0);
- TransformOperations operations_to;
- operations_to.AppendTranslate(13.0, -1.0, 5.0);
- operations_to.AppendScale(-3.0, -2.0, 5.0);
- operations_to.AppendTranslate(6.0, -2.0, 3.0);
-
- gfx::BoxF box(1.f, 2.f, 3.f, 4.f, 4.f, 4.f);
- gfx::BoxF bounds;
-
- SkScalar min_progress = -0.5f;
- SkScalar max_progress = 1.5f;
- EXPECT_TRUE(operations_to.BlendedBoundsForBox(
- box, operations_from, min_progress, max_progress, &bounds));
- EXPECT_EQ(gfx::BoxF(-57.f, -59.f, -1.f, 76.f, 112.f, 80.f).ToString(),
- bounds.ToString());
-
- min_progress = 0.f;
- max_progress = 1.f;
- EXPECT_TRUE(operations_to.BlendedBoundsForBox(
- box, operations_from, min_progress, max_progress, &bounds));
- EXPECT_EQ(gfx::BoxF(-32.f, -25.f, 7.f, 42.f, 44.f, 48.f).ToString(),
- bounds.ToString());
-
- TransformOperations identity;
- EXPECT_TRUE(operations_to.BlendedBoundsForBox(
- box, identity, min_progress, max_progress, &bounds));
- EXPECT_EQ(gfx::BoxF(-33.f, -13.f, 3.f, 57.f, 19.f, 52.f).ToString(),
- bounds.ToString());
-
- EXPECT_TRUE(identity.BlendedBoundsForBox(
- box, operations_from, min_progress, max_progress, &bounds));
- EXPECT_EQ(gfx::BoxF(-7.f, -3.f, 2.f, 15.f, 23.f, 20.f).ToString(),
- bounds.ToString());
-}
-
-TEST(TransformOperationTest, IsTranslationWithSingleOperation) {
- TransformOperations empty_operations;
- EXPECT_TRUE(empty_operations.IsTranslation());
-
- TransformOperations identity;
- identity.AppendIdentity();
- EXPECT_TRUE(identity.IsTranslation());
-
- TransformOperations translate;
- translate.AppendTranslate(1.f, 2.f, 3.f);
- EXPECT_TRUE(translate.IsTranslation());
-
- TransformOperations rotate;
- rotate.AppendRotate(1.f, 2.f, 3.f, 4.f);
- EXPECT_FALSE(rotate.IsTranslation());
-
- TransformOperations scale;
- scale.AppendScale(1.f, 2.f, 3.f);
- EXPECT_FALSE(scale.IsTranslation());
-
- TransformOperations skew;
- skew.AppendSkew(1.f, 2.f);
- EXPECT_FALSE(skew.IsTranslation());
-
- TransformOperations perspective;
- perspective.AppendPerspective(1.f);
- EXPECT_FALSE(perspective.IsTranslation());
-
- TransformOperations identity_matrix;
- identity_matrix.AppendMatrix(gfx::Transform());
- EXPECT_TRUE(identity_matrix.IsTranslation());
-
- TransformOperations translation_matrix;
- gfx::Transform translation_transform;
- translation_transform.Translate3d(1.f, 2.f, 3.f);
- translation_matrix.AppendMatrix(translation_transform);
- EXPECT_TRUE(translation_matrix.IsTranslation());
-
- TransformOperations scaling_matrix;
- gfx::Transform scaling_transform;
- scaling_transform.Scale(2.f, 2.f);
- scaling_matrix.AppendMatrix(scaling_transform);
- EXPECT_FALSE(scaling_matrix.IsTranslation());
-}
-
-TEST(TransformOperationTest, IsTranslationWithMultipleOperations) {
- TransformOperations operations1;
- operations1.AppendSkew(1.f, 2.f);
- operations1.AppendTranslate(1.f, 2.f, 3.f);
- operations1.AppendIdentity();
- EXPECT_FALSE(operations1.IsTranslation());
-
- TransformOperations operations2;
- operations2.AppendIdentity();
- operations2.AppendTranslate(3.f, 2.f, 1.f);
- gfx::Transform translation_transform;
- translation_transform.Translate3d(1.f, 2.f, 3.f);
- operations2.AppendMatrix(translation_transform);
- EXPECT_TRUE(operations2.IsTranslation());
-}
-
-TEST(TransformOperationTest, ScaleComponent) {
- SkScalar scale;
-
- // Scale.
- TransformOperations operations1;
- operations1.AppendScale(-3.f, 2.f, 5.f);
- EXPECT_TRUE(operations1.ScaleComponent(&scale));
- EXPECT_EQ(5.f, scale);
-
- // Translate.
- TransformOperations operations2;
- operations2.AppendTranslate(1.f, 2.f, 3.f);
- EXPECT_TRUE(operations2.ScaleComponent(&scale));
- EXPECT_EQ(1.f, scale);
-
- // Rotate.
- TransformOperations operations3;
- operations3.AppendRotate(1.f, 2.f, 3.f, 4.f);
- EXPECT_TRUE(operations3.ScaleComponent(&scale));
- EXPECT_EQ(1.f, scale);
-
- // Matrix that's only a translation.
- TransformOperations operations4;
- gfx::Transform translation_transform;
- translation_transform.Translate3d(1.f, 2.f, 3.f);
- operations4.AppendMatrix(translation_transform);
- EXPECT_TRUE(operations4.ScaleComponent(&scale));
- EXPECT_EQ(1.f, scale);
-
- // Matrix that includes scale.
- TransformOperations operations5;
- gfx::Transform matrix;
- matrix.RotateAboutZAxis(30.0);
- matrix.Scale(-7.f, 6.f);
- matrix.Translate3d(gfx::Vector3dF(3.f, 7.f, 1.f));
- operations5.AppendMatrix(matrix);
- EXPECT_TRUE(operations5.ScaleComponent(&scale));
- EXPECT_EQ(7.f, scale);
-
- // Matrix with perspective.
- TransformOperations operations6;
- matrix.ApplyPerspectiveDepth(2000.f);
- operations6.AppendMatrix(matrix);
- EXPECT_FALSE(operations6.ScaleComponent(&scale));
-
- // Skew.
- TransformOperations operations7;
- operations7.AppendSkew(30.f, 60.f);
- EXPECT_TRUE(operations7.ScaleComponent(&scale));
- EXPECT_EQ(2.f, scale);
-
- // Perspective.
- TransformOperations operations8;
- operations8.AppendPerspective(500.f);
- EXPECT_FALSE(operations8.ScaleComponent(&scale));
-
- // Translate + Scale.
- TransformOperations operations9;
- operations9.AppendTranslate(1.f, 2.f, 3.f);
- operations9.AppendScale(2.f, 5.f, 4.f);
- EXPECT_TRUE(operations9.ScaleComponent(&scale));
- EXPECT_EQ(5.f, scale);
-
- // Translate + Scale + Matrix with translate.
- operations9.AppendMatrix(translation_transform);
- EXPECT_TRUE(operations9.ScaleComponent(&scale));
- EXPECT_EQ(5.f, scale);
-
- // Scale + translate.
- TransformOperations operations10;
- operations10.AppendScale(2.f, 3.f, 2.f);
- operations10.AppendTranslate(1.f, 2.f, 3.f);
- EXPECT_TRUE(operations10.ScaleComponent(&scale));
- EXPECT_EQ(3.f, scale);
-
- // Two Scales.
- TransformOperations operations11;
- operations11.AppendScale(2.f, 3.f, 2.f);
- operations11.AppendScale(-3.f, -2.f, -3.f);
- EXPECT_TRUE(operations11.ScaleComponent(&scale));
- EXPECT_EQ(9.f, scale);
-
- // Scale + Matrix.
- TransformOperations operations12;
- operations12.AppendScale(2.f, 2.f, 2.f);
- gfx::Transform scaling_transform;
- scaling_transform.Scale(2.f, 2.f);
- operations12.AppendMatrix(scaling_transform);
- EXPECT_TRUE(operations12.ScaleComponent(&scale));
- EXPECT_EQ(4.f, scale);
-
- // Scale + Rotate.
- TransformOperations operations13;
- operations13.AppendScale(2.f, 2.f, 2.f);
- operations13.AppendRotate(1.f, 2.f, 3.f, 4.f);
- EXPECT_TRUE(operations13.ScaleComponent(&scale));
- EXPECT_EQ(2.f, scale);
-
- // Scale + Skew.
- TransformOperations operations14;
- operations14.AppendScale(2.f, 2.f, 2.f);
- operations14.AppendSkew(60.f, 45.f);
- EXPECT_TRUE(operations14.ScaleComponent(&scale));
- EXPECT_EQ(4.f, scale);
-
- // Scale + Perspective.
- TransformOperations operations15;
- operations15.AppendScale(2.f, 2.f, 2.f);
- operations15.AppendPerspective(1.f);
- EXPECT_FALSE(operations15.ScaleComponent(&scale));
-
- // Matrix with skew.
- TransformOperations operations16;
- gfx::Transform skew_transform;
- skew_transform.Skew(50.f, 60.f);
- operations16.AppendMatrix(skew_transform);
- EXPECT_TRUE(operations16.ScaleComponent(&scale));
- EXPECT_EQ(2.f, scale);
-}
-
-TEST(TransformOperationsTest, ApproximateEquality) {
- float noise = 1e-7f;
- float tolerance = 1e-5f;
- TransformOperations lhs;
- TransformOperations rhs;
-
- // Empty lists of operations are trivially equal.
- EXPECT_TRUE(lhs.ApproximatelyEqual(rhs, tolerance));
-
- rhs.AppendIdentity();
- rhs.AppendTranslate(0, 0, 0);
- rhs.AppendRotate(1, 0, 0, 0);
- rhs.AppendScale(1, 1, 1);
- rhs.AppendSkew(0, 0);
- rhs.AppendMatrix(gfx::Transform());
-
- // Even though both lists operations are effectively the identity matrix, rhs
- // has a different number of operations and is therefore different.
- EXPECT_FALSE(lhs.ApproximatelyEqual(rhs, tolerance));
-
- rhs.AppendPerspective(800);
-
- // Assignment should produce equal lists of operations.
- lhs = rhs;
- EXPECT_TRUE(lhs.ApproximatelyEqual(rhs, tolerance));
-
- // Cannot affect identity operations.
- lhs.at(0).translate.x = 1;
- EXPECT_TRUE(lhs.ApproximatelyEqual(rhs, tolerance));
-
- lhs.at(1).translate.x += noise;
- EXPECT_TRUE(lhs.ApproximatelyEqual(rhs, tolerance));
- lhs.at(1).translate.x += 1;
- EXPECT_FALSE(lhs.ApproximatelyEqual(rhs, tolerance));
-
- lhs = rhs;
- lhs.at(2).rotate.angle += noise;
- EXPECT_TRUE(lhs.ApproximatelyEqual(rhs, tolerance));
- lhs.at(2).rotate.angle = 1;
- EXPECT_FALSE(lhs.ApproximatelyEqual(rhs, tolerance));
-
- lhs = rhs;
- lhs.at(3).scale.x += noise;
- EXPECT_TRUE(lhs.ApproximatelyEqual(rhs, tolerance));
- lhs.at(3).scale.x += 1;
- EXPECT_FALSE(lhs.ApproximatelyEqual(rhs, tolerance));
-
- lhs = rhs;
- lhs.at(4).skew.x += noise;
- EXPECT_TRUE(lhs.ApproximatelyEqual(rhs, tolerance));
- lhs.at(4).skew.x = 2;
- EXPECT_FALSE(lhs.ApproximatelyEqual(rhs, tolerance));
-
- lhs = rhs;
- lhs.at(5).matrix.Translate3d(noise, 0, 0);
- EXPECT_TRUE(lhs.ApproximatelyEqual(rhs, tolerance));
- lhs.at(5).matrix.Translate3d(1, 1, 1);
- EXPECT_FALSE(lhs.ApproximatelyEqual(rhs, tolerance));
-
- lhs = rhs;
- lhs.at(6).perspective_depth += noise;
- EXPECT_TRUE(lhs.ApproximatelyEqual(rhs, tolerance));
- lhs.at(6).perspective_depth = 801;
- EXPECT_FALSE(lhs.ApproximatelyEqual(rhs, tolerance));
-}
-
-} // namespace
-
-// This test is intentionally outside the anonymous namespace for visibility as
-// it needs to be friend of TransformOperations.
-TEST(TransformOperationsTest, TestDecompositionCache) {
- TransformOperations transforms;
- EXPECT_EQ(0UL, transforms.decomposed_transforms_.size());
- EXPECT_TRUE(transforms.ComputeDecomposedTransform(0));
- EXPECT_EQ(1UL, transforms.decomposed_transforms_.size());
-
- // Reset cache when appending a scale transform.
- transforms.AppendScale(2.f, 2.f, 2.f);
- EXPECT_EQ(0UL, transforms.decomposed_transforms_.size());
- EXPECT_TRUE(transforms.ComputeDecomposedTransform(1));
- EXPECT_EQ(1UL, transforms.decomposed_transforms_.size());
- EXPECT_TRUE(transforms.ComputeDecomposedTransform(1));
- EXPECT_EQ(1UL, transforms.decomposed_transforms_.size());
- EXPECT_TRUE(transforms.ComputeDecomposedTransform(0));
- EXPECT_EQ(2UL, transforms.decomposed_transforms_.size());
-
- // Reset cache when appending a rotation transform.
- transforms.AppendRotate(1, 0, 0, 45);
- EXPECT_EQ(0UL, transforms.decomposed_transforms_.size());
- EXPECT_TRUE(transforms.ComputeDecomposedTransform(0));
- EXPECT_EQ(1UL, transforms.decomposed_transforms_.size());
-
- // Reset cache when appending a translation transform.
- transforms.AppendTranslate(1, 1, 1);
- EXPECT_EQ(0UL, transforms.decomposed_transforms_.size());
- EXPECT_TRUE(transforms.ComputeDecomposedTransform(0));
- EXPECT_EQ(1UL, transforms.decomposed_transforms_.size());
-
- // Reset cache when appending a skew transform.
- transforms.AppendSkew(1, 0);
- EXPECT_EQ(0UL, transforms.decomposed_transforms_.size());
- EXPECT_TRUE(transforms.ComputeDecomposedTransform(0));
- EXPECT_EQ(1UL, transforms.decomposed_transforms_.size());
-
- // Reset cache when appending a perspective transform.
- transforms.AppendPerspective(800);
- EXPECT_EQ(0UL, transforms.decomposed_transforms_.size());
- EXPECT_TRUE(transforms.ComputeDecomposedTransform(0));
- EXPECT_EQ(1UL, transforms.decomposed_transforms_.size());
-
- // Reset cache when appending a matrix transform.
- transforms.AppendMatrix(gfx::Transform());
- EXPECT_EQ(0UL, transforms.decomposed_transforms_.size());
- EXPECT_TRUE(transforms.ComputeDecomposedTransform(0));
- EXPECT_EQ(1UL, transforms.decomposed_transforms_.size());
-
- // Reset cache when appending a generic transform operation.
- transforms.Append(TransformOperation());
- EXPECT_EQ(0UL, transforms.decomposed_transforms_.size());
- EXPECT_TRUE(transforms.ComputeDecomposedTransform(0));
- EXPECT_EQ(1UL, transforms.decomposed_transforms_.size());
-}
-
-TEST(TransformOperationTest, BlendSkewMismatch) {
- TransformOperations from_ops, to_ops, expected_ops;
- from_ops.AppendSkewX(0);
- from_ops.AppendRotate(0, 0, 1, 0);
- to_ops.AppendSkewY(0);
- to_ops.AppendRotate(0, 0, 1, 360);
-
- // Skew types do not match so use matrix interpolation
- expected_ops.AppendMatrix(gfx::Transform());
-
- TransformOperations blended_ops = to_ops.Blend(from_ops, 0.5);
- ASSERT_EQ(blended_ops.size(), 1u);
- ExpectTransformOperationEqual(blended_ops.at(0), expected_ops.at(0));
-}
-
-TEST(TransformOperationTest, BlendSkewMatch) {
- TransformOperations from_ops, to_ops, expected_ops;
- from_ops.AppendSkew(30, 0);
- from_ops.AppendRotate(0, 0, 1, 0);
- to_ops.AppendSkew(0, 30);
- to_ops.AppendRotate(0, 0, 1, 360);
-
- // Skew types match so interpolate as a function.
- expected_ops.AppendSkew(15, 15);
- expected_ops.AppendRotate(0, 0, 1, 180);
-
- TransformOperations blended_ops = to_ops.Blend(from_ops, 0.5);
- ASSERT_EQ(blended_ops.size(), 2u);
- ExpectTransformOperationEqual(blended_ops.at(0), expected_ops.at(0));
- ExpectTransformOperationEqual(blended_ops.at(1), expected_ops.at(1));
-}
-
-} // namespace cc
diff --git a/chromium/cc/base/features.cc b/chromium/cc/base/features.cc
index 0e831481045..5e95d7db995 100644
--- a/chromium/cc/base/features.cc
+++ b/chromium/cc/base/features.cc
@@ -8,9 +8,21 @@
namespace features {
+// Uses the Resume method instead of the Catch-up method for animated images.
+// - Catch-up behavior tries to keep animated images in pace with wall-clock
+// time. This might require decoding several animation frames if the
+// animation has fallen behind.
+// - Resume behavior presents what would have been the next presented frame.
+// This means it might only decode one frame, resuming where it left off.
+// However, if the animation updates faster than the display's refresh rate,
+// it is possible to decode more than a single frame.
+const base::Feature kAnimatedImageResume = {"AnimatedImageResume",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// Enables impulse-style scroll animations in place of the default ones.
const base::Feature kImpulseScrollAnimations = {
- "ImpulseScrollAnimations", base::FEATURE_DISABLED_BY_DEFAULT};
+ "ImpulseScrollAnimations",
+ base::FEATURE_DISABLED_BY_DEFAULT};
// Whether the compositor should attempt to sync with the scroll handlers before
// submitting a frame.
@@ -60,4 +72,10 @@ const base::Feature kSchedulerSmoothnessForAnimatedScrolls{
const base::Feature kWheelEventRegions{"WheelEventRegions",
base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kHudDisplayForPerformanceMetrics{
+ "HudDisplayForPerformanceMetrics", base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kJankInjectionAblationFeature{
+ "JankInjectionAblation", base::FEATURE_DISABLED_BY_DEFAULT};
} // namespace features
diff --git a/chromium/cc/base/features.h b/chromium/cc/base/features.h
index 6c1e4db7b81..8fef93721ec 100644
--- a/chromium/cc/base/features.h
+++ b/chromium/cc/base/features.h
@@ -11,6 +11,7 @@
namespace features {
+CC_BASE_EXPORT extern const base::Feature kAnimatedImageResume;
CC_BASE_EXPORT extern const base::Feature kImpulseScrollAnimations;
CC_BASE_EXPORT extern const base::Feature kSynchronizedScrolling;
@@ -42,6 +43,13 @@ CC_BASE_EXPORT extern const base::Feature
// https://docs.google.com/document/d/1ar4WhVnLA-fmw6atgP-23iq-ys_NfFoGb3LA5AgaylA/edit?usp=sharing
CC_BASE_EXPORT extern const base::Feature kWheelEventRegions;
+// When enabled, cc will show blink's Web-Vital metrics inside its heads up
+// display.
+CC_BASE_EXPORT extern const base::Feature kHudDisplayForPerformanceMetrics;
+
+// When enabled, some jank is injected to the animation/scrolling pipeline.
+CC_BASE_EXPORT extern const base::Feature kJankInjectionAblationFeature;
+
} // namespace features
#endif // CC_BASE_FEATURES_H_
diff --git a/chromium/cc/base/math_util.cc b/chromium/cc/base/math_util.cc
index 486974d284d..6af60ed1cf4 100644
--- a/chromium/cc/base/math_util.cc
+++ b/chromium/cc/base/math_util.cc
@@ -577,42 +577,6 @@ gfx::RectF MathUtil::ScaleRectProportional(const gfx::RectF& input_outer_rect,
return output_inner_rect;
}
-static inline bool NearlyZero(double value) {
- return std::abs(value) < std::numeric_limits<double>::epsilon();
-}
-
-static inline float ScaleOnAxis(double a, double b, double c) {
- if (NearlyZero(b) && NearlyZero(c))
- return std::abs(a);
- if (NearlyZero(a) && NearlyZero(c))
- return std::abs(b);
- if (NearlyZero(a) && NearlyZero(b))
- return std::abs(c);
-
- // Do the sqrt as a double to not lose precision.
- return static_cast<float>(std::sqrt(a * a + b * b + c * c));
-}
-
-gfx::Vector2dF MathUtil::ComputeTransform2dScaleComponents(
- const gfx::Transform& transform,
- float fallback_value) {
- if (transform.HasPerspective())
- return gfx::Vector2dF(fallback_value, fallback_value);
- float x_scale = ScaleOnAxis(transform.matrix().getDouble(0, 0),
- transform.matrix().getDouble(1, 0),
- transform.matrix().getDouble(2, 0));
- float y_scale = ScaleOnAxis(transform.matrix().getDouble(0, 1),
- transform.matrix().getDouble(1, 1),
- transform.matrix().getDouble(2, 1));
- return gfx::Vector2dF(x_scale, y_scale);
-}
-
-float MathUtil::ComputeApproximateMaxScale(const gfx::Transform& transform) {
- gfx::RectF unit(0.f, 0.f, 1.f, 1.f);
- transform.TransformRect(&unit);
- return std::max(unit.width(), unit.height());
-}
-
float MathUtil::SmallestAngleBetweenVectors(const gfx::Vector2dF& v1,
const gfx::Vector2dF& v2) {
double dot_product = gfx::DotProduct(v1, v2) / v1.Length() / v2.Length();
@@ -868,4 +832,39 @@ bool MathUtil::IsNearlyTheSameForTesting(const gfx::Point3F& left,
return IsNearlyTheSame(left, right);
}
+// Equivalent to SkMatrix::HasPerspective
+bool MathUtil::SkM44HasPerspective(const SkM44& m) {
+ return (m.rc(3, 0) != 0 || m.rc(3, 1) != 0 || m.rc(3, 2) != 0 ||
+ m.rc(3, 3) != 1);
+}
+
+// Since some operations assume a 2d transformation, check to make sure that
+// is the case by seeing that the z-axis is identity
+bool MathUtil::SkM44Is2D(const SkM44& m) {
+ return (m.rc(0, 2) == 0 && m.rc(1, 2) == 0 && m.rc(2, 2) == 1 &&
+ m.rc(2, 0) == 0 && m.rc(2, 1) == 0 && m.rc(2, 3) == 0 &&
+ m.rc(3, 2) == 0);
+}
+
+// Equivalent to SkMatrix::PreservesAxisAlignment
+// Checks if the transformation is a 90 degree rotation or scaling
+// See SkMatrix::computeTypeMask
+bool MathUtil::SkM44Preserves2DAxisAlignment(const SkM44& m) {
+ // Conservatively assume that perspective transforms would not preserve
+ // axis-alignment
+ if (!SkM44Is2D(m) || SkM44HasPerspective(m))
+ return false;
+
+ // Does the matrix have skew components
+ if (m.rc(0, 1) != 0 || m.rc(1, 0) != 0) {
+ // Rects only map to rects if both skews are non-zero and both scale
+ // components are zero (i.e. it's a +/-90-degree rotation)
+ return (m.rc(0, 0) == 0 && m.rc(1, 1) == 0 && m.rc(0, 1) != 0 &&
+ m.rc(1, 0) != 0);
+ }
+ // Since the matrix has no skewing, it maps to a rectangle so long as the
+ // scale components are non-zero
+ return (m.rc(0, 0) != 0 && m.rc(1, 1) != 0);
+}
+
} // namespace cc
diff --git a/chromium/cc/base/math_util.h b/chromium/cc/base/math_util.h
index 8cb8c38628b..e6940430086 100644
--- a/chromium/cc/base/math_util.h
+++ b/chromium/cc/base/math_util.h
@@ -13,6 +13,7 @@
#include "base/numerics/ranges.h"
#include "build/build_config.h"
#include "cc/base/base_export.h"
+#include "third_party/skia/include/core/SkM44.h"
#include "ui/gfx/geometry/box_f.h"
#include "ui/gfx/geometry/point3_f.h"
#include "ui/gfx/geometry/point_f.h"
@@ -234,13 +235,6 @@ class CC_BASE_EXPORT MathUtil {
const gfx::PointF& point,
bool* clipped);
- static gfx::Vector2dF ComputeTransform2dScaleComponents(const gfx::Transform&,
- float fallbackValue);
- // Returns an approximate max scale value of the transform even if it has
- // perspective. Prefer to use ComputeTransform2dScaleComponents if there is no
- // perspective, since it can produce more accurate results.
- static float ComputeApproximateMaxScale(const gfx::Transform& transform);
-
// Makes a rect that has the same relationship to input_outer_rect as
// scale_inner_rect has to scale_outer_rect. scale_inner_rect should be
// contained within scale_outer_rect, and likewise the rectangle that is
@@ -325,6 +319,12 @@ class CC_BASE_EXPORT MathUtil {
static bool IsNearlyTheSameForTesting(const gfx::Point3F& l,
const gfx::Point3F& r);
+ // Helper functions for migration from SkMatrix->SkM44. It may make sense to
+ // move these to skia itself at some point.
+ static bool SkM44HasPerspective(const SkM44& m);
+ static bool SkM44Is2D(const SkM44& m);
+ static bool SkM44Preserves2DAxisAlignment(const SkM44& m);
+
private:
template <typename T>
static T RoundUpInternal(T n, T mul) {
diff --git a/chromium/cc/debug/layer_tree_debug_state.cc b/chromium/cc/debug/layer_tree_debug_state.cc
index 0ce673525cf..2a791a688a7 100644
--- a/chromium/cc/debug/layer_tree_debug_state.cc
+++ b/chromium/cc/debug/layer_tree_debug_state.cc
@@ -4,29 +4,10 @@
#include "cc/debug/layer_tree_debug_state.h"
-
namespace cc {
// IMPORTANT: new fields must be added to Equal() and Unite()
-LayerTreeDebugState::LayerTreeDebugState()
- : show_fps_counter(false),
- show_debug_borders(false),
- show_layout_shift_regions(false),
- show_paint_rects(false),
- show_property_changed_rects(false),
- show_surface_damage_rects(false),
- show_screen_space_rects(false),
- show_touch_event_handler_rects(false),
- show_wheel_event_handler_rects(false),
- show_scroll_event_handler_rects(false),
- show_non_fast_scrollable_rects(false),
- show_main_thread_scrolling_reason_rects(false),
- show_layer_animation_bounds_rects(false),
- slow_down_raster_scale_factor(0),
- rasterize_only_visible_content(false),
- highlight_non_lcd_text_layers(false),
- show_hit_test_borders(false),
- record_rendering_stats_(false) {}
+LayerTreeDebugState::LayerTreeDebugState() = default;
LayerTreeDebugState::LayerTreeDebugState(const LayerTreeDebugState& other) =
default;
@@ -41,11 +22,11 @@ bool LayerTreeDebugState::RecordRenderingStats() const {
return record_rendering_stats_;
}
-bool LayerTreeDebugState::ShowHudInfo() const {
- return show_fps_counter || ShowHudRects();
+bool LayerTreeDebugState::ShouldCreateHudLayer() const {
+ return ShowDebugRects() || ShouldDrawHudInfo();
}
-bool LayerTreeDebugState::ShowHudRects() const {
+bool LayerTreeDebugState::ShowDebugRects() const {
return show_paint_rects || show_property_changed_rects ||
show_surface_damage_rects || show_screen_space_rects ||
show_touch_event_handler_rects || show_wheel_event_handler_rects ||
@@ -58,6 +39,18 @@ bool LayerTreeDebugState::ShowMemoryStats() const {
return show_fps_counter;
}
+bool LayerTreeDebugState::ShouldDrawHudInfo() const {
+ return show_fps_counter || show_web_vital_metrics || show_smoothness_metrics;
+}
+
+void LayerTreeDebugState::TurnOffHudInfoDisplay() {
+ // Turn off all types of HUD info display. ShouldDrawHudInfo() would return
+ // false after this function.
+ show_fps_counter = false;
+ show_web_vital_metrics = false;
+ show_smoothness_metrics = false;
+}
+
bool LayerTreeDebugState::Equal(const LayerTreeDebugState& a,
const LayerTreeDebugState& b) {
return (
@@ -80,39 +73,8 @@ bool LayerTreeDebugState::Equal(const LayerTreeDebugState& a,
a.rasterize_only_visible_content == b.rasterize_only_visible_content &&
a.highlight_non_lcd_text_layers == b.highlight_non_lcd_text_layers &&
a.show_hit_test_borders == b.show_hit_test_borders &&
+ a.show_web_vital_metrics == b.show_web_vital_metrics &&
a.record_rendering_stats_ == b.record_rendering_stats_);
}
-LayerTreeDebugState LayerTreeDebugState::Unite(const LayerTreeDebugState& a,
- const LayerTreeDebugState& b) {
- LayerTreeDebugState r(a);
-
- r.show_fps_counter |= b.show_fps_counter;
- r.show_debug_borders |= b.show_debug_borders;
-
- r.show_layout_shift_regions |= b.show_layout_shift_regions;
- r.show_paint_rects |= b.show_paint_rects;
- r.show_property_changed_rects |= b.show_property_changed_rects;
- r.show_surface_damage_rects |= b.show_surface_damage_rects;
- r.show_screen_space_rects |= b.show_screen_space_rects;
- r.show_touch_event_handler_rects |= b.show_touch_event_handler_rects;
- r.show_wheel_event_handler_rects |= b.show_wheel_event_handler_rects;
- r.show_scroll_event_handler_rects |= b.show_scroll_event_handler_rects;
- r.show_non_fast_scrollable_rects |= b.show_non_fast_scrollable_rects;
- r.show_main_thread_scrolling_reason_rects |=
- b.show_main_thread_scrolling_reason_rects;
- r.show_layer_animation_bounds_rects |= b.show_layer_animation_bounds_rects;
-
- if (b.slow_down_raster_scale_factor)
- r.slow_down_raster_scale_factor = b.slow_down_raster_scale_factor;
- r.rasterize_only_visible_content |= b.rasterize_only_visible_content;
- r.highlight_non_lcd_text_layers |= b.highlight_non_lcd_text_layers;
-
- r.show_hit_test_borders |= b.show_hit_test_borders;
-
- r.record_rendering_stats_ |= b.record_rendering_stats_;
-
- return r;
-}
-
} // namespace cc
diff --git a/chromium/cc/debug/layer_tree_debug_state.h b/chromium/cc/debug/layer_tree_debug_state.h
index 95b79cda95d..d6618b9e4a8 100644
--- a/chromium/cc/debug/layer_tree_debug_state.h
+++ b/chromium/cc/debug/layer_tree_debug_state.h
@@ -29,40 +29,48 @@ class CC_DEBUG_EXPORT LayerTreeDebugState {
LayerTreeDebugState(const LayerTreeDebugState& other);
~LayerTreeDebugState();
- bool show_fps_counter;
- DebugBorderTypes show_debug_borders;
-
- bool show_layout_shift_regions;
- bool show_paint_rects;
- bool show_property_changed_rects;
- bool show_surface_damage_rects;
- bool show_screen_space_rects;
- bool show_touch_event_handler_rects;
- bool show_wheel_event_handler_rects;
- bool show_scroll_event_handler_rects;
- bool show_non_fast_scrollable_rects;
- bool show_main_thread_scrolling_reason_rects;
- bool show_layer_animation_bounds_rects;
-
- int slow_down_raster_scale_factor;
- bool rasterize_only_visible_content;
- bool highlight_non_lcd_text_layers;
-
- bool show_hit_test_borders;
+ bool show_fps_counter = false;
+ DebugBorderTypes show_debug_borders = false;
+
+ bool show_layout_shift_regions = false;
+ bool show_paint_rects = false;
+ bool show_property_changed_rects = false;
+ bool show_surface_damage_rects = false;
+ bool show_screen_space_rects = false;
+ bool show_touch_event_handler_rects = false;
+ bool show_wheel_event_handler_rects = false;
+ bool show_scroll_event_handler_rects = false;
+ bool show_non_fast_scrollable_rects = false;
+ bool show_main_thread_scrolling_reason_rects = false;
+ bool show_layer_animation_bounds_rects = false;
+
+ int slow_down_raster_scale_factor = 0;
+ bool rasterize_only_visible_content = false;
+ bool highlight_non_lcd_text_layers = false;
+
+ bool show_hit_test_borders = false;
+
+ // This is part of the feature to show performance metrics on HUD. This
+ // particular flag is set only in Blink.
+ bool show_web_vital_metrics = false;
+ bool show_smoothness_metrics = false;
void SetRecordRenderingStats(bool enabled);
bool RecordRenderingStats() const;
- bool ShowHudInfo() const;
- bool ShowHudRects() const;
+ // HUD layer is responsible for drawing debug rects as well as displaying HUD
+ // overlay. This function checks if a HUD layer should be created for any of
+ // these situations.
+ bool ShouldCreateHudLayer() const;
+ bool ShowDebugRects() const;
bool ShowMemoryStats() const;
+ bool ShouldDrawHudInfo() const;
+ void TurnOffHudInfoDisplay();
static bool Equal(const LayerTreeDebugState& a, const LayerTreeDebugState& b);
- static LayerTreeDebugState Unite(const LayerTreeDebugState& a,
- const LayerTreeDebugState& b);
private:
- bool record_rendering_stats_;
+ bool record_rendering_stats_ = false;
};
} // namespace cc
diff --git a/chromium/cc/document_transition/README.md b/chromium/cc/document_transition/README.md
new file mode 100644
index 00000000000..3b764d357b0
--- /dev/null
+++ b/chromium/cc/document_transition/README.md
@@ -0,0 +1,5 @@
+# cc/document\_transition
+
+The document transition direction supports the Document Transition and Shared
+Element Transition projects in Blink. Please see
+//third\_party/blink/renderer/core/document\_transition/README.md for more details.
diff --git a/chromium/cc/document_transition/document_transition_request.cc b/chromium/cc/document_transition/document_transition_request.cc
new file mode 100644
index 00000000000..220d097f1ff
--- /dev/null
+++ b/chromium/cc/document_transition/document_transition_request.cc
@@ -0,0 +1,114 @@
+// 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.
+
+#include "cc/document_transition/document_transition_request.h"
+
+#include <memory>
+#include <sstream>
+#include <utility>
+
+#include "base/callback.h"
+#include "base/memory/ptr_util.h"
+#include "components/viz/common/quads/compositor_frame_transition_directive.h"
+
+namespace cc {
+namespace {
+
+std::string TypeToString(viz::CompositorFrameTransitionDirective::Type type) {
+ switch (type) {
+ case viz::CompositorFrameTransitionDirective::Type::kSave:
+ return "kSave";
+ case viz::CompositorFrameTransitionDirective::Type::kAnimate:
+ return "kAnimate";
+ }
+ return "<unknown>";
+}
+
+std::string EffectToString(
+ viz::CompositorFrameTransitionDirective::Effect effect) {
+ switch (effect) {
+ case viz::CompositorFrameTransitionDirective::Effect::kNone:
+ return "kNone";
+ case viz::CompositorFrameTransitionDirective::Effect::kCoverDown:
+ return "kCoverDown";
+ case viz::CompositorFrameTransitionDirective::Effect::kCoverLeft:
+ return "kCoverLeft";
+ case viz::CompositorFrameTransitionDirective::Effect::kCoverRight:
+ return "kCoverRight";
+ case viz::CompositorFrameTransitionDirective::Effect::kCoverUp:
+ return "kCoverUp";
+ case viz::CompositorFrameTransitionDirective::Effect::kExplode:
+ return "kExplode";
+ case viz::CompositorFrameTransitionDirective::Effect::kFade:
+ return "kFade";
+ case viz::CompositorFrameTransitionDirective::Effect::kImplode:
+ return "kImplode";
+ case viz::CompositorFrameTransitionDirective::Effect::kRevealDown:
+ return "kRevealDown";
+ case viz::CompositorFrameTransitionDirective::Effect::kRevealLeft:
+ return "kRevealLeft";
+ case viz::CompositorFrameTransitionDirective::Effect::kRevealRight:
+ return "kRevealRight";
+ case viz::CompositorFrameTransitionDirective::Effect::kRevealUp:
+ return "kRevealUp";
+ }
+ return "<unknown>";
+}
+
+} // namespace
+
+uint32_t DocumentTransitionRequest::s_next_sequence_id_ = 1;
+
+// static
+std::unique_ptr<DocumentTransitionRequest>
+DocumentTransitionRequest::CreatePrepare(Effect effect,
+ base::TimeDelta duration,
+ base::OnceClosure commit_callback) {
+ return base::WrapUnique(new DocumentTransitionRequest(
+ effect, duration, std::move(commit_callback)));
+}
+
+// static
+std::unique_ptr<DocumentTransitionRequest>
+DocumentTransitionRequest::CreateStart(base::OnceClosure commit_callback) {
+ return base::WrapUnique(
+ new DocumentTransitionRequest(std::move(commit_callback)));
+}
+
+DocumentTransitionRequest::DocumentTransitionRequest(
+ Effect effect,
+ base::TimeDelta duration,
+ base::OnceClosure commit_callback)
+ : type_(Type::kSave),
+ effect_(effect),
+ duration_(duration),
+ commit_callback_(std::move(commit_callback)) {}
+
+DocumentTransitionRequest::DocumentTransitionRequest(
+ base::OnceClosure commit_callback)
+ : type_(Type::kAnimate), commit_callback_(std::move(commit_callback)) {}
+
+DocumentTransitionRequest::~DocumentTransitionRequest() = default;
+
+viz::CompositorFrameTransitionDirective
+DocumentTransitionRequest::ConstructDirective() const {
+ // Note that the clamped_duration is also verified at
+ // CompositorFrameTransitionDirective deserialization time.
+ auto clamped_duration =
+ duration_ < viz::CompositorFrameTransitionDirective::kMaxDuration
+ ? duration_
+ : viz::CompositorFrameTransitionDirective::kMaxDuration;
+ return viz::CompositorFrameTransitionDirective(s_next_sequence_id_++, type_,
+ effect_, clamped_duration);
+}
+
+std::string DocumentTransitionRequest::ToString() const {
+ std::ostringstream str;
+ str << "[type: " << TypeToString(type_)
+ << " effect: " << EffectToString(effect_)
+ << " duration: " << duration_.InMillisecondsF() << "ms]";
+ return str.str();
+}
+
+} // namespace cc
diff --git a/chromium/cc/document_transition/document_transition_request.h b/chromium/cc/document_transition/document_transition_request.h
new file mode 100644
index 00000000000..dddfd4a9fd9
--- /dev/null
+++ b/chromium/cc/document_transition/document_transition_request.h
@@ -0,0 +1,73 @@
+// 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_DOCUMENT_TRANSITION_DOCUMENT_TRANSITION_REQUEST_H_
+#define CC_DOCUMENT_TRANSITION_DOCUMENT_TRANSITION_REQUEST_H_
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "base/callback.h"
+#include "cc/cc_export.h"
+#include "components/viz/common/quads/compositor_frame_transition_directive.h"
+
+namespace cc {
+
+// This class represents a document transition request. It is constructed in
+// Blink with an intent of translating this request into a viz directive for the
+// transition to occur.
+class CC_EXPORT DocumentTransitionRequest {
+ public:
+ using Effect = viz::CompositorFrameTransitionDirective::Effect;
+
+ // Creates a Type::kPrepare type of request.
+ static std::unique_ptr<DocumentTransitionRequest> CreatePrepare(
+ Effect effect,
+ base::TimeDelta duration,
+ base::OnceClosure commit_callback);
+
+ // Creates a Type::kSave type of request.
+ static std::unique_ptr<DocumentTransitionRequest> CreateStart(
+ base::OnceClosure commit_callback);
+
+ DocumentTransitionRequest(DocumentTransitionRequest&) = delete;
+ ~DocumentTransitionRequest();
+
+ DocumentTransitionRequest& operator=(DocumentTransitionRequest&) = delete;
+
+ // The callback is run when the request is committed from the main thread onto
+ // the compositor thread. This is used to indicate that the request has been
+ // submitted for processing and that script may now change the page in some
+ // way. In other words, this callback would resolve the prepare promise that
+ // script may be waiting for.
+ base::OnceClosure TakeCommitCallback() { return std::move(commit_callback_); }
+
+ // This constructs a viz directive. Note that repeated calls to this function
+ // would create a new sequence id for the directive, which means it would be
+ // processed again by viz.
+ viz::CompositorFrameTransitionDirective ConstructDirective() const;
+
+ // Testing / debugging functionality.
+ std::string ToString() const;
+
+ private:
+ using Type = viz::CompositorFrameTransitionDirective::Type;
+
+ DocumentTransitionRequest(Effect effect,
+ base::TimeDelta duration,
+ base::OnceClosure commit_callback);
+ explicit DocumentTransitionRequest(base::OnceClosure commit_callback);
+
+ const Type type_;
+ const Effect effect_ = Effect::kNone;
+ const base::TimeDelta duration_;
+ base::OnceClosure commit_callback_;
+
+ static uint32_t s_next_sequence_id_;
+};
+
+} // namespace cc
+
+#endif // CC_DOCUMENT_TRANSITION_DOCUMENT_TRANSITION_REQUEST_H_
diff --git a/chromium/cc/document_transition/document_transition_request_unittest.cc b/chromium/cc/document_transition/document_transition_request_unittest.cc
new file mode 100644
index 00000000000..e5001d1f2df
--- /dev/null
+++ b/chromium/cc/document_transition/document_transition_request_unittest.cc
@@ -0,0 +1,73 @@
+// 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.
+
+#include "cc/document_transition/document_transition_request.h"
+
+#include <utility>
+
+#include "base/test/bind.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+
+TEST(DocumentTransitionRequestTest, PrepareRequest) {
+ bool called = false;
+ auto callback = base::BindLambdaForTesting([&called]() { called = true; });
+
+ auto request = DocumentTransitionRequest::CreatePrepare(
+ DocumentTransitionRequest::Effect::kRevealLeft,
+ base::TimeDelta::FromMilliseconds(123), std::move(callback));
+
+ EXPECT_FALSE(called);
+ request->TakeCommitCallback().Run();
+ EXPECT_TRUE(called);
+ EXPECT_TRUE(request->TakeCommitCallback().is_null());
+
+ auto directive = request->ConstructDirective();
+ EXPECT_GT(directive.sequence_id(), 0u);
+ EXPECT_EQ(DocumentTransitionRequest::Effect::kRevealLeft, directive.effect());
+ EXPECT_EQ(base::TimeDelta::FromMilliseconds(123), directive.duration());
+ EXPECT_EQ(viz::CompositorFrameTransitionDirective::Type::kSave,
+ directive.type());
+
+ auto duplicate = request->ConstructDirective();
+ EXPECT_GT(duplicate.sequence_id(), directive.sequence_id());
+ EXPECT_EQ(duplicate.effect(), directive.effect());
+ EXPECT_EQ(duplicate.duration(), directive.duration());
+ EXPECT_EQ(duplicate.type(), directive.type());
+}
+
+TEST(DocumentTransitionRequestTest, PrepareRequestLongDurationIsCapped) {
+ auto long_duration = base::TimeDelta::FromSeconds(1);
+
+ ASSERT_GT(long_duration,
+ viz::CompositorFrameTransitionDirective::kMaxDuration);
+
+ auto request = DocumentTransitionRequest::CreatePrepare(
+ DocumentTransitionRequest::Effect::kRevealLeft, long_duration,
+ base::OnceCallback<void()>());
+
+ auto directive = request->ConstructDirective();
+ EXPECT_EQ(viz::CompositorFrameTransitionDirective::kMaxDuration,
+ directive.duration());
+}
+
+TEST(DocumentTransitionRequestTest, StartRequest) {
+ bool called = false;
+ auto callback = base::BindLambdaForTesting([&called]() { called = true; });
+
+ auto request = DocumentTransitionRequest::CreateStart(std::move(callback));
+
+ EXPECT_FALSE(called);
+ request->TakeCommitCallback().Run();
+ EXPECT_TRUE(called);
+ EXPECT_TRUE(request->TakeCommitCallback().is_null());
+
+ auto directive = request->ConstructDirective();
+ EXPECT_GT(directive.sequence_id(), 0u);
+ EXPECT_EQ(viz::CompositorFrameTransitionDirective::Type::kAnimate,
+ directive.type());
+}
+
+} // namespace cc
diff --git a/chromium/cc/input/browser_controls_state.h b/chromium/cc/input/browser_controls_state.h
index 8b2f93f4171..2e5c537949d 100644
--- a/chromium/cc/input/browser_controls_state.h
+++ b/chromium/cc/input/browser_controls_state.h
@@ -7,7 +7,14 @@
namespace cc {
-enum class BrowserControlsState { kShown = 1, kHidden = 2, kBoth = 3 };
+// A Java counterpart will be generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.cc.input
+enum class BrowserControlsState {
+ kShown = 1,
+ kHidden = 2,
+ kBoth = 3,
+ kMaxValue = kBoth
+};
} // namespace cc
diff --git a/chromium/cc/input/compositor_input_interfaces.h b/chromium/cc/input/compositor_input_interfaces.h
index b20b270ae9e..d5bbaededda 100644
--- a/chromium/cc/input/compositor_input_interfaces.h
+++ b/chromium/cc/input/compositor_input_interfaces.h
@@ -10,6 +10,7 @@
#include "base/time/time.h"
#include "cc/input/actively_scrolling_type.h"
#include "cc/paint/element_id.h"
+#include "ui/gfx/geometry/size.h"
namespace viz {
struct BeginFrameArgs;
@@ -107,6 +108,7 @@ class CompositorDelegateForInput {
virtual void DidScrollContent(ElementId element_id, bool animated) = 0;
virtual float DeviceScaleFactor() const = 0;
virtual float PageScaleFactor() const = 0;
+ virtual gfx::Size VisualDeviceViewportSize() const = 0;
virtual const LayerTreeSettings& GetSettings() const = 0;
// TODO(bokan): Temporary escape hatch for code that hasn't yet been
diff --git a/chromium/cc/input/input_handler.h b/chromium/cc/input/input_handler.h
index aeec0fbc1a7..5460c76c716 100644
--- a/chromium/cc/input/input_handler.h
+++ b/chromium/cc/input/input_handler.h
@@ -176,6 +176,8 @@ class CC_EXPORT InputHandler {
SCROLL_ON_MAIN_THREAD = 0,
SCROLL_ON_IMPL_THREAD,
SCROLL_IGNORED,
+ // SCROLL_UNKOWN is not used anymore. However we'll keep this entry as per
+ // the comment above.
SCROLL_UNKNOWN,
LAST_SCROLL_STATUS = SCROLL_UNKNOWN
};
@@ -195,9 +197,17 @@ class CC_EXPORT InputHandler {
main_thread_scrolling_reasons(main_thread_scrolling_reasons),
needs_main_thread_hit_test(needs_main_thread_hit_test) {}
ScrollThread thread = ScrollThread::SCROLL_ON_IMPL_THREAD;
+ // TODO(crbug.com/1155663): Make sure to set main_thread_scrolling_reasons
+ // only when ScrollStatus.thread is set to
+ // InputHander::ScrollThread::SCROLL_ON_MAIN_THREAD
uint32_t main_thread_scrolling_reasons =
MainThreadScrollingReason::kNotScrollingOnMain;
- bool bubble = false;
+ // TODO(crbug.com/1155758): This is a temporary workaround for GuestViews
+ // as they create viewport nodes and want to bubble scroll if the
+ // viewport cannot scroll in the given delta directions. There should be
+ // a parameter to ThreadInputHandler to specify whether unused delta is
+ // consumed by the viewport or bubbles to the parent.
+ bool viewport_cannot_scroll = false;
// Used only in scroll unification. Tells the caller that the input handler
// detected a case where it cannot reliably target a scroll node and needs
@@ -262,6 +272,7 @@ class CC_EXPORT InputHandler {
ScrollBeginThreadState scroll_start_state) = 0;
virtual void RecordScrollEnd(ui::ScrollInputType input_type) = 0;
+ virtual PointerResultType HitTest(const gfx::PointF& mouse_position) = 0;
virtual InputHandlerPointerResult MouseMoveAt(
const gfx::Point& mouse_position) = 0;
// TODO(arakeri): Pass in the modifier instead of a bool once the refactor
diff --git a/chromium/cc/input/main_thread_scrolling_reason.cc b/chromium/cc/input/main_thread_scrolling_reason.cc
index abd24047855..0d0d0c2a57a 100644
--- a/chromium/cc/input/main_thread_scrolling_reason.cc
+++ b/chromium/cc/input/main_thread_scrolling_reason.cc
@@ -32,16 +32,10 @@ void MainThreadScrollingReason::AddToTracedValue(
if (reasons & kHasBackgroundAttachmentFixedObjects)
traced_value.AppendString("Has background-attachment:fixed");
- if (reasons & kHasNonLayerViewportConstrainedObjects)
- traced_value.AppendString("Has non-layer viewport-constrained objects");
if (reasons & kThreadedScrollingDisabled)
traced_value.AppendString("Threaded scrolling is disabled");
if (reasons & kScrollbarScrolling)
traced_value.AppendString("Scrollbar scrolling");
- if (reasons & kFrameOverlay)
- traced_value.AppendString("Frame overlay");
- if (reasons & kHandlingScrollFromMainThread)
- traced_value.AppendString("Handling scroll from main thread");
if (reasons & kNotOpaqueForTextAndLCDText)
traced_value.AppendString("Not opaque for text and LCD text");
if (reasons & kCantPaintScrollingBackgroundAndLCDText)
@@ -56,12 +50,8 @@ void MainThreadScrollingReason::AddToTracedValue(
traced_value.AppendString("No scrolling layer");
if (reasons & kNotScrollable)
traced_value.AppendString("Not scrollable");
- if (reasons & kContinuingMainThreadScroll)
- traced_value.AppendString("Continuing main thread scroll");
if (reasons & kNonInvertibleTransform)
traced_value.AppendString("Non-invertible transform");
- if (reasons & kPageBasedScrolling)
- traced_value.AppendString("Page-based scrolling");
if (reasons & kWheelEventHandlerRegion)
traced_value.AppendString("Wheel event handler region");
if (reasons & kTouchEventHandlerRegion)
diff --git a/chromium/cc/input/main_thread_scrolling_reason.h b/chromium/cc/input/main_thread_scrolling_reason.h
index 4ddd536afcc..0378bdac161 100644
--- a/chromium/cc/input/main_thread_scrolling_reason.h
+++ b/chromium/cc/input/main_thread_scrolling_reason.h
@@ -17,52 +17,43 @@ class TracedValue;
namespace cc {
-// Ensure this stays in sync with MainThreadScrollingReason in histograms.xml.
-// When adding a new MainThreadScrollingReason, make sure the corresponding
-// [MainThread/Compositor]CanSetScrollReasons function is also updated.
+// Ensure this stays in sync with MainThreadScrollingReason in
+// tools/metrics/enums.xml. When adding a new MainThreadScrollingReason, make
+// sure the corresponding [MainThread/Compositor]CanSetScrollReasons function
+// is also updated.
struct CC_EXPORT MainThreadScrollingReason {
enum : uint32_t {
kNotScrollingOnMain = 0,
+ // 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.
+ // See also blink::RecordScrollReasonsMetric().
+
// Non-transient scrolling reasons.
- kHasBackgroundAttachmentFixedObjects = 1 << 0,
- kHasNonLayerViewportConstrainedObjects = 1 << 1,
- kThreadedScrollingDisabled = 1 << 2,
- kScrollbarScrolling = 1 << 3,
- kFrameOverlay = 1 << 4,
-
- // This bit is set when any of the other main thread scrolling reasons cause
- // an input event to be handled on the main thread, and the main thread
- // blink::ScrollAnimator is in the middle of running a scroll offset
- // animation. Note that a scroll handled by the main thread can result in an
- // animation running on the main thread or on the compositor thread.
- kHandlingScrollFromMainThread = 1 << 13,
+ kHasBackgroundAttachmentFixedObjects = 1 << 1,
+ kThreadedScrollingDisabled = 1 << 3,
// Style-related scrolling on main reasons.
// These *AndLCDText reasons are due to subpixel text rendering which can
// only be applied by blending glyphs with the background at a specific
// screen position; transparency and transforms break this.
- kNonCompositedReasonsFirst = 17,
- kNotOpaqueForTextAndLCDText = 1 << 18,
- kCantPaintScrollingBackgroundAndLCDText = 1 << 19,
- kNonCompositedReasonsLast = 22,
+ kNonCompositedReasonsFirst = 18,
+ kNotOpaqueForTextAndLCDText = 1 << 19,
+ kCantPaintScrollingBackgroundAndLCDText = 1 << 20,
+ kNonCompositedReasonsLast = 23,
// Transient scrolling reasons. These are computed for each scroll begin.
- kNonFastScrollableRegion = 1 << 5,
- kFailedHitTest = 1 << 7,
- kNoScrollingLayer = 1 << 8,
- kNotScrollable = 1 << 9,
- kContinuingMainThreadScroll = 1 << 10,
- kNonInvertibleTransform = 1 << 11,
- kPageBasedScrolling = 1 << 12,
- kWheelEventHandlerRegion = 1 << 23,
- kTouchEventHandlerRegion = 1 << 24,
-
- // The maximum number of flags in this struct (excluding itself).
- // New flags should increment this number but it should never be decremented
- // because the values are used in UMA histograms. It should also be noted
- // that it excludes the kNotScrollingOnMain value.
- kMainThreadScrollingReasonCount = 25,
+ kScrollbarScrolling = 1 << 4,
+ kNonFastScrollableRegion = 1 << 6,
+ kFailedHitTest = 1 << 8,
+ kNoScrollingLayer = 1 << 9,
+ kNotScrollable = 1 << 10,
+ kNonInvertibleTransform = 1 << 12,
+ kWheelEventHandlerRegion = 1 << 24,
+ kTouchEventHandlerRegion = 1 << 25,
+
+ kMainThreadScrollingReasonLast = 25,
};
static const uint32_t kNonCompositedReasons =
@@ -71,20 +62,17 @@ struct CC_EXPORT MainThreadScrollingReason {
// Returns true if the given MainThreadScrollingReason can be set by the main
// thread.
static bool MainThreadCanSetScrollReasons(uint32_t reasons) {
- uint32_t reasons_set_by_main_thread =
- kNotScrollingOnMain | kHasBackgroundAttachmentFixedObjects |
- kHasNonLayerViewportConstrainedObjects | kThreadedScrollingDisabled |
- kScrollbarScrolling | kFrameOverlay | kHandlingScrollFromMainThread;
+ constexpr uint32_t reasons_set_by_main_thread =
+ kHasBackgroundAttachmentFixedObjects | kThreadedScrollingDisabled;
return (reasons & reasons_set_by_main_thread) == reasons;
}
// Returns true if the given MainThreadScrollingReason can be set by the
// compositor.
static bool CompositorCanSetScrollReasons(uint32_t reasons) {
- uint32_t reasons_set_by_compositor =
+ constexpr uint32_t reasons_set_by_compositor =
kNonFastScrollableRegion | kFailedHitTest | kNoScrollingLayer |
- kNotScrollable | kContinuingMainThreadScroll | kNonInvertibleTransform |
- kPageBasedScrolling | kWheelEventHandlerRegion |
+ kNotScrollable | kNonInvertibleTransform | kWheelEventHandlerRegion |
kTouchEventHandlerRegion;
return (reasons & reasons_set_by_compositor) == reasons;
}
diff --git a/chromium/cc/input/main_thread_scrolling_reason_unittest.cc b/chromium/cc/input/main_thread_scrolling_reason_unittest.cc
index becbfe296db..282ef9ac64a 100644
--- a/chromium/cc/input/main_thread_scrolling_reason_unittest.cc
+++ b/chromium/cc/input/main_thread_scrolling_reason_unittest.cc
@@ -14,20 +14,15 @@ TEST_F(MainThreadScrollingReasonTest, AsText) {
EXPECT_EQ("", MainThreadScrollingReason::AsText(0));
EXPECT_EQ(
"Has background-attachment:fixed, "
- "Has non-layer viewport-constrained objects, "
"Threaded scrolling is disabled, "
"Scrollbar scrolling, "
- "Frame overlay, "
- "Handling scroll from main thread, "
"Not opaque for text and LCD text, "
"Can't paint scrolling background and LCD text, "
"Non fast scrollable region, "
"Failed hit test, "
"No scrolling layer, "
"Not scrollable, "
- "Continuing main thread scroll, "
"Non-invertible transform, "
- "Page-based scrolling, "
"Wheel event handler region, "
"Touch event handler region",
MainThreadScrollingReason::AsText(0xffffffffu));
diff --git a/chromium/cc/input/scrollbar_controller.cc b/chromium/cc/input/scrollbar_controller.cc
index 75f786b67c1..7cd1f44f02a 100644
--- a/chromium/cc/input/scrollbar_controller.cc
+++ b/chromium/cc/input/scrollbar_controller.cc
@@ -50,26 +50,22 @@ ScrollbarLayerImplBase* ScrollbarController::ScrollbarLayer() const {
return nullptr;
}
-// Performs hit test and prepares scroll deltas that will be used by GSB and
-// GSU.
-InputHandlerPointerResult ScrollbarController::HandlePointerDown(
- const gfx::PointF position_in_widget,
- bool jump_key_modifier) {
- LayerImpl* layer_impl = GetLayerHitByPoint(position_in_widget);
-
+PointerResultType ScrollbarController::HitTest(
+ const gfx::PointF position_in_widget) const {
// If a non-custom scrollbar layer was not found, we return early as there is
// no point in setting additional state in the ScrollbarController. Return an
// empty InputHandlerPointerResult in this case so that when it is bubbled up
// to InputHandlerProxy::RouteToTypeSpecificHandler, the pointer event gets
// passed on to the main thread.
+ const LayerImpl* layer_impl = GetLayerHitByPoint(position_in_widget);
if (!(layer_impl && layer_impl->IsScrollbarLayer()))
- return InputHandlerPointerResult();
+ return PointerResultType::kUnhandled;
// If the scrollbar layer has faded out (eg: Overlay scrollbars), don't
// initiate a scroll.
const ScrollbarLayerImplBase* scrollbar = ToScrollbarLayer(layer_impl);
if (scrollbar->OverlayScrollbarOpacity() == 0.f)
- return InputHandlerPointerResult();
+ return PointerResultType::kUnhandled;
// If the scroll_node has a main_thread_scrolling_reason, don't initiate a
// scroll.
@@ -78,8 +74,23 @@ InputHandlerPointerResult ScrollbarController::HandlePointerDown(
->property_trees()
->scroll_tree.FindNodeFromElementId(scrollbar->scroll_element_id());
if (target_node->main_thread_scrolling_reasons)
+ return PointerResultType::kUnhandled;
+
+ return PointerResultType::kScrollbarScroll;
+}
+
+// Performs hit test and prepares scroll deltas that will be used by GSB and
+// GSU.
+InputHandlerPointerResult ScrollbarController::HandlePointerDown(
+ const gfx::PointF position_in_widget,
+ bool jump_key_modifier) {
+ if (HitTest(position_in_widget) != PointerResultType::kScrollbarScroll)
return InputHandlerPointerResult();
+ // TODO(arakeri): GetLayerHitByPoint should ideally be called only once per
+ // pointerdown. This needs to be optimized. See crbug.com/1156922.
+ const ScrollbarLayerImplBase* scrollbar =
+ ToScrollbarLayer(GetLayerHitByPoint(position_in_widget));
captured_scrollbar_metadata_ = CapturedScrollbarMetadata();
captured_scrollbar_metadata_->scroll_element_id =
scrollbar->scroll_element_id();
@@ -255,7 +266,7 @@ float ScrollbarController::GetScrollDeltaForAbsoluteJump() const {
return delta * GetScrollerToScrollbarRatio() * GetPageScaleFactorForScroll();
}
-int ScrollbarController::GetScrollDeltaForDragPosition(
+float ScrollbarController::GetScrollDeltaForDragPosition(
const gfx::PointF pointer_position_in_widget) const {
const ScrollbarLayerImplBase* scrollbar = ScrollbarLayer();
// Convert the move position to scrollbar layer relative for comparison with
@@ -278,9 +289,7 @@ int ScrollbarController::GetScrollDeltaForDragPosition(
// correct amount, we have to convert the delta to be unscaled (i.e. multiply
// by the page scale factor), as GSU deltas are always unscaled.
scroll_delta *= GetPageScaleFactorForScroll();
-
- // Scroll delta floored to match main thread per pixel behavior
- return floorf(scroll_delta);
+ return scroll_delta;
}
// Performs hit test and prepares scroll deltas that will be used by GSU.
@@ -333,7 +342,7 @@ InputHandlerPointerResult ScrollbarController::HandlePointerMove(
// valid ScrollNode.
DCHECK(target_node);
- int delta = GetScrollDeltaForDragPosition(position_in_widget);
+ float delta = GetScrollDeltaForDragPosition(position_in_widget);
if (drag_state_->scroller_length_at_previous_move !=
scrollbar->scroll_layer_length()) {
drag_state_->scroller_displacement = delta;
@@ -436,7 +445,7 @@ float ScrollbarController::GetScrollerToScrollbarRatio() const {
scrollbar->orientation() == ScrollbarOrientation::VERTICAL
? thumb_rect.height()
: thumb_rect.width();
- int viewport_length = GetViewportLength();
+ float viewport_length = GetViewportLength();
return (scroll_layer_length - viewport_length) /
(scrollbar_track_length - scrollbar_thumb_length);
@@ -590,6 +599,7 @@ void ScrollbarController::StartAutoScrollAnimation(
? AutoScrollDirection::AUTOSCROLL_BACKWARD
: AutoScrollDirection::AUTOSCROLL_FORWARD;
+ layer_tree_host_impl_->mutator_host()->ScrollAnimationAbort();
layer_tree_host_impl_->AutoScrollAnimationCreate(
*scroll_node, target_offset_vector, std::abs(velocity));
}
@@ -627,7 +637,7 @@ LayerImpl* ScrollbarController::GetLayerHitByPoint(
return layer_impl;
}
-int ScrollbarController::GetViewportLength() const {
+float ScrollbarController::GetViewportLength() const {
const ScrollbarLayerImplBase* scrollbar = ScrollbarLayer();
const ScrollNode* scroll_node =
layer_tree_host_impl_->active_tree()
@@ -649,7 +659,7 @@ int ScrollbarController::GetViewportLength() const {
return length / GetPageScaleFactorForScroll();
}
-int ScrollbarController::GetScrollDeltaForPercentBasedScroll() const {
+float ScrollbarController::GetScrollDeltaForPercentBasedScroll() const {
const ScrollbarLayerImplBase* scrollbar = ScrollbarLayer();
const ScrollNode* scroll_node =
@@ -677,10 +687,10 @@ float ScrollbarController::GetPageScaleFactorForScroll() const {
return layer_tree_host_impl_->active_tree()->page_scale_factor_for_scroll();
}
-int ScrollbarController::GetScrollDeltaForScrollbarPart(
+float ScrollbarController::GetScrollDeltaForScrollbarPart(
const ScrollbarPart scrollbar_part,
const bool jump_key_modifier) const {
- int scroll_delta = 0;
+ float scroll_delta = 0;
switch (scrollbar_part) {
case ScrollbarPart::BACK_BUTTON:
diff --git a/chromium/cc/input/scrollbar_controller.h b/chromium/cc/input/scrollbar_controller.h
index fb827f06a48..6d15cbcd295 100644
--- a/chromium/cc/input/scrollbar_controller.h
+++ b/chromium/cc/input/scrollbar_controller.h
@@ -148,10 +148,13 @@ class CC_EXPORT ScrollbarController {
ScrollbarLayerImplBase* ScrollbarLayer() const;
void WillBeginImplFrame();
void ResetState();
+ PointerResultType HitTest(const gfx::PointF position_in_widget) const;
private:
FRIEND_TEST_ALL_PREFIXES(ScrollUnifiedLayerTreeHostImplTest,
ThumbDragAfterJumpClick);
+ FRIEND_TEST_ALL_PREFIXES(ScrollUnifiedLayerTreeHostImplTest,
+ AbortAnimatedScrollBeforeStartingAutoscroll);
// "Autoscroll" here means the continuous scrolling that occurs when the
// pointer is held down on a hit-testable area of the scrollbar such as an
@@ -232,8 +235,8 @@ class CC_EXPORT ScrollbarController {
gfx::Rect GetRectForScrollbarPart(const ScrollbarPart scrollbar_part) const;
LayerImpl* GetLayerHitByPoint(const gfx::PointF position_in_widget) const;
- int GetScrollDeltaForScrollbarPart(const ScrollbarPart scrollbar_part,
- const bool jump_key_modifier) const;
+ float GetScrollDeltaForScrollbarPart(const ScrollbarPart scrollbar_part,
+ const bool jump_key_modifier) const;
// Makes position_in_widget relative to the scrollbar.
gfx::PointF GetScrollbarRelativePosition(const gfx::PointF position_in_widget,
@@ -257,17 +260,17 @@ class CC_EXPORT ScrollbarController {
bool jump_key_modifier) const;
// Calculates the delta based on position_in_widget and drag_origin.
- int GetScrollDeltaForDragPosition(
+ float GetScrollDeltaForDragPosition(
const gfx::PointF pointer_position_in_widget) const;
// Returns the ratio of the scroller length to the scrollbar length. This is
// needed to scale the scroll delta for thumb drag.
float GetScrollerToScrollbarRatio() const;
- int GetViewportLength() const;
+ float GetViewportLength() const;
// Returns the pixel delta for a percent-based scroll of the scrollbar
- int GetScrollDeltaForPercentBasedScroll() const;
+ float GetScrollDeltaForPercentBasedScroll() const;
// Returns the page scale factor (i.e. pinch zoom factor). This is relevant
// for root viewport scrollbar scrolling.
diff --git a/chromium/cc/input/snap_selection_strategy.cc b/chromium/cc/input/snap_selection_strategy.cc
index 704e07d384b..b99b3de4938 100644
--- a/chromium/cc/input/snap_selection_strategy.cc
+++ b/chromium/cc/input/snap_selection_strategy.cc
@@ -124,18 +124,18 @@ bool DirectionStrategy::IsValidSnapPosition(SearchAxis axis,
float position) const {
// If not using fractional offsets then it is possible for the currently
// snapped area's offset, which is fractional, to not be equal to the current
- // scroll offset, which is not fractional. Therefore we round the offsets so
- // that any position within 0.5 of the current position is ignored.
+ // scroll offset, which is not fractional. Therefore we truncate the offsets
+ // so that any position within 1 of the current position is ignored.
if (axis == SearchAxis::kX) {
float delta = position - current_position_.x();
if (!use_fractional_offsets_)
- delta = std::round(delta);
+ delta = delta > 0 ? std::floor(delta) : std::ceil(delta);
return (step_.x() > 0 && delta > 0) || // "Right" arrow
(step_.x() < 0 && delta < 0); // "Left" arrow
} else {
float delta = position - current_position_.y();
if (!use_fractional_offsets_)
- delta = std::round(delta);
+ delta = delta > 0 ? std::floor(delta) : std::ceil(delta);
return (step_.y() > 0 && delta > 0) || // "Down" arrow
(step_.y() < 0 && delta < 0); // "Up" arrow
}
diff --git a/chromium/cc/input/threaded_input_handler.cc b/chromium/cc/input/threaded_input_handler.cc
index f1510a7281e..a22f04db5f7 100644
--- a/chromium/cc/input/threaded_input_handler.cc
+++ b/chromium/cc/input/threaded_input_handler.cc
@@ -249,7 +249,8 @@ InputHandler::ScrollStatus ThreadedInputHandler::ScrollBegin(
layer_impl, first_scrolling_layer_or_scrollbar)) {
TRACE_EVENT_INSTANT0("cc", "Failed Hit Test",
TRACE_EVENT_SCOPE_THREAD);
- scroll_status.thread = InputHandler::ScrollThread::SCROLL_UNKNOWN;
+ scroll_status.thread =
+ InputHandler::ScrollThread::SCROLL_ON_MAIN_THREAD;
scroll_status.main_thread_scrolling_reasons =
MainThreadScrollingReason::kFailedHitTest;
return scroll_status;
@@ -277,15 +278,17 @@ InputHandler::ScrollStatus ThreadedInputHandler::ScrollBegin(
scroll_status.thread = InputHandler::ScrollThread::SCROLL_ON_MAIN_THREAD;
return scroll_status;
} else if (!scrolling_node) {
+ // TODO(crbug.com/1155663): Make sure to set main_thread_scrolling_reasons
+ // only when ScrollStatus.thread is set to
+ // InputHander::ScrollThread::SCROLL_ON_MAIN_THREAD
scroll_status.main_thread_scrolling_reasons =
MainThreadScrollingReason::kNoScrollingLayer;
if (compositor_delegate_.GetSettings().is_layer_tree_for_subframe) {
// OOPIFs never have a viewport scroll node so if we can't scroll
// we need to be bubble up to the parent frame. This happens by
- // returning SCROLL_UNKNOWN.
+ // returning SCROLL_IGNORED.
TRACE_EVENT_INSTANT0("cc", "Ignored - No ScrollNode (OOPIF)",
TRACE_EVENT_SCOPE_THREAD);
- scroll_status.thread = InputHandler::ScrollThread::SCROLL_UNKNOWN;
} else {
// If we didn't hit a layer above we'd usually fallback to the
// viewport scroll node. However, there may not be one if a scroll
@@ -295,8 +298,8 @@ InputHandler::ScrollStatus ThreadedInputHandler::ScrollBegin(
// configurations where input is allowed prior to a commit.
TRACE_EVENT_INSTANT0("cc", "Ignored - No ScrollNode",
TRACE_EVENT_SCOPE_THREAD);
- scroll_status.thread = InputHandler::ScrollThread::SCROLL_IGNORED;
}
+ scroll_status.thread = InputHandler::ScrollThread::SCROLL_IGNORED;
return scroll_status;
}
@@ -314,7 +317,12 @@ InputHandler::ScrollStatus ThreadedInputHandler::ScrollBegin(
// oopif.
if (GetViewport().ShouldScroll(*CurrentlyScrollingNode()) &&
!GetViewport().CanScroll(*CurrentlyScrollingNode(), *scroll_state)) {
- scroll_status.bubble = true;
+ // TODO(crbug.com/1155758): This is a temporary workaround for GuestViews
+ // as they create viewport nodes and want to bubble scroll if the
+ // viewport cannot scroll in the given delta directions. There should be
+ // a parameter to ThreadInputHandler to specify whether unused delta is
+ // consumed by the viewport or bubbles to the parent.
+ scroll_status.viewport_cannot_scroll = true;
}
return scroll_status;
@@ -575,6 +583,14 @@ InputHandlerPointerResult ThreadedInputHandler::MouseMoveAt(
return result;
}
+PointerResultType ThreadedInputHandler::HitTest(
+ const gfx::PointF& viewport_point) {
+ return compositor_delegate_.GetSettings()
+ .compositor_threaded_scrollbar_scrolling
+ ? scrollbar_controller_->HitTest(viewport_point)
+ : PointerResultType::kUnhandled;
+}
+
InputHandlerPointerResult ThreadedInputHandler::MouseDown(
const gfx::PointF& viewport_point,
bool shift_modifier) {
@@ -951,11 +967,14 @@ void ThreadedInputHandler::ProcessCommitDeltas(
commit_data->manipulation_info |= kManipulationInfoPrecisionTouchPad;
if (has_pinch_zoomed_)
commit_data->manipulation_info |= kManipulationInfoPinchZoom;
+ if (has_scrolled_by_scrollbar_)
+ commit_data->manipulation_info |= kManipulationInfoScrollbar;
has_scrolled_by_wheel_ = false;
has_scrolled_by_touch_ = false;
has_scrolled_by_precisiontouchpad_ = false;
has_pinch_zoomed_ = false;
+ has_scrolled_by_scrollbar_ = false;
commit_data->scroll_gesture_did_end = scroll_gesture_did_end_;
scroll_gesture_did_end_ = false;
@@ -1170,16 +1189,16 @@ gfx::Vector2dF ThreadedInputHandler::ResolveScrollGranularityToPixels(
if (granularity == ui::ScrollGranularity::kScrollByPercentage) {
gfx::SizeF scroller_size = gfx::SizeF(scroll_node.container_bounds);
-
- gfx::SizeF viewport_size =
- InnerViewportScrollNode()
- ? gfx::SizeF(InnerViewportScrollNode()->container_bounds)
- : gfx::SizeF(ActiveTree().GetDeviceViewport().size());
+ gfx::SizeF viewport_size(compositor_delegate_.VisualDeviceViewportSize());
// Convert from rootframe coordinates to screen coordinates (physical
- // pixels).
+ // pixels if --use-zoom-for-dsf enabled, DIPs otherwise).
scroller_size.Scale(compositor_delegate_.PageScaleFactor());
+ // Convert from physical pixels to screen coordinates (if --use-zoom-for-dsf
+ // enabled, `DeviceScaleFactor()` returns 1).
+ viewport_size.Scale(1 / compositor_delegate_.DeviceScaleFactor());
+
pixel_delta = ScrollUtils::ResolveScrollPercentageToPixels(
pixel_delta, scroller_size, viewport_size);
}
@@ -1823,6 +1842,7 @@ ScrollNode* ThreadedInputHandler::FindNodeToLatch(ScrollState* scroll_state,
ui::ScrollInputType type) {
ScrollTree& scroll_tree = GetScrollTree();
ScrollNode* scroll_node = nullptr;
+ ScrollNode* first_scrollable_node = nullptr;
for (ScrollNode* cur_node = starting_node; cur_node;
cur_node = scroll_tree.parent(cur_node)) {
if (GetViewport().ShouldScroll(*cur_node)) {
@@ -1836,10 +1856,11 @@ ScrollNode* ThreadedInputHandler::FindNodeToLatch(ScrollState* scroll_state,
if (!cur_node->scrollable)
continue;
- // For UX reasons, autoscrolling should always latch to the top-most
- // scroller, even if it can't scroll in the initial direction.
- if (type == ui::ScrollInputType::kAutoscroll ||
- CanConsumeDelta(*scroll_state, *cur_node)) {
+ if (!first_scrollable_node) {
+ first_scrollable_node = cur_node;
+ }
+
+ if (CanConsumeDelta(*scroll_state, *cur_node)) {
scroll_node = cur_node;
break;
}
@@ -1861,6 +1882,14 @@ ScrollNode* ThreadedInputHandler::FindNodeToLatch(ScrollState* scroll_state,
}
}
+ // If the root scroller can not consume delta in an autoscroll, latch on
+ // to the top most autoscrollable scroller. See https://crbug.com/969150
+ if ((type == ui::ScrollInputType::kAutoscroll) && first_scrollable_node) {
+ // If scroll_node is nullptr or delta can not be consumed
+ if (!(scroll_node && CanConsumeDelta(*scroll_state, *scroll_node)))
+ scroll_node = first_scrollable_node;
+ }
+
return scroll_node;
}
@@ -2093,6 +2122,8 @@ void ThreadedInputHandler::UpdateScrollSourceInfo(
has_scrolled_by_wheel_ = true;
} else if (type == ui::ScrollInputType::kTouchscreen) {
has_scrolled_by_touch_ = true;
+ } else if (type == ui::ScrollInputType::kScrollbar) {
+ has_scrolled_by_scrollbar_ = true;
}
}
diff --git a/chromium/cc/input/threaded_input_handler.h b/chromium/cc/input/threaded_input_handler.h
index d84d2ebd8ce..80b33189b2f 100644
--- a/chromium/cc/input/threaded_input_handler.h
+++ b/chromium/cc/input/threaded_input_handler.h
@@ -56,6 +56,7 @@ class CC_EXPORT ThreadedInputHandler : public InputHandler,
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;
@@ -168,6 +169,8 @@ class CC_EXPORT ThreadedInputHandler : public InputHandler,
private:
FRIEND_TEST_ALL_PREFIXES(ScrollUnifiedLayerTreeHostImplTest,
+ AbortAnimatedScrollBeforeStartingAutoscroll);
+ FRIEND_TEST_ALL_PREFIXES(ScrollUnifiedLayerTreeHostImplTest,
AnimatedScrollYielding);
FRIEND_TEST_ALL_PREFIXES(ScrollUnifiedLayerTreeHostImplTest,
AutoscrollOnDeletedScrollbar);
@@ -434,6 +437,7 @@ class CC_EXPORT ThreadedInputHandler : public InputHandler,
bool has_scrolled_by_wheel_ = false;
bool has_scrolled_by_touch_ = false;
bool has_scrolled_by_precisiontouchpad_ = false;
+ bool has_scrolled_by_scrollbar_ = false;
// Must be the last member to ensure this is destroyed first in the
// destruction order and invalidates all weak pointers.
diff --git a/chromium/cc/ipc/cc_param_traits_macros.h b/chromium/cc/ipc/cc_param_traits_macros.h
index af561bb6feb..146444cde30 100644
--- a/chromium/cc/ipc/cc_param_traits_macros.h
+++ b/chromium/cc/ipc/cc_param_traits_macros.h
@@ -6,6 +6,7 @@
#define CC_IPC_CC_PARAM_TRAITS_MACROS_H_
#include "base/component_export.h"
+#include "cc/input/browser_controls_state.h"
#include "cc/input/overscroll_behavior.h"
#include "cc/input/touch_action.h"
#include "cc/trees/browser_controls_params.h"
@@ -34,4 +35,7 @@ IPC_STRUCT_TRAITS_BEGIN(cc::BrowserControlsParams)
IPC_STRUCT_TRAITS_MEMBER(only_expand_top_controls_at_page_top)
IPC_STRUCT_TRAITS_END()
+IPC_ENUM_TRAITS_MAX_VALUE(cc::BrowserControlsState,
+ cc::BrowserControlsState::kMaxValue)
+
#endif // CC_IPC_CC_PARAM_TRAITS_MACROS_H_
diff --git a/chromium/cc/layers/content_layer_client.h b/chromium/cc/layers/content_layer_client.h
index e7643fc5cf4..25d1a33757c 100644
--- a/chromium/cc/layers/content_layer_client.h
+++ b/chromium/cc/layers/content_layer_client.h
@@ -22,7 +22,7 @@ class CC_EXPORT ContentLayerClient {
// layer this client paints, that the client is capable of painting via
// paintContents(). Calling paintContents() will return a DisplayItemList
// that is guaranteed valid only within this region.
- virtual gfx::Rect PaintableRegion() = 0;
+ virtual gfx::Rect PaintableRegion() const = 0;
// Paints the content area for the layer, typically dirty rects submitted
// to the layer itself, into a DisplayItemList that it returns. The
diff --git a/chromium/cc/layers/heads_up_display_layer.cc b/chromium/cc/layers/heads_up_display_layer.cc
index 0c56668a44f..09dbbd9e4d2 100644
--- a/chromium/cc/layers/heads_up_display_layer.cc
+++ b/chromium/cc/layers/heads_up_display_layer.cc
@@ -5,6 +5,8 @@
#include "cc/layers/heads_up_display_layer.h"
#include <algorithm>
+#include <utility>
+#include <vector>
#include "base/trace_event/trace_event.h"
#include "cc/layers/heads_up_display_layer_impl.h"
@@ -37,13 +39,21 @@ void HeadsUpDisplayLayer::UpdateLocationAndSize(
gfx::Size bounds;
- if (layer_tree_host()->GetDebugState().ShowHudRects()) {
+ // If the HUD is not displaying full-viewport rects (e.g., it is showing the
+ // Frame Rendering Stats), use a fixed size.
+ constexpr int kDefaultHUDSize = 256;
+ bounds.SetSize(kDefaultHUDSize, kDefaultHUDSize);
+
+ if (layer_tree_host()->GetDebugState().ShowDebugRects()) {
bounds = device_viewport_in_layout_pixels;
- } else {
- // If the HUD is not displaying full-viewport rects (e.g., it is showing the
- // Frame Rendering Stats), use a fixed size.
- constexpr int kDefaultHUDSize = 256;
- bounds.SetSize(kDefaultHUDSize, kDefaultHUDSize);
+ } else if (layer_tree_host()->GetDebugState().show_web_vital_metrics ||
+ layer_tree_host()->GetDebugState().show_smoothness_metrics) {
+ // If the HUD is used to display performance metrics (which is on the right
+ // hand side_, make sure the bounds has the correct width, with a fixed
+ // height.
+ bounds.set_width(device_viewport_in_layout_pixels.width());
+ // Increase HUD layer height to make sure all the metrics are showing.
+ bounds.set_height(kDefaultHUDSize * 2);
}
SetBounds(bounds);
@@ -67,6 +77,11 @@ void HeadsUpDisplayLayer::SetLayoutShiftRects(
layout_shift_rects_ = rects;
}
+void HeadsUpDisplayLayer::UpdateWebVitalMetrics(
+ std::unique_ptr<WebVitalMetrics> web_vital_metrics) {
+ web_vital_metrics_ = std::move(web_vital_metrics);
+}
+
void HeadsUpDisplayLayer::PushPropertiesTo(LayerImpl* layer) {
Layer::PushPropertiesTo(layer);
TRACE_EVENT0("cc", "HeadsUpDisplayLayer::PushPropertiesTo");
@@ -76,6 +91,8 @@ void HeadsUpDisplayLayer::PushPropertiesTo(LayerImpl* layer) {
layer_impl->SetHUDTypeface(typeface_);
layer_impl->SetLayoutShiftRects(layout_shift_rects_);
layout_shift_rects_.clear();
+ if (web_vital_metrics_ && web_vital_metrics_->HasValue())
+ layer_impl->SetWebVitalMetrics(std::move(web_vital_metrics_));
}
} // namespace cc
diff --git a/chromium/cc/layers/heads_up_display_layer.h b/chromium/cc/layers/heads_up_display_layer.h
index 1dea4e99e44..9d497439259 100644
--- a/chromium/cc/layers/heads_up_display_layer.h
+++ b/chromium/cc/layers/heads_up_display_layer.h
@@ -7,9 +7,11 @@
#include <memory>
#include <string>
+#include <vector>
#include "cc/cc_export.h"
#include "cc/layers/layer.h"
+#include "cc/metrics/web_vital_metrics.h"
#include "third_party/skia/include/core/SkRefCnt.h"
#include "third_party/skia/include/core/SkTypeface.h"
#include "ui/gfx/geometry/rect.h"
@@ -25,6 +27,8 @@ class CC_EXPORT HeadsUpDisplayLayer : public Layer {
void UpdateLocationAndSize(const gfx::Size& device_viewport,
float device_scale_factor);
+ void UpdateWebVitalMetrics(
+ std::unique_ptr<WebVitalMetrics> web_vital_metrics);
const std::vector<gfx::Rect>& LayoutShiftRects() const;
void SetLayoutShiftRects(const std::vector<gfx::Rect>& rects);
@@ -43,6 +47,8 @@ class CC_EXPORT HeadsUpDisplayLayer : public Layer {
sk_sp<SkTypeface> typeface_;
std::vector<gfx::Rect> layout_shift_rects_;
+
+ std::unique_ptr<WebVitalMetrics> web_vital_metrics_;
};
} // namespace cc
diff --git a/chromium/cc/layers/heads_up_display_layer_impl.cc b/chromium/cc/layers/heads_up_display_layer_impl.cc
index 3e5cc2b7319..de7936aad42 100644
--- a/chromium/cc/layers/heads_up_display_layer_impl.cc
+++ b/chromium/cc/layers/heads_up_display_layer_impl.cc
@@ -8,6 +8,7 @@
#include <stdint.h>
#include <algorithm>
+#include <iomanip>
#include <utility>
#include <vector>
@@ -20,6 +21,7 @@
#include "base/trace_event/process_memory_dump.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/traced_value.h"
+#include "build/build_config.h"
#include "cc/debug/debug_colors.h"
#include "cc/metrics/dropped_frame_counter.h"
#include "cc/paint/display_item_list.h"
@@ -90,6 +92,35 @@ class DummyImageProvider : public ImageProvider {
}
};
+std::string ToStringTwoDecimalPrecision(double input) {
+ std::stringstream stream;
+ stream << std::fixed << std::setprecision(2) << input;
+ return stream.str();
+}
+
+#if defined(OS_ANDROID)
+struct MetricsDrawSizes {
+ const int kTopPadding = 35;
+ const int kPadding = 15;
+ const int kFontHeight = 32;
+ const int kWidth = 500;
+ const int kSidePadding = 20;
+} constexpr metrics_sizes;
+#else
+struct MetricsDrawSizes {
+ const int kTopPadding = 35;
+ const int kPadding = 15;
+ const int kFontHeight = 22;
+ const int kWidth = 400;
+ const int kSidePadding = 20;
+} constexpr metrics_sizes;
+#endif
+
+constexpr int ComputeTotalHeight(int num_of_lines) {
+ int num_of_spaces = std::max(0, num_of_lines - 1);
+ return num_of_lines * metrics_sizes.kFontHeight +
+ num_of_spaces * metrics_sizes.kPadding + 2 * metrics_sizes.kTopPadding;
+}
} // namespace
HeadsUpDisplayLayerImpl::HeadsUpDisplayLayerImpl(LayerTreeImpl* tree_impl,
@@ -522,6 +553,11 @@ void HeadsUpDisplayLayerImpl::SetLayoutShiftRects(
layout_shift_rects_ = rects;
}
+void HeadsUpDisplayLayerImpl::SetWebVitalMetrics(
+ std::unique_ptr<WebVitalMetrics> web_vital_metrics) {
+ web_vital_metrics_ = std::move(web_vital_metrics);
+}
+
void HeadsUpDisplayLayerImpl::PushPropertiesTo(LayerImpl* layer) {
LayerImpl::PushPropertiesTo(layer);
@@ -531,6 +567,8 @@ void HeadsUpDisplayLayerImpl::PushPropertiesTo(LayerImpl* layer) {
layer_impl->SetHUDTypeface(typeface_);
layer_impl->SetLayoutShiftRects(layout_shift_rects_);
layout_shift_rects_.clear();
+ if (web_vital_metrics_ && web_vital_metrics_->HasValue())
+ layer_impl->SetWebVitalMetrics(std::move(web_vital_metrics_));
}
void HeadsUpDisplayLayerImpl::UpdateHudContents() {
@@ -544,6 +582,9 @@ void HeadsUpDisplayLayerImpl::UpdateHudContents() {
if (debug_state.show_fps_counter) {
throughput_value_ =
layer_tree_impl()->dropped_frame_counter()->GetAverageThroughput();
+ const auto& args = layer_tree_impl()->CurrentBeginFrameArgs();
+ if (args.IsValid())
+ frame_interval_ = args.interval;
}
if (debug_state.ShowMemoryStats()) {
@@ -564,26 +605,46 @@ void HeadsUpDisplayLayerImpl::DrawHudContents(PaintCanvas* canvas) {
canvas->save();
canvas->scale(internal_contents_scale_, internal_contents_scale_);
- if (debug_state.ShowHudRects()) {
+ if (debug_state.ShowDebugRects()) {
DrawDebugRects(canvas, layer_tree_impl()->debug_rect_history());
if (IsAnimatingHUDContents()) {
layer_tree_impl()->SetNeedsRedraw();
}
}
- if (!debug_state.show_fps_counter) {
+ if (!debug_state.ShouldDrawHudInfo()) {
canvas->restore();
return;
}
- SkRect area = DrawFrameThroughputDisplay(
- canvas, layer_tree_impl()->dropped_frame_counter(), 0, 0);
- area = DrawGpuRasterizationStatus(canvas, 0, area.bottom(),
- std::max<SkScalar>(area.width(), 150));
+ SkRect area = SkRect::MakeXYWH(0, 0, 0, 0);
- if (debug_state.ShowMemoryStats() && memory_entry_.total_bytes_used)
- DrawMemoryDisplay(canvas, 0, area.bottom(),
- std::max<SkScalar>(area.width(), 150));
+ if (debug_state.show_fps_counter) {
+ area = DrawFrameThroughputDisplay(
+ canvas, layer_tree_impl()->dropped_frame_counter(), 0, 0);
+ area = DrawGpuRasterizationStatus(canvas, 0, area.bottom(),
+ std::max<SkScalar>(area.width(), 150));
+ }
+
+ if (debug_state.ShowMemoryStats() && memory_entry_.total_bytes_used) {
+ area = DrawMemoryDisplay(canvas, 0, area.bottom(),
+ std::max<SkScalar>(area.width(), 150));
+ }
+
+ SkRect metrics_area = SkRect::MakeXYWH(
+ std::max<SkScalar>(0, bounds().width() - metrics_sizes.kWidth), 0,
+ metrics_sizes.kWidth, 0);
+ if (debug_state.show_web_vital_metrics) {
+ metrics_area = DrawWebVitalMetrics(
+ canvas, metrics_area.left(), metrics_area.bottom(),
+ std::max<SkScalar>(metrics_area.width(), metrics_sizes.kWidth));
+ }
+
+ if (debug_state.show_smoothness_metrics) {
+ metrics_area = DrawSmoothnessMetrics(
+ canvas, metrics_area.left(), metrics_area.bottom(),
+ std::max<SkScalar>(metrics_area.width(), metrics_sizes.kWidth));
+ }
canvas->restore();
}
@@ -640,6 +701,16 @@ void HeadsUpDisplayLayerImpl::DrawGraphLines(PaintCanvas* canvas,
bounds.bottom(), *flags);
}
+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);
+ canvas->drawLine(bounds.left(), bounds.top(), bounds.right(), bounds.top(),
+ *flags);
+}
+
SkRect HeadsUpDisplayLayerImpl::DrawFrameThroughputDisplay(
PaintCanvas* canvas,
const DroppedFrameCounter* dropped_frame_counter,
@@ -674,14 +745,15 @@ SkRect HeadsUpDisplayLayerImpl::DrawFrameThroughputDisplay(
kGraphWidth, kGraphHeight);
// Draw the frame rendering stats.
- const std::string title("Frames");
- const std::string value_text = base::StringPrintf("%d%%", throughput_value_);
- const std::string dropped_frames_text =
- base::StringPrintf("%zu (%zu m) dropped of %zu",
- dropped_frame_counter->total_compositor_dropped(),
- dropped_frame_counter->total_main_dropped(),
- dropped_frame_counter->total_frames());
-
+ const std::string title("Frame Rate");
+ std::string value_text = "n/a";
+ if (frame_interval_.has_value()) {
+ // This assumes a constant frame rate. If the frame rate changed throughout
+ // the sequence, then maybe we should average over the sequence.
+ double frame_rate = static_cast<double>(throughput_value_) /
+ (100 * frame_interval_.value().InSecondsF());
+ value_text = base::StringPrintf("%5.1f fps", frame_rate);
+ }
VLOG(1) << value_text;
flags.setColor(DebugColors::HUDTitleColor());
@@ -689,9 +761,7 @@ SkRect HeadsUpDisplayLayerImpl::DrawFrameThroughputDisplay(
title_bounds.left(), title_bounds.bottom());
flags.setColor(DebugColors::FPSDisplayTextAndGraphColor());
- DrawText(canvas, flags, value_text, TextAlign::kLeft, kFontHeight,
- text_bounds.left(), text_bounds.bottom());
- DrawText(canvas, flags, dropped_frames_text, TextAlign::kRight, kFontHeight,
+ DrawText(canvas, flags, value_text, TextAlign::kRight, kFontHeight,
text_bounds.right(), text_bounds.bottom());
DrawGraphLines(canvas, &flags, graph_bounds);
@@ -1022,6 +1092,134 @@ void HeadsUpDisplayLayerImpl::DrawDebugRects(
}
}
+int HeadsUpDisplayLayerImpl::DrawSingleMetric(
+ PaintCanvas* canvas,
+ int left,
+ int right,
+ int top,
+ std::string name,
+ const WebVitalMetrics::MetricsInfo& info,
+ bool has_value,
+ double value) const {
+ std::string value_str = "-";
+ SkColor metrics_color = DebugColors::HUDTitleColor();
+ if (has_value) {
+ value_str = ToStringTwoDecimalPrecision(value) + info.UnitToString();
+ if (value < info.green_threshold)
+ metrics_color = SK_ColorGREEN;
+ else if (value < info.yellow_threshold)
+ metrics_color = SK_ColorYELLOW;
+ else
+ metrics_color = SK_ColorRED;
+ }
+
+ PaintFlags flags;
+ flags.setColor(DebugColors::HUDTitleColor());
+ DrawText(canvas, flags, name, TextAlign::kLeft, metrics_sizes.kFontHeight,
+ left + metrics_sizes.kSidePadding, top);
+ flags.setColor(metrics_color);
+ DrawText(canvas, flags, value_str, TextAlign::kRight,
+ metrics_sizes.kFontHeight, right - metrics_sizes.kSidePadding, top);
+
+ return top + metrics_sizes.kFontHeight + metrics_sizes.kPadding;
+}
+
+SkRect HeadsUpDisplayLayerImpl::DrawWebVitalMetrics(PaintCanvas* canvas,
+ int left,
+ int top,
+ int width) const {
+ const int height = ComputeTotalHeight(3);
+ const SkRect area = SkRect::MakeXYWH(left, top, width, height);
+
+ PaintFlags flags;
+ DrawGraphBackground(canvas, &flags, area);
+
+ int current_top = top + metrics_sizes.kTopPadding + metrics_sizes.kFontHeight;
+ double metric_value = 0.f;
+ bool has_lcp = web_vital_metrics_ && web_vital_metrics_->has_lcp;
+ if (has_lcp)
+ metric_value = web_vital_metrics_->largest_contentful_paint.InSecondsF();
+ current_top = DrawSingleMetric(
+ canvas, left, left + width, current_top, "Largest Contentful Paint",
+ WebVitalMetrics::lcp_info, has_lcp, metric_value);
+
+ bool has_fid = web_vital_metrics_ && web_vital_metrics_->has_fid;
+ if (has_fid)
+ metric_value = web_vital_metrics_->first_input_delay.InMillisecondsF();
+ current_top = DrawSingleMetric(canvas, left, left + width, current_top,
+ "First Input Delay", WebVitalMetrics::fid_info,
+ has_fid, metric_value);
+
+ bool has_layout_shift = web_vital_metrics_ && web_vital_metrics_->has_cls;
+ if (has_layout_shift)
+ metric_value = web_vital_metrics_->layout_shift;
+ current_top = DrawSingleMetric(
+ canvas, left, left + width, current_top, "Cumulative Layout Shift",
+ WebVitalMetrics::cls_info, has_layout_shift, metric_value);
+
+ return area;
+}
+
+int HeadsUpDisplayLayerImpl::DrawSinglePercentageMetric(PaintCanvas* canvas,
+ int left,
+ int right,
+ int top,
+ std::string name,
+ double value) const {
+ std::string value_str = "-";
+ SkColor metrics_color = DebugColors::HUDTitleColor();
+ value_str = ToStringTwoDecimalPrecision(value) + "%";
+
+ PaintFlags flags;
+ flags.setColor(DebugColors::HUDTitleColor());
+ DrawText(canvas, flags, name, TextAlign::kLeft, metrics_sizes.kFontHeight,
+ left + metrics_sizes.kSidePadding, top);
+ flags.setColor(metrics_color);
+ DrawText(canvas, flags, value_str, TextAlign::kRight,
+ metrics_sizes.kFontHeight, right - metrics_sizes.kSidePadding, top);
+
+ return top + metrics_sizes.kFontHeight + metrics_sizes.kPadding;
+}
+
+SkRect HeadsUpDisplayLayerImpl::DrawSmoothnessMetrics(PaintCanvas* canvas,
+ int left,
+ int top,
+ int width) const {
+ const int height = ComputeTotalHeight(3);
+ const SkRect area = SkRect::MakeXYWH(left, top, width, height);
+
+ PaintFlags flags;
+ DrawGraphBackground(canvas, &flags, area);
+ if (top != 0) {
+ // There are metrics drawn before this.
+ SkRect separator =
+ SkRect::MakeXYWH(area.x(), area.y(), area.width(), area.height());
+ DrawSeparatorLine(canvas, &flags, separator);
+ }
+
+ int current_top = top + metrics_sizes.kTopPadding + metrics_sizes.kFontHeight;
+ double avg_smoothness = layer_tree_impl()
+ ->dropped_frame_counter()
+ ->GetMostRecentAverageSmoothness();
+ current_top =
+ DrawSinglePercentageMetric(canvas, left, left + width, current_top,
+ "Average Dropped Frame", avg_smoothness);
+ double worst_smoothness = layer_tree_impl()
+ ->dropped_frame_counter()
+ ->sliding_window_max_percent_dropped();
+ current_top =
+ DrawSinglePercentageMetric(canvas, left, left + width, current_top,
+ "Max Dropped Frame", worst_smoothness);
+ double percentile_smoothness = layer_tree_impl()
+ ->dropped_frame_counter()
+ ->GetMostRecent95PercentileSmoothness();
+ current_top =
+ DrawSinglePercentageMetric(canvas, left, left + width, current_top,
+ "95th Percentile DF", percentile_smoothness);
+
+ return area;
+}
+
const char* HeadsUpDisplayLayerImpl::LayerTypeAsString() const {
return "cc::HeadsUpDisplayLayerImpl";
}
diff --git a/chromium/cc/layers/heads_up_display_layer_impl.h b/chromium/cc/layers/heads_up_display_layer_impl.h
index 056bfb006f2..804201da7d9 100644
--- a/chromium/cc/layers/heads_up_display_layer_impl.h
+++ b/chromium/cc/layers/heads_up_display_layer_impl.h
@@ -13,6 +13,7 @@
#include "base/time/time.h"
#include "cc/cc_export.h"
#include "cc/layers/layer_impl.h"
+#include "cc/metrics/web_vital_metrics.h"
#include "cc/resources/memory_history.h"
#include "cc/resources/resource_pool.h"
#include "cc/trees/debug_rect_history.h"
@@ -68,6 +69,7 @@ class CC_EXPORT HeadsUpDisplayLayerImpl : public LayerImpl {
void SetHUDTypeface(sk_sp<SkTypeface> typeface);
void SetLayoutShiftRects(const std::vector<gfx::Rect>& rects);
const std::vector<gfx::Rect>& LayoutShiftRects() const;
+ void SetWebVitalMetrics(std::unique_ptr<WebVitalMetrics> web_vital_metrics);
// This evicts hud quad appended during render pass preparation.
void EvictHudQuad(const viz::CompositorRenderPassList& list);
@@ -103,6 +105,10 @@ class CC_EXPORT HeadsUpDisplayLayerImpl : public LayerImpl {
void DrawGraphLines(PaintCanvas* canvas,
PaintFlags* flags,
const SkRect& bounds) const;
+ // Draw a separator line at top of bounds.
+ void DrawSeparatorLine(PaintCanvas* canvas,
+ PaintFlags* flags,
+ const SkRect& bounds) const;
SkRect DrawFrameThroughputDisplay(
PaintCanvas* canvas,
@@ -127,6 +133,35 @@ class CC_EXPORT HeadsUpDisplayLayerImpl : public LayerImpl {
void DrawDebugRects(PaintCanvas* canvas,
DebugRectHistory* debug_rect_history);
+ // This function draws a single web vital metric. If the metrics doesn't have
+ // a valid value, the value is set to -1. This function returns the height
+ // of the current draw so it can be used to calculate the top of the next
+ // draw.
+ int DrawSingleMetric(PaintCanvas* canvas,
+ int left,
+ int right,
+ int top,
+ std::string name,
+ const WebVitalMetrics::MetricsInfo& info,
+ bool has_value,
+ double value) const;
+ SkRect DrawWebVitalMetrics(PaintCanvas* canvas,
+ int left,
+ int top,
+ int width) const;
+
+ // This function draws a single smoothness related metric.
+ int DrawSinglePercentageMetric(PaintCanvas* canvas,
+ int left,
+ int right,
+ int top,
+ std::string name,
+ double value) const;
+ SkRect DrawSmoothnessMetrics(PaintCanvas* canvas,
+ int left,
+ int top,
+ int width) const;
+
ResourcePool::InUsePoolResource in_flight_resource_;
std::unique_ptr<ResourcePool> pool_;
viz::DrawQuad* current_quad_ = nullptr;
@@ -140,12 +175,16 @@ class CC_EXPORT HeadsUpDisplayLayerImpl : public LayerImpl {
gfx::Size internal_content_bounds_;
uint32_t throughput_value_ = 0.0f;
+ // Obtained from the current BeginFrameArgs.
+ base::Optional<base::TimeDelta> frame_interval_;
MemoryHistory::Entry memory_entry_;
int paint_rects_fade_step_ = 0;
int layout_shift_rects_fade_step_ = 0;
std::vector<DebugRect> paint_rects_;
std::vector<DebugRect> layout_shift_debug_rects_;
+ std::unique_ptr<WebVitalMetrics> web_vital_metrics_;
+
base::TimeTicks time_of_last_graph_update_;
};
diff --git a/chromium/cc/layers/heads_up_display_unittest.cc b/chromium/cc/layers/heads_up_display_unittest.cc
index 688a510cbb6..20b6f21c510 100644
--- a/chromium/cc/layers/heads_up_display_unittest.cc
+++ b/chromium/cc/layers/heads_up_display_unittest.cc
@@ -97,5 +97,25 @@ class HeadsUpDisplaySizeWithFPS : public LayerTreeTest {
SINGLE_AND_MULTI_THREAD_TEST_F(HeadsUpDisplaySizeWithFPS);
+class HeadsUpDisplaySizeWithMetrics : public LayerTreeTest {
+ public:
+ void InitializeSettings(LayerTreeSettings* settings) override {
+ settings->initial_debug_state.show_web_vital_metrics = true;
+ }
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ void DidCommit() override {
+ // The metrics should be shown on the right, so the width of the HUD layer
+ // should be the saem as the root layer bounds.
+ ASSERT_TRUE(layer_tree_host()->hud_layer());
+ EXPECT_EQ(gfx::Size(layer_tree_host()->root_layer()->bounds().width(), 512),
+ layer_tree_host()->hud_layer()->bounds());
+ EndTest();
+ }
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(HeadsUpDisplaySizeWithMetrics);
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/layers/layer.cc b/chromium/cc/layers/layer.cc
index aca2eaf4da0..2a0de3af1dd 100644
--- a/chromium/cc/layers/layer.cc
+++ b/chromium/cc/layers/layer.cc
@@ -59,7 +59,6 @@ struct SameSizeAsLayer : public base::RefCounted<SameSizeAsLayer> {
int int_fields[6];
gfx::Vector2dF offset;
unsigned bitfields;
- SkColor safe_opaque_background_color;
void* debug_info;
};
@@ -87,19 +86,13 @@ Layer::Inputs::Inputs(int layer_id)
Layer::Inputs::~Inputs() = default;
Layer::LayerTreeInputs::LayerTreeInputs()
- : mask_layer(nullptr),
- opacity(1.f),
- blend_mode(SkBlendMode::kSrcOver),
- masks_to_bounds(false),
+ : masks_to_bounds(false),
is_fast_rounded_corner(false),
user_scrollable_horizontal(true),
user_scrollable_vertical(true),
trilinear_filtering(false),
hide_layer_and_subtree(false),
- scrollable(false),
- backdrop_filter_quality(1.0f),
- mirror_count(0),
- corner_radii({0, 0, 0, 0}) {}
+ scrollable(false) {}
Layer::LayerTreeInputs::~LayerTreeInputs() = default;
@@ -128,8 +121,7 @@ Layer::Layer()
needs_show_scrollbars_(false),
has_transform_node_(false),
has_clip_node_(false),
- subtree_has_copy_request_(false),
- safe_opaque_background_color_(0) {}
+ subtree_has_copy_request_(false) {}
Layer::~Layer() {
// Our parent should be holding a reference to us so there should be no
@@ -496,25 +488,41 @@ void Layer::SetBackgroundColor(SkColor background_color) {
void Layer::SetSafeOpaqueBackgroundColor(SkColor background_color) {
DCHECK(IsPropertyChangeAllowed());
- SkColor opaque_color = SkColorSetA(background_color, 255);
- if (safe_opaque_background_color_ == opaque_color)
+ SkColor opaque_color = SkColorSetA(background_color, SK_AlphaOPAQUE);
+ auto& inputs = EnsureLayerTreeInputs();
+ if (inputs.safe_opaque_background_color == opaque_color)
return;
- safe_opaque_background_color_ = opaque_color;
+ inputs.safe_opaque_background_color = opaque_color;
SetNeedsPushProperties();
}
SkColor Layer::SafeOpaqueBackgroundColor() const {
if (contents_opaque()) {
- // TODO(936906): We should uncomment this DCHECK, since the
- // |safe_opaque_background_color_| could be transparent if it is never set
- // (the default is 0). But to do that, one test needs to be fixed.
- // DCHECK_EQ(SkColorGetA(safe_opaque_background_color_), SK_AlphaOPAQUE);
- return safe_opaque_background_color_;
+ if (!layer_tree_host_ || !layer_tree_host_->IsUsingLayerLists()) {
+ // In layer tree mode, PropertyTreeBuilder should have calculated the safe
+ // opaque background color and called SetSafeOpaqueBackgroundColor().
+ DCHECK(layer_tree_inputs());
+ DCHECK_EQ(SkColorGetA(layer_tree_inputs()->safe_opaque_background_color),
+ SK_AlphaOPAQUE);
+ return layer_tree_inputs()->safe_opaque_background_color;
+ }
+ // 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.
+ SkColor color = background_color() == SK_ColorTRANSPARENT
+ ? layer_tree_host_->background_color()
+ : background_color();
+ return SkColorSetA(color, SK_AlphaOPAQUE);
}
- SkColor color = background_color();
- if (SkColorGetA(color) == 255)
- color = SK_ColorTRANSPARENT;
- return color;
+ if (SkColorGetA(background_color()) == SK_AlphaOPAQUE) {
+ // The layer is not opaque while the background color is, meaning that the
+ // background color doesn't cover the whole layer. Use SK_ColorTRANSPARENT
+ // to avoid intrusive checkerboard where the layer is not covered by the
+ // background color.
+ return SK_ColorTRANSPARENT;
+ }
+ return background_color();
}
void Layer::SetMasksToBounds(bool masks_to_bounds) {
@@ -995,6 +1003,22 @@ void Layer::SetDidScrollCallback(
EnsureLayerTreeInputs().did_scroll_callback = std::move(callback);
}
+void Layer::SetSubtreeCaptureId(viz::SubtreeCaptureId subtree_id) {
+ DCHECK(IsPropertyChangeAllowed());
+
+ auto& inputs = EnsureLayerTreeInputs();
+ if (inputs.subtree_capture_id == subtree_id)
+ return;
+
+ DCHECK(!inputs.subtree_capture_id.is_valid() || !subtree_id.is_valid())
+ << "Not allowed to change from a valid ID to another valid ID, as it may "
+ "already be in use.";
+
+ inputs.subtree_capture_id = subtree_id;
+ SetPropertyTreesNeedRebuild();
+ SetNeedsCommit();
+}
+
void Layer::SetScrollable(const gfx::Size& bounds) {
DCHECK(IsPropertyChangeAllowed());
auto& inputs = EnsureLayerTreeInputs();
@@ -1305,7 +1329,7 @@ void Layer::PushPropertiesTo(LayerImpl* layer) {
layer->SetElementId(inputs_.element_id);
layer->SetHasTransformNode(has_transform_node_);
layer->SetBackgroundColor(inputs_.background_color);
- layer->SetSafeOpaqueBackgroundColor(safe_opaque_background_color_);
+ layer->SetSafeOpaqueBackgroundColor(SafeOpaqueBackgroundColor());
layer->SetBounds(inputs_.bounds);
layer->SetTransformTreeIndex(transform_tree_index());
layer->SetEffectTreeIndex(effect_tree_index());
diff --git a/chromium/cc/layers/layer.h b/chromium/cc/layers/layer.h
index 69915971416..f73be661141 100644
--- a/chromium/cc/layers/layer.h
+++ b/chromium/cc/layers/layer.h
@@ -31,6 +31,7 @@
#include "cc/trees/effect_node.h"
#include "cc/trees/property_tree.h"
#include "cc/trees/target_property.h"
+#include "components/viz/common/surfaces/subtree_capture_id.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/geometry/point3_f.h"
#include "ui/gfx/geometry/rect.h"
@@ -151,22 +152,22 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
virtual void SetBackgroundColor(SkColor background_color);
SkColor background_color() const { return inputs_.background_color; }
- // Internal to property tree generation. Sets an opaque background color for
- // the layer, to be used in place of the background_color() if the layer says
- // contents_opaque() is true.
+ // For layer tree mode only. In layer list mode, client doesn't need to set
+ // it. Sets an opaque background color for the layer, to be used in place of
+ // the background_color() if the layer says contents_opaque() is true.
void SetSafeOpaqueBackgroundColor(SkColor background_color);
- // Returns a background color with opaque-ness equal to the value of
+
+ // Returns a background color with opaqueness equal to the value of
// contents_opaque().
- // If the layer says contents_opaque() is true, this returns the value set by
- // SetSafeOpaqueBackgroundColor() which should be an opaque color. Otherwise,
- // it returns something non-opaque. It prefers to return the
+ // 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 layer_tree_host()->background_clor().
+ // 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 SK_ColorTRANSPARENT is returned.
+ // claims to not be), then SK_ColorTRANSPARENT is returned to avoid intrusive
+ // checkerboard where the layer is not covered by the background_color().
SkColor SafeOpaqueBackgroundColor() const;
- // For testing, return the actual stored value.
- SkColor ActualSafeOpaqueBackgroundColorForTesting() const {
- return safe_opaque_background_color_;
- }
// For layer tree mode only.
// Set and get the position of this layer, relative to its parent. This is
@@ -472,6 +473,27 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
void SetDidScrollCallback(base::RepeatingCallback<
void(const gfx::ScrollOffset&, const ElementId&)>);
+ // For layer tree mode only.
+ // Sets the given |subtree_id| on this layer, so that the layer subtree rooted
+ // at this layer can be uniquely identified by a FrameSinkVideoCapturer.
+ // The existence of a valid SubtreeCaptureId on this layer will force it to be
+ // drawn into a separate CompositorRenderPass.
+ // Setting a non-valid (i.e. default-constructed SubtreeCaptureId) will clear
+ // this property.
+ // It is not allowed to change this ID from a valid ID to another valid ID,
+ // since a client might already using the existing valid ID to make this layer
+ // subtree identifiable by a capturer.
+ //
+ // Note that this is useful when it's desired to video record a layer subtree
+ // of a non-root layer using a FrameSinkVideoCapturer, since non-root layers
+ // are usually not drawn into their own CompositorRenderPass.
+ void SetSubtreeCaptureId(viz::SubtreeCaptureId subtree_id);
+ viz::SubtreeCaptureId subtree_capture_id() const {
+ if (layer_tree_inputs())
+ return layer_tree_inputs()->subtree_capture_id;
+ return viz::SubtreeCaptureId();
+ }
+
// Set or get if the layer and its subtree should be cached as a texture in
// the display compositor. This is used as an optimization when it is known
// that the layer will be animated without changing its content, or any of its
@@ -862,10 +884,10 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
// If not null, points to one of child layers which is set as mask layer
// by SetMaskLayer().
- PictureLayer* mask_layer;
+ PictureLayer* mask_layer = nullptr;
- float opacity;
- SkBlendMode blend_mode;
+ float opacity = 1.0f;
+ SkBlendMode blend_mode = SkBlendMode::kSrcOver;
bool masks_to_bounds : 1;
@@ -889,12 +911,20 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
gfx::Transform transform;
gfx::Point3F transform_origin;
+ // A unique ID that identifies the layer subtree rooted at this layer, so
+ // that it can be independently captured by the FrameSinkVideoCapturer. If
+ // this ID is set (i.e. valid), it would force this subtree into a render
+ // surface that darws in a render pass.
+ viz::SubtreeCaptureId subtree_capture_id;
+
+ SkColor safe_opaque_background_color = SK_ColorTRANSPARENT;
+
FilterOperations filters;
FilterOperations backdrop_filters;
base::Optional<gfx::RRectF> backdrop_filter_bounds;
- float backdrop_filter_quality;
+ float backdrop_filter_quality = 1.0f;
- int mirror_count;
+ int mirror_count = 0;
gfx::ScrollOffset scroll_offset;
// Size of the scroll container that this layer scrolls in.
@@ -925,6 +955,7 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
int clip_tree_index_;
int scroll_tree_index_;
int property_tree_sequence_number_;
+
gfx::Vector2dF offset_to_transform_parent_;
// When true, the layer is about to perform an update. Any commit requests
@@ -945,8 +976,6 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
// This value is valid only when LayerTreeHost::has_copy_request() is true
bool subtree_has_copy_request_ : 1;
- SkColor safe_opaque_background_color_;
-
std::unique_ptr<LayerDebugInfo> debug_info_;
static constexpr gfx::Transform kIdentityTransform{};
diff --git a/chromium/cc/layers/layer_impl.cc b/chromium/cc/layers/layer_impl.cc
index 460019a63e3..2d69deaaddd 100644
--- a/chromium/cc/layers/layer_impl.cc
+++ b/chromium/cc/layers/layer_impl.cc
@@ -42,6 +42,7 @@
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/geometry/vector2d_conversions.h"
+#include "ui/gfx/transform_util.h"
namespace cc {
LayerImpl::LayerImpl(LayerTreeImpl* tree_impl,
@@ -288,7 +289,7 @@ void LayerImpl::GetContentsResourceId(viz::ResourceId* resource_id,
gfx::Size* resource_size,
gfx::SizeF* resource_uv_size) const {
NOTREACHED();
- *resource_id = 0;
+ *resource_id = viz::kInvalidResourceId;
}
gfx::Vector2dF LayerImpl::ScrollBy(const gfx::Vector2dF& scroll) {
@@ -555,20 +556,6 @@ void LayerImpl::SetSafeOpaqueBackgroundColor(SkColor background_color) {
safe_opaque_background_color_ = background_color;
}
-SkColor LayerImpl::SafeOpaqueBackgroundColor() const {
- if (contents_opaque()) {
- // TODO(936906): We should uncomment this DCHECK, since the
- // |safe_opaque_background_color_| could be transparent if it is never set
- // (the default is 0). But to do that, one test needs to be fixed.
- // DCHECK_EQ(SkColorGetA(safe_opaque_background_color_), SK_AlphaOPAQUE);
- return safe_opaque_background_color_;
- }
- SkColor color = background_color();
- if (SkColorGetA(color) == 255)
- color = SK_ColorTRANSPARENT;
- return color;
-}
-
void LayerImpl::SetContentsOpaque(bool opaque) {
contents_opaque_ = opaque;
contents_opaque_for_text_ = opaque;
@@ -812,7 +799,7 @@ float LayerImpl::GetIdealContentsScale() const {
const auto& transform = ScreenSpaceTransform();
if (transform.HasPerspective()) {
- float scale = MathUtil::ComputeApproximateMaxScale(transform);
+ float scale = gfx::ComputeApproximateMaxScale(transform);
const int kMaxTilesToCoverLayerDimension = 5;
// Cap the scale in a way that it should be covered by at most
@@ -842,7 +829,7 @@ float LayerImpl::GetIdealContentsScale() const {
}
gfx::Vector2dF transform_scales =
- MathUtil::ComputeTransform2dScaleComponents(transform, default_scale);
+ gfx::ComputeTransform2dScaleComponents(transform, default_scale);
return GetPreferredRasterScale(transform_scales);
}
diff --git a/chromium/cc/layers/layer_impl.h b/chromium/cc/layers/layer_impl.h
index 6af8b62c8ba..66c0b8015c8 100644
--- a/chromium/cc/layers/layer_impl.h
+++ b/chromium/cc/layers/layer_impl.h
@@ -163,9 +163,12 @@ class CC_EXPORT LayerImpl {
void SetBackgroundColor(SkColor background_color);
SkColor background_color() const { return background_color_; }
void SetSafeOpaqueBackgroundColor(SkColor background_color);
- // If contents_opaque(), return an opaque color else return a
- // non-opaque color. Tries to return background_color(), if possible.
- SkColor SafeOpaqueBackgroundColor() const;
+ SkColor safe_opaque_background_color() const {
+ // Layer::SafeOpaqueBackgroundColor() should ensure this.
+ DCHECK_EQ(contents_opaque(),
+ SkColorGetA(safe_opaque_background_color_) == SK_AlphaOPAQUE);
+ return safe_opaque_background_color_;
+ }
// See Layer::SetContentsOpaque() and SetContentsOpaqueForText() for the
// relationship between the two flags.
diff --git a/chromium/cc/layers/layer_impl_unittest.cc b/chromium/cc/layers/layer_impl_unittest.cc
index a4924c9f3ba..7ef644a4208 100644
--- a/chromium/cc/layers/layer_impl_unittest.cc
+++ b/chromium/cc/layers/layer_impl_unittest.cc
@@ -17,7 +17,6 @@
#include "cc/trees/tree_synchronizer.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/effects/SkBlurImageFilter.h"
namespace cc {
namespace {
diff --git a/chromium/cc/layers/layer_unittest.cc b/chromium/cc/layers/layer_unittest.cc
index 2b7d4d69605..9770b8c6873 100644
--- a/chromium/cc/layers/layer_unittest.cc
+++ b/chromium/cc/layers/layer_unittest.cc
@@ -9,11 +9,10 @@
#include <utility>
#include "base/bind.h"
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
#include "base/threading/thread_task_runner_handle.h"
#include "cc/animation/animation_host.h"
#include "cc/animation/animation_id_provider.h"
-#include "cc/animation/keyframed_animation_curve.h"
#include "cc/base/math_util.h"
#include "cc/layers/layer_impl.h"
#include "cc/layers/picture_layer.h"
@@ -38,6 +37,7 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/animation/keyframe/keyframed_animation_curve.h"
#include "ui/gfx/geometry/point3_f.h"
#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/geometry/scroll_offset.h"
@@ -1719,7 +1719,7 @@ TEST_F(LayerTest, UpdatingClipRect) {
// Setting a filter that moves pixels.
FilterOperations move_pixel_filters;
move_pixel_filters.Append(
- FilterOperation::CreateBlurFilter(2, SkBlurImageFilter::kClamp_TileMode));
+ FilterOperation::CreateBlurFilter(2, SkTileMode::kClamp));
ASSERT_TRUE(move_pixel_filters.HasFilterThatMovesPixels());
clipped_3->SetFilters(move_pixel_filters);
diff --git a/chromium/cc/layers/mirror_layer_impl.cc b/chromium/cc/layers/mirror_layer_impl.cc
index b76d41508e9..2343eeb56a9 100644
--- a/chromium/cc/layers/mirror_layer_impl.cc
+++ b/chromium/cc/layers/mirror_layer_impl.cc
@@ -47,7 +47,7 @@ void MirrorLayerImpl::AppendQuads(viz::CompositorRenderPass* render_pass,
AppendDebugBorderQuad(render_pass, content_rect, shared_quad_state,
append_quads_data);
- viz::ResourceId mask_resource_id = 0;
+ viz::ResourceId mask_resource_id = viz::kInvalidResourceId;
gfx::RectF mask_uv_rect;
gfx::Size mask_texture_size;
diff --git a/chromium/cc/layers/painted_scrollbar_layer.cc b/chromium/cc/layers/painted_scrollbar_layer.cc
index a7348df68a9..3e0b802ba84 100644
--- a/chromium/cc/layers/painted_scrollbar_layer.cc
+++ b/chromium/cc/layers/painted_scrollbar_layer.cc
@@ -14,6 +14,7 @@
#include "cc/trees/draw_property_utils.h"
#include "cc/trees/layer_tree_host.h"
#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/transform_util.h"
namespace cc {
@@ -85,7 +86,7 @@ void PaintedScrollbarLayer::PushPropertiesTo(LayerImpl* layer) {
else
scrollbar_layer->set_thumb_ui_resource_id(0);
- scrollbar_layer->set_scrollbar_painted_opacity(painted_opacity_);
+ scrollbar_layer->SetScrollbarPaintedOpacity(painted_opacity_);
scrollbar_layer->set_is_overlay_scrollbar(is_overlay_);
}
@@ -141,7 +142,7 @@ bool PaintedScrollbarLayer::UpdateInternalContentScale() {
transform = draw_property_utils::ScreenSpaceTransform(
this, layer_tree_host()->property_trees()->transform_tree);
- gfx::Vector2dF transform_scales = MathUtil::ComputeTransform2dScaleComponents(
+ gfx::Vector2dF transform_scales = gfx::ComputeTransform2dScaleComponents(
transform, layer_tree_host()->device_scale_factor());
float scale = std::max(transform_scales.x(), transform_scales.y());
// Clamp minimum scale to 1 to avoid too low scale during scale animation.
diff --git a/chromium/cc/layers/painted_scrollbar_layer_impl.cc b/chromium/cc/layers/painted_scrollbar_layer_impl.cc
index 0eda954cd9e..5ccb0727ab8 100644
--- a/chromium/cc/layers/painted_scrollbar_layer_impl.cc
+++ b/chromium/cc/layers/painted_scrollbar_layer_impl.cc
@@ -77,7 +77,7 @@ void PaintedScrollbarLayerImpl::PushPropertiesTo(LayerImpl* layer) {
scrollbar_layer->set_track_ui_resource_id(track_ui_resource_id_);
scrollbar_layer->set_thumb_ui_resource_id(thumb_ui_resource_id_);
- scrollbar_layer->set_scrollbar_painted_opacity(painted_opacity_);
+ scrollbar_layer->SetScrollbarPaintedOpacity(painted_opacity_);
}
float PaintedScrollbarLayerImpl::OverlayScrollbarOpacity() const {
@@ -277,6 +277,13 @@ void PaintedScrollbarLayerImpl::SetTrackRect(gfx::Rect track_rect) {
NoteLayerPropertyChanged();
}
+void PaintedScrollbarLayerImpl::SetScrollbarPaintedOpacity(float opacity) {
+ if (painted_opacity_ == opacity)
+ return;
+ painted_opacity_ = opacity;
+ NoteLayerPropertyChanged();
+}
+
float PaintedScrollbarLayerImpl::TrackLength() const {
if (orientation() == ScrollbarOrientation::VERTICAL)
return track_rect_.height() + vertical_adjust();
diff --git a/chromium/cc/layers/painted_scrollbar_layer_impl.h b/chromium/cc/layers/painted_scrollbar_layer_impl.h
index 4e72b0112ab..9e7859264d5 100644
--- a/chromium/cc/layers/painted_scrollbar_layer_impl.h
+++ b/chromium/cc/layers/painted_scrollbar_layer_impl.h
@@ -45,6 +45,7 @@ class CC_EXPORT PaintedScrollbarLayerImpl : public ScrollbarLayerImplBase {
void SetThumbThickness(int thumb_thickness);
void SetThumbLength(int thumb_length);
void SetTrackRect(gfx::Rect track_rect);
+ void SetScrollbarPaintedOpacity(float opacity);
void set_track_ui_resource_id(UIResourceId uid) {
track_ui_resource_id_ = uid;
@@ -52,10 +53,6 @@ class CC_EXPORT PaintedScrollbarLayerImpl : public ScrollbarLayerImplBase {
void set_thumb_ui_resource_id(UIResourceId uid) {
thumb_ui_resource_id_ = uid;
}
-
- void set_scrollbar_painted_opacity(float opacity) {
- painted_opacity_ = opacity;
- }
float OverlayScrollbarOpacity() const override;
void set_internal_contents_scale_and_bounds(float content_scale,
diff --git a/chromium/cc/layers/painted_scrollbar_layer_impl_unittest.cc b/chromium/cc/layers/painted_scrollbar_layer_impl_unittest.cc
index 11f47b40e2b..1669534136f 100644
--- a/chromium/cc/layers/painted_scrollbar_layer_impl_unittest.cc
+++ b/chromium/cc/layers/painted_scrollbar_layer_impl_unittest.cc
@@ -55,7 +55,7 @@ TEST(PaintedScrollbarLayerImplTest, Occlusion) {
scrollbar_layer_impl->SetScrollLayerLength(200.f);
scrollbar_layer_impl->set_track_ui_resource_id(track_uid);
scrollbar_layer_impl->set_thumb_ui_resource_id(thumb_uid);
- scrollbar_layer_impl->set_scrollbar_painted_opacity(painted_opacity_);
+ scrollbar_layer_impl->SetScrollbarPaintedOpacity(painted_opacity_);
CopyProperties(impl.root_layer(), scrollbar_layer_impl);
impl.CalcDrawProps(viewport_size);
@@ -134,5 +134,16 @@ TEST(PaintedScrollbarLayerImplTest, Occlusion) {
}
}
+TEST(PaintedScrollbarLayerImplTest, PaintedOpacityChangesInvalidate) {
+ LayerTreeImplTestBase impl;
+ ScrollbarOrientation orientation = ScrollbarOrientation::VERTICAL;
+ PaintedScrollbarLayerImpl* scrollbar_layer_impl =
+ impl.AddLayer<PaintedScrollbarLayerImpl>(orientation, false, false);
+ EXPECT_FALSE(
+ scrollbar_layer_impl->LayerPropertyChangedNotFromPropertyTrees());
+ scrollbar_layer_impl->SetScrollbarPaintedOpacity(0.3f);
+ EXPECT_TRUE(scrollbar_layer_impl->LayerPropertyChangedNotFromPropertyTrees());
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/layers/picture_layer_impl.cc b/chromium/cc/layers/picture_layer_impl.cc
index a89ec6638fe..e49acdc47ec 100644
--- a/chromium/cc/layers/picture_layer_impl.cc
+++ b/chromium/cc/layers/picture_layer_impl.cc
@@ -66,6 +66,15 @@ const float kMaxIdealContentsScale = 10000.f;
// the native scale.
const float kMinScaleRatioForWillChangeTransform = 0.25f;
+// Used to avoid raster scale adjustment during a transform animation by
+// using the maximum animation scale, but sometimes the maximum animation scale
+// can't be accurately calculated (e.g. with nested scale transforms). We'll
+// adjust raster scale if it is not affected by invalid scale and is smaller
+// than the ideal scale divided by this ratio. The situation is rare.
+// See PropertyTrees::MaximumAnimationToScreenScale() and
+// AnimationAffectedByInvalidScale().
+const float kRatioToAdjustRasterScaleForTransformAnimation = 1.5f;
+
// Intersect rects which may have right() and bottom() that overflow integer
// boundaries. This code is similar to gfx::Rect::Intersect with the exception
// that the types are promoted to int64_t when there is a chance of overflow.
@@ -512,7 +521,7 @@ void PictureLayerImpl::AppendQuads(viz::CompositorRenderPass* render_pass,
if (!has_draw_quad) {
// Checkerboard.
- SkColor color = SafeOpaqueBackgroundColor();
+ SkColor color = safe_opaque_background_color();
if (ShowDebugBorders(DebugBorderType::LAYER)) {
// Fill the whole tile with the missing tile color.
color = DebugColors::DefaultCheckerboardColor();
@@ -582,6 +591,7 @@ void PictureLayerImpl::AppendQuads(viz::CompositorRenderPass* render_pass,
// better scheme would be to maintain a tighter visible_layer_rect for the
// finer tilings.
CleanUpTilingsOnActiveLayer(last_append_quads_tilings_);
+ SanityCheckTilingState();
}
bool PictureLayerImpl::UpdateTiles() {
@@ -658,6 +668,8 @@ bool PictureLayerImpl::UpdateTiles() {
viewport_rect_for_tile_priority_in_content_space_, ideal_contents_scale_,
current_frame_time_in_seconds, occlusion_in_content_space,
can_require_tiles_for_activation);
+ DCHECK_GT(tilings_->num_tilings(), 0u);
+ SanityCheckTilingState();
return updated;
}
@@ -1037,7 +1049,7 @@ void PictureLayerImpl::GetContentsResourceId(
gfx::SizeF* resource_uv_size) const {
// We need contents resource for backdrop filter masks only.
if (!is_backdrop_filter_mask()) {
- *resource_id = 0;
+ *resource_id = viz::kInvalidResourceId;
return;
}
@@ -1055,7 +1067,7 @@ void PictureLayerImpl::GetContentsResourceId(
// Mask resource not ready yet.
if (!iter || !*iter) {
- *resource_id = 0;
+ *resource_id = viz::kInvalidResourceId;
return;
}
@@ -1067,7 +1079,7 @@ void PictureLayerImpl::GetContentsResourceId(
const TileDrawInfo& draw_info = iter->draw_info();
if (!draw_info.IsReadyToDraw() ||
draw_info.mode() != TileDrawInfo::RESOURCE_MODE) {
- *resource_id = 0;
+ *resource_id = viz::kInvalidResourceId;
return;
}
@@ -1349,14 +1361,31 @@ bool PictureLayerImpl::ShouldAdjustRasterScale() const {
if (raster_contents_scale_ < MinimumContentsScale())
return true;
- // Don't change the raster scale if any of the following are true:
- // - We have an animating transform.
- // - The raster scale is already ideal.
- if (draw_properties().screen_space_transform_is_animating ||
- raster_source_scale_ == ideal_source_scale_) {
+ // Avoid frequent raster scale changes if we have an animating transform.
+ if (draw_properties().screen_space_transform_is_animating) {
+ // Except when the device viewport rect has changed because the raster scale
+ // may depend on the rect.
+ if (layer_tree_impl()->device_viewport_rect_changed())
+ return true;
+ // Or when the raster scale is not affected by invalid scale and is too
+ // small compared to the ideal scale.
+ if (ideal_contents_scale_ >
+ raster_contents_scale_ *
+ kRatioToAdjustRasterScaleForTransformAnimation) {
+ auto* property_trees = layer_tree_impl()->property_trees();
+ int transform_id = transform_tree_index();
+ if (property_trees->AnimationScaleCacheIsInvalid(transform_id) ||
+ !property_trees->AnimationAffectedByInvalidScale(transform_id)) {
+ return true;
+ }
+ }
return false;
}
+ // Don't change the raster scale if the raster scale is already ideal.
+ if (raster_source_scale_ == ideal_source_scale_)
+ return false;
+
// Don't update will-change: transform layers if the raster contents scale is
// bigger than the minimum scale.
if (HasWillChangeTransformHint() &&
@@ -1493,38 +1522,34 @@ void PictureLayerImpl::AdjustRasterScaleForTransformAnimation(
float preserved_raster_contents_scale) {
DCHECK(draw_properties().screen_space_transform_is_animating);
- CombinedAnimationScale animation_scales =
- layer_tree_impl()->property_trees()->GetAnimationScales(
- transform_tree_index(), layer_tree_impl());
- float maximum_scale = animation_scales.maximum_animation_scale;
- float starting_scale = animation_scales.starting_animation_scale;
- // Adjust raster scale only if the animation scale is known.
- if (maximum_scale == kNotScaled && starting_scale == kNotScaled) {
- // Use at least the native scale if the animation scale is unknown.
- raster_contents_scale_ = std::max(raster_contents_scale_,
- ideal_page_scale_ * ideal_device_scale_);
- } else {
- // We rasterize at the maximum scale that will occur during the animation.
- raster_contents_scale_ = std::max(maximum_scale, starting_scale);
- }
- DCHECK_NE(raster_contents_scale_, kNotScaled);
-
- // We will cap the adjusted scale with the viewport area, which is impossible
- // if the viewport is empty.
- gfx::Size viewport = layer_tree_impl()->GetDeviceViewport().size();
- if (viewport.IsEmpty())
- return;
+ float maximum_animation_scale =
+ layer_tree_impl()->property_trees()->MaximumAnimationToScreenScale(
+ transform_tree_index());
+ raster_contents_scale_ =
+ std::max(raster_contents_scale_, maximum_animation_scale);
// However we want to avoid excessive memory use. Choose a scale at which this
// layer's rastered content is not larger than the viewport.
- float max_viewport_dimension = std::max(viewport.width(), viewport.height());
+ gfx::Size viewport = layer_tree_impl()->GetDeviceViewport().size();
+ // To avoid too small scale in a small viewport.
+ constexpr int kMinViewportDimension = 500;
+ float max_viewport_dimension =
+ std::max({viewport.width(), viewport.height(), kMinViewportDimension});
DCHECK(max_viewport_dimension);
// Use square to compensate for viewports with different aspect ratios.
float squared_viewport_area = max_viewport_dimension * max_viewport_dimension;
- gfx::Size bounds_at_maximum_scale =
- gfx::ScaleToCeiledSize(raster_source_->GetSize(), raster_contents_scale_);
- float maximum_area = static_cast<float>(bounds_at_maximum_scale.width()) *
- bounds_at_maximum_scale.height();
+
+ gfx::SizeF raster_source_size(raster_source_->GetSize());
+ // Clamp raster_source_size by max_viewport_dimension to avoid too small
+ // scale for huge layers for which the far from viewport area won't be
+ // rasterized and out of viewport area is rasterized in low priority.
+ gfx::SizeF max_visible_bounds(
+ std::min(raster_source_size.width(), max_viewport_dimension),
+ std::min(raster_source_size.height(), max_viewport_dimension));
+ gfx::SizeF max_visible_bounds_at_max_scale =
+ gfx::ScaleSize(max_visible_bounds, raster_contents_scale_);
+ float maximum_area = max_visible_bounds_at_max_scale.width() *
+ max_visible_bounds_at_max_scale.height();
// Clamp the scale to make the rastered content not larger than the viewport.
if (UNLIKELY(maximum_area > squared_viewport_area))
raster_contents_scale_ /= std::sqrt(maximum_area / squared_viewport_area);
@@ -1563,8 +1588,6 @@ void PictureLayerImpl::CleanUpTilingsOnActiveLayer(
tilings_->CleanUpTilings(min_acceptable_high_res_scale,
max_acceptable_high_res_scale, used_tilings,
twin_set);
- DCHECK_GT(tilings_->num_tilings(), 0u);
- SanityCheckTilingState();
}
float PictureLayerImpl::MinimumRasterContentsScaleForWillChangeTransform()
diff --git a/chromium/cc/layers/picture_layer_impl.h b/chromium/cc/layers/picture_layer_impl.h
index a79a2441c89..e526ef44341 100644
--- a/chromium/cc/layers/picture_layer_impl.h
+++ b/chromium/cc/layers/picture_layer_impl.h
@@ -167,6 +167,10 @@ class CC_EXPORT PictureLayerImpl
ideal_contents_scale_ = raster_contents_scale_ = scale;
}
+ void AddLastAppendQuadsTilingForTesting(PictureLayerTiling* tiling) {
+ last_append_quads_tilings_.push_back(tiling);
+ }
+
protected:
PictureLayerImpl(LayerTreeImpl* tree_impl, int id);
PictureLayerTiling* AddTiling(const gfx::AxisTransform2d& contents_transform);
diff --git a/chromium/cc/layers/picture_layer_impl_unittest.cc b/chromium/cc/layers/picture_layer_impl_unittest.cc
index c9e135ee659..61ac7452a91 100644
--- a/chromium/cc/layers/picture_layer_impl_unittest.cc
+++ b/chromium/cc/layers/picture_layer_impl_unittest.cc
@@ -151,10 +151,7 @@ class PictureLayerImplTest : public TestLayerTreeHostBase {
void SetupDrawProperties(FakePictureLayerImpl* layer,
float ideal_contents_scale,
float device_scale_factor,
- float page_scale_factor,
- float maximum_animation_contents_scale,
- float starting_animation_contents_scale,
- bool animating_transform_to_screen) {
+ float page_scale_factor) {
layer->layer_tree_impl()->SetDeviceScaleFactor(device_scale_factor);
host_impl()->active_tree()->SetPageScaleOnActiveTree(page_scale_factor);
@@ -164,25 +161,14 @@ class PictureLayerImplTest : public TestLayerTreeHostBase {
layer->draw_properties().target_space_transform = scale_transform;
layer->set_contributes_to_drawn_render_surface(true);
DCHECK_EQ(layer->GetIdealContentsScale(), ideal_contents_scale);
- layer->layer_tree_impl()->property_trees()->SetAnimationScalesForTesting(
- layer->transform_tree_index(), maximum_animation_contents_scale,
- starting_animation_contents_scale);
- layer->draw_properties().screen_space_transform_is_animating =
- animating_transform_to_screen;
}
- void SetupDrawPropertiesAndUpdateTiles(
- FakePictureLayerImpl* layer,
- float ideal_contents_scale,
- float device_scale_factor,
- float page_scale_factor,
- float maximum_animation_contents_scale,
- float starting_animation_contents_scale,
- bool animating_transform_to_screen) {
+ void SetupDrawPropertiesAndUpdateTiles(FakePictureLayerImpl* layer,
+ float ideal_contents_scale,
+ float device_scale_factor,
+ float page_scale_factor) {
SetupDrawProperties(layer, ideal_contents_scale, device_scale_factor,
- page_scale_factor, maximum_animation_contents_scale,
- starting_animation_contents_scale,
- animating_transform_to_screen);
+ page_scale_factor);
layer->UpdateTiles();
}
@@ -200,21 +186,48 @@ class PictureLayerImplTest : public TestLayerTreeHostBase {
}
}
+ void SetMaximumAnimationToScreenScale(FakePictureLayerImpl* layer,
+ float maximum_animation_to_screen_scale,
+ bool affected_by_invalid_scale) {
+ layer->layer_tree_impl()
+ ->property_trees()
+ ->SetMaximumAnimationToScreenScaleForTesting(
+ layer->transform_tree_index(), maximum_animation_to_screen_scale,
+ affected_by_invalid_scale);
+ layer->draw_properties().screen_space_transform_is_animating = true;
+ }
+
void SetContentsScaleOnBothLayers(float contents_scale,
float device_scale_factor,
- float page_scale_factor,
- float maximum_animation_contents_scale,
- float starting_animation_contents_scale,
- bool animating_transform) {
- SetupDrawPropertiesAndUpdateTiles(
- pending_layer(), contents_scale, device_scale_factor, page_scale_factor,
- maximum_animation_contents_scale, starting_animation_contents_scale,
- animating_transform);
-
- SetupDrawPropertiesAndUpdateTiles(
- active_layer(), contents_scale, device_scale_factor, page_scale_factor,
- maximum_animation_contents_scale, starting_animation_contents_scale,
- animating_transform);
+ float page_scale_factor) {
+ // Sets arbitrary animation scale to ensure it's not used in any way.
+ constexpr float kArbitraryScale = 12345.0f;
+ SetMaximumAnimationToScreenScale(pending_layer(), kArbitraryScale, false);
+ pending_layer()->draw_properties().screen_space_transform_is_animating =
+ false;
+ SetupDrawPropertiesAndUpdateTiles(pending_layer(), contents_scale,
+ device_scale_factor, page_scale_factor);
+ SetMaximumAnimationToScreenScale(active_layer(), kArbitraryScale, false);
+ active_layer()->draw_properties().screen_space_transform_is_animating =
+ false;
+ SetupDrawPropertiesAndUpdateTiles(active_layer(), contents_scale,
+ device_scale_factor, page_scale_factor);
+ }
+
+ void SetContentsAndAnimationScalesOnBothLayers(
+ float contents_scale,
+ float device_scale_factor,
+ float page_scale_factor,
+ float maximum_animation_scale,
+ bool affected_by_invalid_scale) {
+ SetMaximumAnimationToScreenScale(pending_layer(), maximum_animation_scale,
+ affected_by_invalid_scale);
+ SetupDrawPropertiesAndUpdateTiles(pending_layer(), contents_scale,
+ device_scale_factor, page_scale_factor);
+ SetMaximumAnimationToScreenScale(active_layer(), maximum_animation_scale,
+ affected_by_invalid_scale);
+ SetupDrawPropertiesAndUpdateTiles(active_layer(), contents_scale,
+ device_scale_factor, page_scale_factor);
}
void ResetTilingsAndRasterScales() {
@@ -319,8 +332,7 @@ TEST_F(LegacySWPictureLayerImplTest, ExternalViewportRectForPrioritizingTiles) {
gfx::Size layer_bounds(400, 400);
SetupDefaultTrees(layer_bounds);
- SetupDrawPropertiesAndUpdateTiles(active_layer(), 1.f, 1.f, 1.f, 1.f, 0.f,
- false);
+ SetupDrawPropertiesAndUpdateTiles(active_layer(), 1.f, 1.f, 1.f);
host_impl()->AdvanceToNextFrame(base::TimeDelta::FromMilliseconds(200));
@@ -372,8 +384,7 @@ TEST_F(LegacySWPictureLayerImplTest, ViewportRectForTilePriorityIsCached) {
gfx::Size layer_bounds(400, 400);
SetupDefaultTrees(layer_bounds);
- SetupDrawPropertiesAndUpdateTiles(active_layer(), 1.f, 1.f, 1.f, 1.f, 0.f,
- false);
+ SetupDrawPropertiesAndUpdateTiles(active_layer(), 1.f, 1.f, 1.f);
host_impl()->AdvanceToNextFrame(base::TimeDelta::FromMilliseconds(200));
@@ -518,12 +529,9 @@ TEST_F(LegacySWPictureLayerImplTest, UpdateTilesCreatesTilings) {
EXPECT_EQ(0u, active_layer()->num_tilings());
SetupDrawPropertiesAndUpdateTiles(active_layer(),
- 6.f, // ideal contents scale
- 3.f, // device scale
- 2.f, // page scale
- 1.f, // maximum animation scale
- 0.f, // starting animation scale
- false);
+ 6.f, // ideal contents scale
+ 3.f, // device scale
+ 2.f); // page scale
ASSERT_EQ(2u, active_layer()->tilings()->num_tilings());
EXPECT_FLOAT_EQ(
6.f, active_layer()->tilings()->tiling_at(0)->contents_scale_key());
@@ -533,12 +541,9 @@ TEST_F(LegacySWPictureLayerImplTest, UpdateTilesCreatesTilings) {
// If we change the page scale factor, then we should get new tilings.
SetupDrawPropertiesAndUpdateTiles(active_layer(),
- 6.6f, // ideal contents scale
- 3.f, // device scale
- 2.2f, // page scale
- 1.f, // maximum animation scale
- 0.f, // starting animation scale
- false);
+ 6.6f, // ideal contents scale
+ 3.f, // device scale
+ 2.2f); // page scale
ASSERT_EQ(4u, active_layer()->tilings()->num_tilings());
EXPECT_FLOAT_EQ(
6.6f, active_layer()->tilings()->tiling_at(0)->contents_scale_key());
@@ -550,10 +555,7 @@ TEST_F(LegacySWPictureLayerImplTest, UpdateTilesCreatesTilings) {
SetupDrawPropertiesAndUpdateTiles(active_layer(),
7.26f, // ideal contents scale
3.3f, // device scale
- 2.2f, // page scale
- 1.f, // maximum animation scale
- 0.f, // starting animation scale
- false);
+ 2.2f); // page scale
ASSERT_EQ(6u, active_layer()->tilings()->num_tilings());
EXPECT_FLOAT_EQ(
7.26f, active_layer()->tilings()->tiling_at(0)->contents_scale_key());
@@ -566,10 +568,7 @@ TEST_F(LegacySWPictureLayerImplTest, UpdateTilesCreatesTilings) {
SetupDrawPropertiesAndUpdateTiles(active_layer(),
7.26f, // ideal contents scale
2.2f, // device scale
- 3.3f, // page scale
- 1.f, // maximum animation scale
- 0.f, // starting animation scale
- false);
+ 3.3f); // page scale
ASSERT_EQ(6u, active_layer()->tilings()->num_tilings());
EXPECT_FLOAT_EQ(
7.26f, active_layer()->tilings()->tiling_at(0)->contents_scale_key());
@@ -590,24 +589,18 @@ TEST_F(LegacySWPictureLayerImplTest, PendingLayerOnlyHasHighResTiling) {
EXPECT_EQ(0u, pending_layer()->tilings()->num_tilings());
SetupDrawPropertiesAndUpdateTiles(pending_layer(),
- 6.f, // ideal contents scale
- 3.f, // device scale
- 2.f, // page scale
- 1.f, // maximum animation scale
- 0.f, // starting animation scale
- false);
+ 6.f, // ideal contents scale
+ 3.f, // device scale
+ 2.f); // page scale
ASSERT_EQ(1u, pending_layer()->tilings()->num_tilings());
EXPECT_FLOAT_EQ(
6.f, pending_layer()->tilings()->tiling_at(0)->contents_scale_key());
// If we change the page scale factor, then we should get new tilings.
SetupDrawPropertiesAndUpdateTiles(pending_layer(),
- 6.6f, // ideal contents scale
- 3.f, // device scale
- 2.2f, // page scale
- 1.f, // maximum animation scale
- 0.f, // starting animation scale
- false);
+ 6.6f, // ideal contents scale
+ 3.f, // device scale
+ 2.2f); // page scale
ASSERT_EQ(1u, pending_layer()->tilings()->num_tilings());
EXPECT_FLOAT_EQ(
6.6f, pending_layer()->tilings()->tiling_at(0)->contents_scale_key());
@@ -616,10 +609,7 @@ TEST_F(LegacySWPictureLayerImplTest, PendingLayerOnlyHasHighResTiling) {
SetupDrawPropertiesAndUpdateTiles(pending_layer(),
7.26f, // ideal contents scale
3.3f, // device scale
- 2.2f, // page scale
- 1.f, // maximum animation scale
- 0.f, // starting animation scale
- false);
+ 2.2f); // page scale
ASSERT_EQ(1u, pending_layer()->tilings()->num_tilings());
EXPECT_FLOAT_EQ(
7.26f, pending_layer()->tilings()->tiling_at(0)->contents_scale_key());
@@ -629,10 +619,7 @@ TEST_F(LegacySWPictureLayerImplTest, PendingLayerOnlyHasHighResTiling) {
SetupDrawPropertiesAndUpdateTiles(pending_layer(),
7.26f, // ideal contents scale
2.2f, // device scale
- 3.3f, // page scale
- 1.f, // maximum animation scale
- 0.f, // starting animation scale
- false);
+ 3.3f); // page scale
ASSERT_EQ(1u, pending_layer()->tilings()->num_tilings());
EXPECT_FLOAT_EQ(
7.26f, pending_layer()->tilings()->tiling_at(0)->contents_scale_key());
@@ -701,7 +688,7 @@ TEST_F(LegacySWPictureLayerImplTest, ZoomOutCrash) {
SetupDefaultTrees(layer_bounds);
ResetTilingsAndRasterScales();
EXPECT_EQ(0u, active_layer()->tilings()->num_tilings());
- SetContentsScaleOnBothLayers(32.0f, 1.0f, 32.0f, 1.0f, 0.f, false);
+ SetContentsScaleOnBothLayers(32.0f, 1.0f, 32.0f);
EXPECT_EQ(32.f, active_layer()->HighResTiling()->contents_scale_key());
// Since this test simulates a pinch it needs an input handler.
@@ -710,8 +697,8 @@ TEST_F(LegacySWPictureLayerImplTest, ZoomOutCrash) {
InputHandler::Create(static_cast<CompositorDelegateForInput&>(*host_impl()));
host_impl()->GetInputHandler().PinchGestureBegin();
- SetContentsScaleOnBothLayers(1.0f, 1.0f, 1.0f, 1.0f, 0.f, false);
- SetContentsScaleOnBothLayers(1.0f, 1.0f, 1.0f, 1.0f, 0.f, false);
+ SetContentsScaleOnBothLayers(1.0f, 1.0f, 1.0f);
+ SetContentsScaleOnBothLayers(1.0f, 1.0f, 1.0f);
EXPECT_EQ(active_layer()->tilings()->NumHighResTilings(), 1);
}
@@ -732,7 +719,7 @@ TEST_F(LegacySWPictureLayerImplTest, ScaledBoundsOverflowInt) {
EXPECT_GT(static_cast<float>(layer_bounds.width()) * scale,
static_cast<float>(std::numeric_limits<int>::max()));
- SetContentsScaleOnBothLayers(scale, 1.0f, scale, 1.0f, 0.f, false);
+ SetContentsScaleOnBothLayers(scale, 1.0f, scale);
float adjusted_scale = active_layer()->HighResTiling()->contents_scale_key();
EXPECT_LT(adjusted_scale, scale);
@@ -753,7 +740,7 @@ TEST_F(LegacySWPictureLayerImplTest, PinchGestureTilings) {
SetupDefaultTrees(layer_bounds);
ResetTilingsAndRasterScales();
- SetContentsScaleOnBothLayers(2.f, 1.0f, 2.f, 1.0f, 0.f, false);
+ SetContentsScaleOnBothLayers(2.f, 1.0f, 2.f);
ASSERT_EQ(active_layer()->num_tilings(), 2u);
ASSERT_EQ(pending_layer()->num_tilings(), 1u);
EXPECT_EQ(active_layer()->tilings()->tiling_at(0)->contents_scale_key(), 2.f);
@@ -776,7 +763,7 @@ TEST_F(LegacySWPictureLayerImplTest, PinchGestureTilings) {
// Zoom out by a small amount. We should create a tiling at half
// the scale (2/kMaxScaleRatioDuringPinch).
- SetContentsScaleOnBothLayers(1.8f, 1.0f, 1.8f, 1.0f, 0.f, false);
+ SetContentsScaleOnBothLayers(1.8f, 1.0f, 1.8f);
ASSERT_EQ(3u, active_layer()->tilings()->num_tilings());
EXPECT_FLOAT_EQ(
2.0f, active_layer()->tilings()->tiling_at(0)->contents_scale_key());
@@ -795,14 +782,14 @@ TEST_F(LegacySWPictureLayerImplTest, PinchGestureTilings) {
// Zoom out further, close to our low-res scale factor. We should
// use that tiling as high-res, and not create a new tiling.
SetContentsScaleOnBothLayers(low_res_factor * 2.1f, 1.0f,
- low_res_factor * 2.1f, 1.0f, 0.f, false);
+ low_res_factor * 2.1f);
ASSERT_EQ(3u, active_layer()->tilings()->num_tilings());
EXPECT_FALSE(
active_layer()->tilings()->FindTilingWithResolution(LOW_RESOLUTION));
// Zoom in a lot now. Since we increase by increments of
// kMaxScaleRatioDuringPinch, this will create a new tiling at 4.0.
- SetContentsScaleOnBothLayers(3.8f, 1.0f, 3.8f, 1.f, 0.f, false);
+ SetContentsScaleOnBothLayers(3.8f, 1.0f, 3.8f);
ASSERT_EQ(4u, active_layer()->tilings()->num_tilings());
EXPECT_FLOAT_EQ(
4.0f, active_layer()->tilings()->tiling_at(0)->contents_scale_key());
@@ -821,7 +808,7 @@ TEST_F(LegacySWPictureLayerImplTest, PinchGestureTilings) {
// After pinch ends, set the scale to what the raster scale was updated to
// (checked above).
- SetContentsScaleOnBothLayers(4.0f, 1.0f, 4.0f, 1.f, 0.f, false);
+ SetContentsScaleOnBothLayers(4.0f, 1.0f, 4.0f);
ASSERT_EQ(4u, active_layer()->tilings()->num_tilings());
EXPECT_FLOAT_EQ(
4.0f, active_layer()->tilings()->tiling_at(0)->contents_scale_key());
@@ -841,7 +828,7 @@ TEST_F(LegacySWPictureLayerImplTest, SnappedTilingDuringZoom) {
EXPECT_EQ(0u, active_layer()->tilings()->num_tilings());
// Set up the high and low res tilings before pinch zoom.
- SetContentsScaleOnBothLayers(0.24f, 1.0f, 0.24f, 1.0f, 0.f, false);
+ SetContentsScaleOnBothLayers(0.24f, 1.0f, 0.24f);
ASSERT_EQ(2u, active_layer()->tilings()->num_tilings());
EXPECT_FLOAT_EQ(
0.24f, active_layer()->tilings()->tiling_at(0)->contents_scale_key());
@@ -861,7 +848,7 @@ TEST_F(LegacySWPictureLayerImplTest, SnappedTilingDuringZoom) {
// Zoom out by a small amount. We should create a tiling at half
// the scale (1/kMaxScaleRatioDuringPinch).
- SetContentsScaleOnBothLayers(0.2f, 1.0f, 0.2f, 1.0f, 0.f, false);
+ SetContentsScaleOnBothLayers(0.2f, 1.0f, 0.2f);
ASSERT_EQ(3u, active_layer()->tilings()->num_tilings());
EXPECT_FLOAT_EQ(
0.24f, active_layer()->tilings()->tiling_at(0)->contents_scale_key());
@@ -875,19 +862,19 @@ TEST_F(LegacySWPictureLayerImplTest, SnappedTilingDuringZoom) {
// Zoom out further, close to our low-res scale factor. We should
// use that tiling as high-res, and not create a new tiling.
- SetContentsScaleOnBothLayers(0.1f, 1.0f, 0.1f, 1.0f, 0.f, false);
+ SetContentsScaleOnBothLayers(0.1f, 1.0f, 0.1f);
ASSERT_EQ(3u, active_layer()->tilings()->num_tilings());
// Zoom in. 0.22(desired_scale) should be snapped to 0.24 during zoom-in
// because 0.22(desired_scale) is within the ratio(1.2).
- SetContentsScaleOnBothLayers(0.22f, 1.0f, 0.22f, 1.0f, 0.f, false);
+ SetContentsScaleOnBothLayers(0.22f, 1.0f, 0.22f);
ASSERT_EQ(3u, active_layer()->tilings()->num_tilings());
EXPECT_FLOAT_EQ(
0.24f, active_layer()->tilings()->tiling_at(0)->contents_scale_key());
// Zoom in a lot. Since we move in factors of two, we should get a scale that
// is a power of 2 times 0.24.
- SetContentsScaleOnBothLayers(1.f, 1.0f, 1.f, 1.0f, 0.f, false);
+ SetContentsScaleOnBothLayers(1.f, 1.0f, 1.f);
ASSERT_EQ(4u, active_layer()->tilings()->num_tilings());
EXPECT_FLOAT_EQ(
1.92f, active_layer()->tilings()->tiling_at(0)->contents_scale_key());
@@ -938,7 +925,7 @@ TEST_F(LegacySWPictureLayerImplTest, CleanUpTilings) {
// Changing the ideal but not creating new tilings.
scale = 1.5f;
page_scale = 1.5f;
- SetContentsScaleOnBothLayers(scale, 1.f, page_scale, 1.f, 0.f, false);
+ SetContentsScaleOnBothLayers(scale, 1.f, page_scale);
EXPECT_FLOAT_EQ(2u, active_layer()->tilings()->num_tilings());
EXPECT_FLOAT_EQ(
1.f, active_layer()->tilings()->tiling_at(0)->contents_scale_key());
@@ -961,7 +948,7 @@ TEST_F(LegacySWPictureLayerImplTest, CleanUpTilings) {
// Create a 1.2 scale tiling. Now we have 1.0 and 1.2 tilings. Ideal = 1.2.
scale = 1.2f;
page_scale = 1.2f;
- SetContentsScaleOnBothLayers(1.2f, 1.f, page_scale, 1.f, 0.f, false);
+ SetContentsScaleOnBothLayers(1.2f, 1.f, page_scale);
ASSERT_EQ(4u, active_layer()->tilings()->num_tilings());
EXPECT_FLOAT_EQ(
1.2f, active_layer()->tilings()->tiling_at(0)->contents_scale_key());
@@ -995,7 +982,7 @@ TEST_F(LegacySWPictureLayerImplTest, CleanUpTilings) {
active_layer()->tilings()->tiling_at(3)->contents_scale_key());
// Now move the ideal scale to 0.5. Our target stays 1.2.
- SetContentsScaleOnBothLayers(0.5f, 1.f, page_scale, 1.f, 0.f, false);
+ SetContentsScaleOnBothLayers(0.5f, 1.f, page_scale);
// The high resolution tiling is between target and ideal, so is not
// removed. The low res tiling for the old ideal=1.0 scale is removed.
@@ -1011,7 +998,7 @@ TEST_F(LegacySWPictureLayerImplTest, CleanUpTilings) {
active_layer()->tilings()->tiling_at(2)->contents_scale_key());
// Now move the ideal scale to 1.0. Our target stays 1.2.
- SetContentsScaleOnBothLayers(1.f, 1.f, page_scale, 1.f, 0.f, false);
+ SetContentsScaleOnBothLayers(1.f, 1.f, page_scale);
// All the tilings are between are target and the ideal, so they are not
// removed.
@@ -1027,8 +1014,7 @@ TEST_F(LegacySWPictureLayerImplTest, CleanUpTilings) {
active_layer()->tilings()->tiling_at(2)->contents_scale_key());
// Now move the ideal scale to 1.1 on the active layer. Our target stays 1.2.
- SetupDrawPropertiesAndUpdateTiles(active_layer(), 1.1f, 1.f, page_scale, 1.f,
- 0.f, false);
+ SetupDrawPropertiesAndUpdateTiles(active_layer(), 1.1f, 1.f, page_scale);
// Because the pending layer's ideal scale is still 1.0, our tilings fall
// in the range [1.0,1.2] and are kept.
@@ -1045,8 +1031,7 @@ TEST_F(LegacySWPictureLayerImplTest, CleanUpTilings) {
// Move the ideal scale on the pending layer to 1.1 as well. Our target stays
// 1.2 still.
- SetupDrawPropertiesAndUpdateTiles(pending_layer(), 1.1f, 1.f, page_scale, 1.f,
- 0.f, false);
+ SetupDrawPropertiesAndUpdateTiles(pending_layer(), 1.1f, 1.f, page_scale);
// Our 1.0 tiling now falls outside the range between our ideal scale and our
// target raster scale. But it is in our used tilings set, so nothing is
@@ -1088,23 +1073,19 @@ TEST_F(LegacySWPictureLayerImplTest, DontAddLowResDuringAnimation) {
float device_scale = 1.f;
float page_scale = 1.f;
float maximum_animation_scale = 1.f;
- float starting_animation_scale = kNotScaled;
- bool animating_transform = true;
+ bool affected_by_invalid_scale = false;
ResetTilingsAndRasterScales();
// Animating, so don't create low res even if there isn't one already.
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
+ SetContentsAndAnimationScalesOnBothLayers(contents_scale, device_scale,
+ page_scale, maximum_animation_scale,
+ affected_by_invalid_scale);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 1.f);
EXPECT_BOTH_EQ(num_tilings(), 1u);
// Stop animating, low res gets created.
- animating_transform = false;
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 1.f);
EXPECT_EQ(active_layer()->LowResTiling()->contents_scale_key(),
low_res_factor);
@@ -1120,10 +1101,9 @@ TEST_F(LegacySWPictureLayerImplTest, DontAddLowResDuringAnimation) {
contents_scale = 2.f;
page_scale = 2.f;
maximum_animation_scale = 2.f;
- animating_transform = true;
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
+ SetContentsAndAnimationScalesOnBothLayers(contents_scale, device_scale,
+ page_scale, maximum_animation_scale,
+ affected_by_invalid_scale);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 2.f);
EXPECT_FALSE(active_layer()->LowResTiling());
EXPECT_FALSE(pending_layer()->LowResTiling());
@@ -1131,10 +1111,7 @@ TEST_F(LegacySWPictureLayerImplTest, DontAddLowResDuringAnimation) {
EXPECT_EQ(1u, pending_layer()->num_tilings());
// Stop animating, new low res gets created for final page scale.
- animating_transform = false;
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 2.f);
EXPECT_EQ(active_layer()->LowResTiling()->contents_scale_key(),
2.f * low_res_factor);
@@ -1155,15 +1132,10 @@ TEST_F(LegacySWPictureLayerImplTest, DontAddLowResForSmallLayers) {
float low_res_factor = host_impl()->settings().low_res_contents_scale_factor;
float device_scale = 1.f;
float page_scale = 1.f;
- float maximum_animation_scale = 1.f;
- float starting_animation_scale = kNotScaled;
- bool animating_transform = false;
// Contents exactly fit on one tile at scale 1, no low res.
float contents_scale = 1.f;
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), contents_scale);
EXPECT_BOTH_EQ(num_tilings(), 1u);
@@ -1171,9 +1143,7 @@ TEST_F(LegacySWPictureLayerImplTest, DontAddLowResForSmallLayers) {
// Contents that are smaller than one tile, no low res.
contents_scale = 0.123f;
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), contents_scale);
EXPECT_BOTH_EQ(num_tilings(), 1u);
@@ -1183,9 +1153,7 @@ TEST_F(LegacySWPictureLayerImplTest, DontAddLowResForSmallLayers) {
// Any content bounds that would create more than one tile will
// generate a low res tiling.
contents_scale = 2.5f;
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), contents_scale);
EXPECT_EQ(active_layer()->LowResTiling()->contents_scale_key(),
contents_scale * low_res_factor);
@@ -1206,9 +1174,8 @@ TEST_F(LegacySWPictureLayerImplTest, DontAddLowResForSmallLayers) {
mask->ReleaseTileResources();
mask->RecreateTileResources();
- SetupDrawPropertiesAndUpdateTiles(
- mask, contents_scale, device_scale, page_scale, maximum_animation_scale,
- starting_animation_scale, animating_transform);
+ SetupDrawPropertiesAndUpdateTiles(mask, contents_scale, device_scale,
+ page_scale);
EXPECT_EQ(mask->HighResTiling()->contents_scale_key(), contents_scale);
EXPECT_EQ(mask->num_tilings(), 1u);
}
@@ -1251,7 +1218,7 @@ TEST_F(LegacySWPictureLayerImplTest, HugeBackdropFilterMasksGetScaledDown) {
gfx::SizeF mask_uv_size;
active_mask->GetContentsResourceId(&mask_resource_id, &mask_texture_size,
&mask_uv_size);
- EXPECT_NE(0u, mask_resource_id);
+ EXPECT_NE(viz::kInvalidResourceId, mask_resource_id);
EXPECT_EQ(active_mask->bounds(), mask_texture_size);
EXPECT_EQ(gfx::SizeF(1.0f, 1.0f), mask_uv_size);
@@ -1260,8 +1227,7 @@ TEST_F(LegacySWPictureLayerImplTest, HugeBackdropFilterMasksGetScaledDown) {
active_mask->ReleaseTileResources();
pending_mask->RecreateTileResources();
active_mask->RecreateTileResources();
- SetupDrawPropertiesAndUpdateTiles(active_mask, 1.f, 1.f, 1.f, 1.f, 0.f,
- false);
+ SetupDrawPropertiesAndUpdateTiles(active_mask, 1.f, 1.f, 1.f);
active_mask->HighResTiling()->CreateAllTilesForTesting();
EXPECT_EQ(1u, active_mask->HighResTiling()->AllTilesForTesting().size());
@@ -1292,7 +1258,7 @@ TEST_F(LegacySWPictureLayerImplTest, HugeBackdropFilterMasksGetScaledDown) {
// The mask resource exists.
active_mask->GetContentsResourceId(&mask_resource_id, &mask_texture_size,
&mask_uv_size);
- EXPECT_NE(0u, mask_resource_id);
+ EXPECT_NE(viz::kInvalidResourceId, mask_resource_id);
gfx::Size expected_size = active_mask->bounds();
expected_size.SetToMin(gfx::Size(max_texture_size, max_texture_size));
EXPECT_EQ(expected_size, mask_texture_size);
@@ -1303,11 +1269,10 @@ TEST_F(LegacySWPictureLayerImplTest, HugeBackdropFilterMasksGetScaledDown) {
active_mask->ReleaseTileResources();
pending_mask->RecreateTileResources();
active_mask->RecreateTileResources();
- SetupDrawPropertiesAndUpdateTiles(active_mask, 1.f, 1.f, 1.f, 1.f, 0.f,
- false);
+ SetupDrawPropertiesAndUpdateTiles(active_mask, 1.f, 1.f, 1.f);
active_mask->HighResTiling()->CreateAllTilesForTesting();
EXPECT_EQ(1u, active_mask->HighResTiling()->AllTilesForTesting().size());
- EXPECT_NE(0u, mask_resource_id);
+ EXPECT_NE(viz::kInvalidResourceId, mask_resource_id);
EXPECT_EQ(expected_size, mask_texture_size);
// Do another activate, the same holds.
@@ -1317,7 +1282,7 @@ TEST_F(LegacySWPictureLayerImplTest, HugeBackdropFilterMasksGetScaledDown) {
active_layer()->GetContentsResourceId(&mask_resource_id, &mask_texture_size,
&mask_uv_size);
EXPECT_EQ(expected_size, mask_texture_size);
- EXPECT_EQ(0u, mask_resource_id);
+ EXPECT_EQ(viz::kInvalidResourceId, mask_resource_id);
EXPECT_EQ(gfx::SizeF(1.0f, 1.0f), mask_uv_size);
// Resize even larger, so that the scale would be smaller than the minimum
@@ -1379,7 +1344,7 @@ TEST_F(LegacySWPictureLayerImplTest, ScaledBackdropFilterMaskLayer) {
gfx::SizeF mask_uv_size;
active_mask->GetContentsResourceId(&mask_resource_id, &mask_texture_size,
&mask_uv_size);
- EXPECT_NE(0u, mask_resource_id);
+ EXPECT_NE(viz::kInvalidResourceId, mask_resource_id);
gfx::Size expected_mask_texture_size =
gfx::ScaleToCeiledSize(active_mask->bounds(), 1.3f);
EXPECT_EQ(mask_texture_size, expected_mask_texture_size);
@@ -1426,7 +1391,7 @@ TEST_F(LegacySWPictureLayerImplTest, ScaledMaskLayer) {
gfx::SizeF mask_uv_size;
active_mask->GetContentsResourceId(&mask_resource_id, &mask_texture_size,
&mask_uv_size);
- EXPECT_EQ(0u, mask_resource_id);
+ EXPECT_EQ(viz::kInvalidResourceId, mask_resource_id);
EXPECT_EQ(gfx::Size(), mask_texture_size);
EXPECT_EQ(gfx::SizeF(), mask_uv_size);
}
@@ -1446,12 +1411,9 @@ TEST_F(LegacySWPictureLayerImplTest, ReleaseTileResources) {
// This should create new tilings.
SetupDrawPropertiesAndUpdateTiles(pending_layer(),
- 1.f, // ideal contents scale
- 1.f, // device scale
- 1.f, // page scale
- 1.f, // maximum animation scale
- 0.f, // starting animation_scale
- false);
+ 1.f, // ideal contents scale
+ 1.f, // device scale
+ 1.f); // page scale
EXPECT_EQ(1u, pending_layer()->tilings()->num_tilings());
}
@@ -1503,8 +1465,7 @@ TEST_F(LegacySWPictureLayerImplTest, ClampTilesToMaxTileSize) {
ResetLayerTreeFrameSink(
FakeLayerTreeFrameSink::Create3d(std::move(gl_owned)));
- SetupDrawPropertiesAndUpdateTiles(pending_layer(), 1.f, 1.f, 1.f, 1.f, 0.f,
- false);
+ SetupDrawPropertiesAndUpdateTiles(pending_layer(), 1.f, 1.f, 1.f);
ASSERT_EQ(1u, pending_layer()->tilings()->num_tilings());
pending_layer()->tilings()->tiling_at(0)->CreateAllTilesForTesting();
@@ -1538,8 +1499,7 @@ TEST_F(LegacySWPictureLayerImplTest, ClampSingleTileToToMaxTileSize) {
ResetLayerTreeFrameSink(
FakeLayerTreeFrameSink::Create3d(std::move(gl_owned)));
- SetupDrawPropertiesAndUpdateTiles(active_layer(), 1.f, 1.f, 1.f, 1.f, 0.f,
- false);
+ SetupDrawPropertiesAndUpdateTiles(active_layer(), 1.f, 1.f, 1.f);
ASSERT_LE(1u, active_layer()->tilings()->num_tilings());
active_layer()->tilings()->tiling_at(0)->CreateAllTilesForTesting();
@@ -2100,10 +2060,8 @@ TEST_F(LegacySWPictureLayerImplTest,
// Due to layer scale throttling, the raster contents scale is changed to 1,
// while the ideal is still 2.
- SetupDrawPropertiesAndUpdateTiles(active_layer(), 1.f, 1.f, 1.f, 1.f, 0.f,
- false);
- SetupDrawPropertiesAndUpdateTiles(active_layer(), 2.f, 1.f, 1.f, 1.f, 0.f,
- false);
+ SetupDrawPropertiesAndUpdateTiles(active_layer(), 1.f, 1.f, 1.f);
+ SetupDrawPropertiesAndUpdateTiles(active_layer(), 2.f, 1.f, 1.f);
EXPECT_EQ(1.f, active_layer()->HighResTiling()->contents_scale_key());
EXPECT_EQ(1.f, active_layer()->raster_contents_scale());
@@ -2523,26 +2481,78 @@ TEST_F(LegacySWPictureLayerImplTest, HighResCreatedWhenBoundsShrink) {
FakeRasterSource::CreateFilled(gfx::Size(10, 10));
SetupPendingTree(pending_raster_source);
- // Sanity checks.
EXPECT_EQ(1u, pending_layer()->tilings()->num_tilings());
- EXPECT_TRUE(pending_layer()->tilings()->FindTilingWithScaleKey(0.5f));
+ EXPECT_EQ(1, pending_layer()->tilings()->NumHighResTilings());
+ auto* high_res = pending_layer()->tilings()->FindTilingWithScaleKey(0.5f);
+ ASSERT_TRUE(high_res);
+ EXPECT_EQ(HIGH_RESOLUTION, high_res->resolution());
ActivateTree();
+ EXPECT_EQ(1u, active_layer()->tilings()->num_tilings());
+ EXPECT_EQ(1, active_layer()->tilings()->NumHighResTilings());
+ high_res = active_layer()->tilings()->FindTilingWithScaleKey(0.5f);
+ ASSERT_TRUE(high_res);
+ EXPECT_EQ(HIGH_RESOLUTION, high_res->resolution());
+
// Now, set the bounds to be 1x1, so that minimum contents scale becomes 1.
pending_raster_source = FakeRasterSource::CreateFilled(gfx::Size(1, 1));
SetupPendingTree(pending_raster_source);
- // Another sanity check.
EXPECT_EQ(1.f, pending_layer()->MinimumContentsScale());
// Since the MinContentsScale is 1, the 0.5 tiling should have been replaced
// by a 1.0 tiling during the UDP in SetupPendingTree.
EXPECT_EQ(1u, pending_layer()->tilings()->num_tilings());
- PictureLayerTiling* tiling =
- pending_layer()->tilings()->FindTilingWithScaleKey(1.0f);
- ASSERT_TRUE(tiling);
- EXPECT_EQ(HIGH_RESOLUTION, tiling->resolution());
+ high_res = pending_layer()->tilings()->FindTilingWithScaleKey(1.0f);
+ ASSERT_TRUE(high_res);
+ EXPECT_EQ(HIGH_RESOLUTION, high_res->resolution());
+
+ ActivateTree();
+ EXPECT_EQ(1u, active_layer()->tilings()->num_tilings());
+ high_res = active_layer()->tilings()->FindTilingWithScaleKey(1.0f);
+ ASSERT_TRUE(high_res);
+ EXPECT_EQ(HIGH_RESOLUTION, high_res->resolution());
+}
+
+// Tests when directly committing to the active tree, a small raster source
+// makes the minimum scale bigger than the the previous high res tiling scale,
+// causing the high res tiling (if not previously used for quads) to be removed.
+// See crbug.com/1160003.
+TEST_F(LegacySWPictureLayerImplTest,
+ HighResCreatedWhenBoundsShrinkOnActiveLayerWithUsedNonIdealScaleTiling) {
+ // Put 0.5 as high res.
+ SetInitialDeviceScaleFactor(0.5f);
+
+ SetupPendingTree(FakeRasterSource::CreateFilled(gfx::Size(10, 10)));
+ ActivateTree();
+ active_layer()
+ ->AddTiling(gfx::AxisTransform2d(1.0f, gfx::Vector2dF()))
+ ->set_resolution(NON_IDEAL_RESOLUTION);
+
+ EXPECT_EQ(2u, active_layer()->tilings()->num_tilings());
+ EXPECT_EQ(1, active_layer()->tilings()->NumHighResTilings());
+ auto* high_res = active_layer()->tilings()->FindTilingWithScaleKey(0.5f);
+ ASSERT_TRUE(high_res);
+ EXPECT_EQ(HIGH_RESOLUTION, high_res->resolution());
+ EXPECT_TRUE(active_layer()->tilings()->FindTilingWithScaleKey(1.0f));
+
+ // Now, set the bounds to be 1x1, so that minimum contents scale becomes 1.
+ active_layer()->SetBounds(gfx::Size(1, 1));
+ active_layer()->SetRasterSource(
+ FakeRasterSource::CreateFilled(gfx::Size(1, 1)), Region());
+ active_layer()->AddLastAppendQuadsTilingForTesting(
+ active_layer()->tilings()->FindTilingWithScaleKey(1.0f));
+ active_layer()->UpdateTiles();
+
+ EXPECT_EQ(1.f, active_layer()->MinimumContentsScale());
+
+ // Since the MinContentsScale is 1, the 0.5 tiling should have been replaced
+ // by a 1.0 tiling during UpdateRasterSource() and UpdateTiles().
+ EXPECT_EQ(1u, active_layer()->tilings()->num_tilings());
+ high_res = active_layer()->tilings()->FindTilingWithScaleKey(1.0f);
+ ASSERT_TRUE(high_res);
+ EXPECT_EQ(HIGH_RESOLUTION, high_res->resolution());
}
TEST_F(LegacySWPictureLayerImplTest, LowResTilingWithoutGpuRasterization) {
@@ -2612,11 +2622,9 @@ TEST_F(CommitToActiveTreePictureLayerImplTest,
SetupDefaultTrees(layer_bounds);
EXPECT_TRUE(host_impl()->use_gpu_rasterization());
- SetContentsScaleOnBothLayers(
- dsf /* contents_scale */, dsf /* device_scale_factor */,
- 1.0f /* page_scale_factor */, 1.0f /* maximum_animation_contents_scale */,
- 1.0f /* starting_animation_contents_scale */,
- false /* animating_transform */);
+ SetContentsScaleOnBothLayers(dsf /* contents_scale */,
+ dsf /* device_scale_factor */,
+ 1.0f /* page_scale_factor */);
active_layer()->HighResTiling()->UpdateAllRequiredStateForTesting();
@@ -2627,7 +2635,7 @@ TEST_F(CommitToActiveTreePictureLayerImplTest,
TEST_F(LegacySWPictureLayerImplTest, NoTilingIfDoesNotDrawContent) {
// Set up layers with tilings.
SetupDefaultTrees(gfx::Size(10, 10));
- SetContentsScaleOnBothLayers(1.f, 1.f, 1.f, 1.f, 0.f, false);
+ SetContentsScaleOnBothLayers(1.f, 1.f, 1.f);
pending_layer()->PushPropertiesTo(active_layer());
EXPECT_TRUE(pending_layer()->DrawsContent());
EXPECT_TRUE(pending_layer()->CanHaveTilings());
@@ -2659,8 +2667,7 @@ TEST_F(LegacySWPictureLayerImplTest, FirstTilingDuringPinch) {
// this case 4.
host_impl()->GetInputHandler().PinchGestureBegin();
float high_res_scale = 2.3f;
- SetContentsScaleOnBothLayers(high_res_scale, 1.f, high_res_scale, 1.f, 0.f,
- false);
+ SetContentsScaleOnBothLayers(high_res_scale, 1.f, high_res_scale);
EXPECT_EQ(4.f, pending_layer()->HighResTiling()->contents_scale_key());
}
@@ -2679,8 +2686,7 @@ TEST_F(LegacySWPictureLayerImplTest, PinchingTooSmall) {
float high_res_scale = 0.0001f;
EXPECT_LT(high_res_scale, pending_layer()->MinimumContentsScale());
- SetContentsScaleOnBothLayers(high_res_scale, 1.f, high_res_scale, 1.f, 0.f,
- false);
+ SetContentsScaleOnBothLayers(high_res_scale, 1.f, high_res_scale);
EXPECT_FLOAT_EQ(pending_layer()->MinimumContentsScale(),
pending_layer()->HighResTiling()->contents_scale_key());
}
@@ -2691,7 +2697,7 @@ TEST_F(LegacySWPictureLayerImplTest, PinchingTooSmallWithContentsScale) {
ResetTilingsAndRasterScales();
float contents_scale = 0.15f;
- SetContentsScaleOnBothLayers(contents_scale, 1.f, 1.f, 1.f, 0.f, false);
+ SetContentsScaleOnBothLayers(contents_scale, 1.f, 1.f);
ASSERT_GE(pending_layer()->num_tilings(), 0u);
EXPECT_FLOAT_EQ(contents_scale,
@@ -2708,97 +2714,130 @@ TEST_F(LegacySWPictureLayerImplTest, PinchingTooSmallWithContentsScale) {
EXPECT_LT(page_scale * contents_scale,
pending_layer()->MinimumContentsScale());
- SetContentsScaleOnBothLayers(contents_scale * page_scale, 1.f, page_scale,
- 1.f, 0.f, false);
+ SetContentsScaleOnBothLayers(contents_scale * page_scale, 1.f, page_scale);
ASSERT_GE(pending_layer()->num_tilings(), 0u);
EXPECT_FLOAT_EQ(pending_layer()->MinimumContentsScale(),
pending_layer()->HighResTiling()->contents_scale_key());
}
-TEST_F(LegacySWPictureLayerImplTest,
- ConsiderAnimationStartScaleForRasterScale) {
+TEST_F(LegacySWPictureLayerImplTest, HighResTilingDuringAnimation) {
gfx::Size viewport_size(1000, 1000);
host_impl()->active_tree()->SetDeviceViewportRect(gfx::Rect(viewport_size));
gfx::Size layer_bounds(100, 100);
SetupDefaultTrees(layer_bounds);
- float contents_scale = 2.f;
+ float contents_scale = 1.f;
float device_scale = 1.f;
float page_scale = 1.f;
- float maximum_animation_scale = 3.f;
- float starting_animation_scale = 1.f;
- bool animating_transform = true;
+ float maximum_animation_scale = 1.f;
+ bool affected_by_invalid_scale = false;
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 1.f);
- // Maximum animation scale is greater than starting animation scale
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
+ // Starting an animation should cause tiling resolution to get set to the
+ // maximum animation scale factor.
+ maximum_animation_scale = 3.f;
+ contents_scale = 2.f;
+
+ SetContentsAndAnimationScalesOnBothLayers(contents_scale, device_scale,
+ page_scale, maximum_animation_scale,
+ affected_by_invalid_scale);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 3.f);
+
+ // Further changes to scale during the animation should not cause a new
+ // high-res tiling to get created.
+ contents_scale = 4.f;
+ maximum_animation_scale = 5.f;
+
+ SetContentsAndAnimationScalesOnBothLayers(contents_scale, device_scale,
+ page_scale, maximum_animation_scale,
+ affected_by_invalid_scale);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 3.f);
- animating_transform = false;
+ // Once we stop animating, a new high-res tiling should be created.
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 4.f);
+
+ // When animating with a maxmium animation scale factor that is so large
+ // that the layer grows larger than the viewport at this scale, a new
+ // high-res tiling should get created at a source scale that the rasterized
+ // layer will not be larger than the viewport, not at its maximum scale.
+ contents_scale = 2.f;
+ maximum_animation_scale = 11.f;
+
+ SetContentsAndAnimationScalesOnBothLayers(contents_scale, device_scale,
+ page_scale, maximum_animation_scale,
+ affected_by_invalid_scale);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 10.f);
// Once we stop animating, a new high-res tiling should be created.
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
- EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 2.f);
+ contents_scale = 11.f;
- // Starting animation scale greater than maximum animation scale.
- // Bounds at starting scale within the viewport.
- animating_transform = true;
- starting_animation_scale = 5.f;
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 11.f);
+
+ // When animating with a maxmium animation scale factor that is so large
+ // that the layer grows larger than the viewport at this scale, and where
+ // the initial source scale is < 1, a new high-res tiling should get created
+ // at a source scale that the rasterized layer will not be larger than the
+ // viewport.
+ contents_scale = 0.1f;
+ maximum_animation_scale = 11.f;
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
- EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 5.f);
+ SetContentsAndAnimationScalesOnBothLayers(contents_scale, device_scale,
+ page_scale, maximum_animation_scale,
+ affected_by_invalid_scale);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 10.f);
// Once we stop animating, a new high-res tiling should be created.
- animating_transform = false;
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
- EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 2.f);
+ contents_scale = 12.f;
+
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 12.f);
- // Starting Animation scale greater than maximum animation scale.
- // Bounds at starting scale outside the viewport.
- animating_transform = true;
- starting_animation_scale = 11.f;
+ // When animating toward a smaller scale, but that is still so large that the
+ // layer grows larger than the viewport at this scale, a new high-res tiling
+ // should get created at a source scale that the rasterized layer is not
+ // larger than the viewport.
+ contents_scale = 11.f;
+ maximum_animation_scale = 11.f;
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
+ SetContentsAndAnimationScalesOnBothLayers(contents_scale, device_scale,
+ page_scale, maximum_animation_scale,
+ affected_by_invalid_scale);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 10.f);
+
+ // Once we stop animating, a new high-res tiling should be created.
+ contents_scale = 11.f;
+
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 11.f);
}
-TEST_F(LegacySWPictureLayerImplTest, HighResTilingDuringAnimation) {
- gfx::Size viewport_size(1000, 1000);
+TEST_F(LegacySWPictureLayerImplTest, HighResTilingDuringAnimationWideLayer) {
+ gfx::Size viewport_size(2048, 2048);
host_impl()->active_tree()->SetDeviceViewportRect(gfx::Rect(viewport_size));
- gfx::Size layer_bounds(100, 100);
+ gfx::Size layer_bounds(1000000, 32);
SetupDefaultTrees(layer_bounds);
float contents_scale = 1.f;
float device_scale = 1.f;
float page_scale = 1.f;
float maximum_animation_scale = 1.f;
- float starting_animation_scale = kNotScaled;
- bool animating_transform = false;
+ bool affected_by_invalid_scale = false;
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 1.f);
// Starting an animation should cause tiling resolution to get set to the
// maximum animation scale factor.
- animating_transform = true;
maximum_animation_scale = 3.f;
contents_scale = 2.f;
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
+ SetContentsAndAnimationScalesOnBothLayers(contents_scale, device_scale,
+ page_scale, maximum_animation_scale,
+ affected_by_invalid_scale);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 3.f);
// Further changes to scale during the animation should not cause a new
@@ -2806,127 +2845,221 @@ TEST_F(LegacySWPictureLayerImplTest, HighResTilingDuringAnimation) {
contents_scale = 4.f;
maximum_animation_scale = 5.f;
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
+ SetContentsAndAnimationScalesOnBothLayers(contents_scale, device_scale,
+ page_scale, maximum_animation_scale,
+ affected_by_invalid_scale);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 3.f);
// Once we stop animating, a new high-res tiling should be created.
- animating_transform = false;
-
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
- EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 4.f);
-
- // When animating with an unknown animation scale factors, a new high-res
- // tiling should be created at the current contents scale.
- animating_transform = true;
- contents_scale = 2.f;
- maximum_animation_scale = kNotScaled;
-
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
- EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 2.f);
-
- // Further changes to scale during the animation should not cause a new
- // high-res tiling to get created.
- contents_scale = 3.f;
-
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
- EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 2.f);
-
- // Once we stop animating, a new high-res tiling should be created.
- animating_transform = false;
- contents_scale = 4.f;
-
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 4.f);
// When animating with a maxmium animation scale factor that is so large
- // that the layer grows larger than the viewport at this scale, a new
- // high-res tiling should get created at a source scale that the rasterized
- // layer will not be larger than the viewport, not at its maximum scale.
- animating_transform = true;
+ // that the layer grows larger than the viewport at this scale, a new high-res
+ // tiling should get created at a source scale that the rasterized visible
+ // rect will not be larger than the viewport, not at its maximum scale.
contents_scale = 2.f;
maximum_animation_scale = 11.f;
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
- EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 10.f);
+ SetContentsAndAnimationScalesOnBothLayers(contents_scale, device_scale,
+ page_scale, maximum_animation_scale,
+ affected_by_invalid_scale);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 8.f);
// Once we stop animating, a new high-res tiling should be created.
- animating_transform = false;
contents_scale = 11.f;
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 11.f);
// When animating with a maxmium animation scale factor that is so large
// that the layer grows larger than the viewport at this scale, and where
- // the intial source scale is < 1, a new high-res tiling should get created
- // at a source scale that the rasterized layer will not be larger than the
- // viewport.
- animating_transform = true;
+ // the initial source scale is < 1, a new high-res tiling should get created
+ // at a source scale that the rasterized visible rect will not be larger than
+ // the viewport.
contents_scale = 0.1f;
maximum_animation_scale = 11.f;
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
- EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 10.f);
+ SetContentsAndAnimationScalesOnBothLayers(contents_scale, device_scale,
+ page_scale, maximum_animation_scale,
+ affected_by_invalid_scale);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 8.f);
// Once we stop animating, a new high-res tiling should be created.
- animating_transform = false;
contents_scale = 12.f;
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 12.f);
// When animating toward a smaller scale, but that is still so large that the
// layer grows larger than the viewport at this scale, a new high-res tiling
- // should get created at a source scale that the rasterized layer is not
- // larger than the viewport.
- animating_transform = true;
+ // should get created at a source scale that the rasterized visible rect is
+ // not larger than the viewport.
contents_scale = 11.f;
maximum_animation_scale = 11.f;
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
- EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 10.f);
+ SetContentsAndAnimationScalesOnBothLayers(contents_scale, device_scale,
+ page_scale, maximum_animation_scale,
+ affected_by_invalid_scale);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 8.f);
// Once we stop animating, a new high-res tiling should be created.
- animating_transform = false;
contents_scale = 11.f;
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 11.f);
+}
+
+TEST_F(LegacySWPictureLayerImplTest,
+ HighResTilingDuringAnimationSmallerAnimationScale) {
+ gfx::Size viewport_size(1000, 1000);
+ host_impl()->active_tree()->SetDeviceViewportRect(gfx::Rect(viewport_size));
+
+ gfx::Size layer_bounds(100, 100);
+ SetupDefaultTrees(layer_bounds);
+
+ float contents_scale = 1.f;
+ float device_scale = 1.f;
+ float page_scale = 1.f;
+ float maximum_animation_scale = 1.f;
+ bool affected_by_invalid_scale = false;
+
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 1.f);
- // When animating with an unknown animation scale factors, a new high-res
- // tiling should be created at the native scale if the current contents
- // scale is smaller.
- animating_transform = true;
+ // When animating with smaller animation scale factors (i.e. not accurately
+ // calculated because some limitations, e.g. nested scales), a new high-res
+ // tiling should be created at the current contents scale.
contents_scale = 0.5f;
- maximum_animation_scale = kNotScaled;
+ maximum_animation_scale = 0.4f;
+
+ SetContentsAndAnimationScalesOnBothLayers(contents_scale, device_scale,
+ page_scale, maximum_animation_scale,
+ affected_by_invalid_scale);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 0.5f);
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
- EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(),
- page_scale * device_scale);
+ // Increase the contents scale a bit, and the current high-res tiling should
+ // still be used.
+ contents_scale = 0.6f;
+ SetContentsAndAnimationScalesOnBothLayers(contents_scale, device_scale,
+ page_scale, maximum_animation_scale,
+ affected_by_invalid_scale);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 0.5f);
+
+ // A new high-res tiling should be created at the current contents scale if
+ // its >1.5x of the current high-res scale.
+ contents_scale = 0.8f;
+ SetContentsAndAnimationScalesOnBothLayers(contents_scale, device_scale,
+ page_scale, maximum_animation_scale,
+ affected_by_invalid_scale);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 0.8f);
+
+ // Reduce the contents scale, and the current high-res tiling should still be
+ // used.
+ contents_scale = 0.4f;
+ SetContentsAndAnimationScalesOnBothLayers(contents_scale, device_scale,
+ page_scale, maximum_animation_scale,
+ affected_by_invalid_scale);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 0.8f);
+}
+
+TEST_F(LegacySWPictureLayerImplTest,
+ HighResTilingDuringAnimationSmallerAnimationScaleWithInvalidScale) {
+ gfx::Size viewport_size(1000, 1000);
+ host_impl()->active_tree()->SetDeviceViewportRect(gfx::Rect(viewport_size));
+
+ gfx::Size layer_bounds(100, 100);
+ SetupDefaultTrees(layer_bounds);
+
+ float contents_scale = 1.f;
+ float device_scale = 1.f;
+ float page_scale = 1.f;
+ float maximum_animation_scale = 1.f;
+ bool affected_by_invalid_scale = true;
+
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 1.f);
+
+ // When animating with smaller animation scale factors (i.e. not accurately
+ // calculated because some limitations, e.g. nested scales), a new high-res
+ // tiling should be created at the current contents scale.
+ contents_scale = 0.5f;
+ maximum_animation_scale = 0.4f;
+
+ SetContentsAndAnimationScalesOnBothLayers(contents_scale, device_scale,
+ page_scale, maximum_animation_scale,
+ affected_by_invalid_scale);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 0.5f);
+
+ // Increase the contents scale a bit, and the current high-res tiling should
+ // still be used.
+ contents_scale = 0.6f;
+ SetContentsAndAnimationScalesOnBothLayers(contents_scale, device_scale,
+ page_scale, maximum_animation_scale,
+ affected_by_invalid_scale);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 0.5f);
+
+ // Raster scale change during animation should be avoided.
+ contents_scale = 1.2f;
+ SetContentsAndAnimationScalesOnBothLayers(contents_scale, device_scale,
+ page_scale, maximum_animation_scale,
+ affected_by_invalid_scale);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 0.5f);
+
+ // Raster scale change during animation should be avoided.
+ contents_scale = 0.4f;
+ SetContentsAndAnimationScalesOnBothLayers(contents_scale, device_scale,
+ page_scale, maximum_animation_scale,
+ affected_by_invalid_scale);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 0.5f);
+
+ // Should update raster scale if the cache is invalidated (simulating that a
+ // new property tree is pushed).
+ contents_scale = 1.2f;
+ SetMaximumAnimationToScreenScale(pending_layer(), maximum_animation_scale,
+ affected_by_invalid_scale);
+ host_impl()->pending_tree()->property_trees()->ResetCachedData();
+ SetupDrawPropertiesAndUpdateTiles(pending_layer(), contents_scale,
+ device_scale, page_scale);
+ SetMaximumAnimationToScreenScale(active_layer(), maximum_animation_scale,
+ affected_by_invalid_scale);
+ host_impl()->active_tree()->property_trees()->ResetCachedData();
+ SetupDrawPropertiesAndUpdateTiles(active_layer(), contents_scale,
+ device_scale, page_scale);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 1.2f);
+}
+
+TEST_F(LegacySWPictureLayerImplTest, ViewportSizeChangeDuringAnimation) {
+ gfx::Size layer_bounds(100, 100);
+ SetupDefaultTrees(layer_bounds);
+
+ host_impl()->pending_tree()->SetDeviceViewportRect(gfx::Rect());
+
+ EXPECT_EQ(pending_layer()->HighResTiling()->contents_scale_key(), 1.f);
+
+ float maximum_animation_scale = 20.f;
+ // This flag should be ignored on viewport size change.
+ bool affected_by_invalid_scale = true;
+
+ // Starting an animation should cause tiling resolution to get set to the
+ // maximum animation scale factor, clamped by the viewport size (using default
+ // minimum 500x500 as the viewport is empty for now).
+ SetMaximumAnimationToScreenScale(pending_layer(), maximum_animation_scale,
+ affected_by_invalid_scale);
+ pending_layer()->UpdateTiles();
+ EXPECT_EQ(pending_layer()->HighResTiling()->contents_scale_key(), 5.f);
+
+ // Setting viewport rect smaller than the minimum won't change raster scale.
+ host_impl()->pending_tree()->SetDeviceViewportRect(gfx::Rect(400, 400));
+ SetMaximumAnimationToScreenScale(pending_layer(), maximum_animation_scale,
+ affected_by_invalid_scale);
+ pending_layer()->UpdateTiles();
+ EXPECT_EQ(pending_layer()->HighResTiling()->contents_scale_key(), 5.f);
+
+ // For a larger viewport size, the clamped scale is also larger.
+ host_impl()->pending_tree()->SetDeviceViewportRect(gfx::Rect(1000, 200));
+ SetMaximumAnimationToScreenScale(pending_layer(), maximum_animation_scale,
+ affected_by_invalid_scale);
+ pending_layer()->UpdateTiles();
+ EXPECT_EQ(pending_layer()->HighResTiling()->contents_scale_key(), 10.f);
}
TEST_F(LegacySWPictureLayerImplTest,
@@ -2941,8 +3074,7 @@ TEST_F(LegacySWPictureLayerImplTest,
float device_scale = 1.f;
float page_scale = 1.f;
float maximum_animation_scale = 1.f;
- float starting_animation_scale = kNotScaled;
- bool animating_transform = false;
+ bool affected_by_invalid_scale = false;
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 1.f);
@@ -2951,41 +3083,31 @@ TEST_F(LegacySWPictureLayerImplTest,
// Starting an animation should cause tiling resolution to get set to the
// maximum animation scale factor.
- animating_transform = true;
maximum_animation_scale = 2.f;
contents_scale = 1.f;
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
+ SetContentsAndAnimationScalesOnBothLayers(contents_scale, device_scale,
+ page_scale, maximum_animation_scale,
+ affected_by_invalid_scale);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 2.f);
// Once we stop animating, because we have a will-change: transform hint
// we should not reset the scale factor.
- animating_transform = false;
-
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 2.f);
// Starting an animation with a different maximum animation scale should
// not cause a change either.
- animating_transform = true;
maximum_animation_scale = 1.5f;
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
+ SetContentsAndAnimationScalesOnBothLayers(contents_scale, device_scale,
+ page_scale, maximum_animation_scale,
+ affected_by_invalid_scale);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 2.f);
// Again, stop animating, because we have a will-change: transform hint
// we should not reset the scale factor.
- animating_transform = false;
-
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 2.f);
}
@@ -3000,20 +3122,18 @@ TEST_F(LegacySWPictureLayerImplTest, HighResTilingDuringAnimationAspectRatio) {
float device_scale = 1.f;
float page_scale = 1.f;
float maximum_animation_scale = 1.f;
- float starting_animation_scale = kNotScaled;
- bool animating_transform = false;
+ bool affected_by_invalid_scale = false;
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 1.f);
// Allow rastering at maximum scale if the animation size is smaller than
- // the square of the maximum viewporrt dimension.
- animating_transform = true;
+ // the square of the maximum viewport dimension.
contents_scale = 2.f;
maximum_animation_scale = 15.f;
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
+ SetContentsAndAnimationScalesOnBothLayers(contents_scale, device_scale,
+ page_scale, maximum_animation_scale,
+ affected_by_invalid_scale);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 15.f);
}
@@ -3029,21 +3149,19 @@ TEST_F(LegacySWPictureLayerImplTest,
float device_scale = 1.f;
float page_scale = 1.f;
float maximum_animation_scale = 1.f;
- float starting_animation_scale = kNotScaled;
- bool animating_transform = false;
+ bool affected_by_invalid_scale = false;
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 1.f);
// The maximum animation scale exceeds the squared size of the maximum
// viewport dimension, so raster scale should be shrunk to make the
// rasterized layer not larger than the viewport.
- animating_transform = true;
contents_scale = 2.f;
maximum_animation_scale = 21.f;
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
+ SetContentsAndAnimationScalesOnBothLayers(contents_scale, device_scale,
+ page_scale, maximum_animation_scale,
+ affected_by_invalid_scale);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 20.f);
}
@@ -3489,29 +3607,20 @@ TEST_F(LegacySWPictureLayerImplTest, RasterScaleChangeWithoutAnimation) {
float contents_scale = 2.f;
float device_scale = 1.5f;
float page_scale = 1.f;
- float maximum_animation_scale = 1.f;
- float starting_animation_scale = kNotScaled;
- bool animating_transform = false;
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 2.f);
// Changing the source scale without being in an animation will cause
// the layer to change scale.
contents_scale = 3.f;
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 3.f);
contents_scale = 0.5f;
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 0.5f);
// If we change the layer contents scale after setting will change
@@ -3522,9 +3631,7 @@ TEST_F(LegacySWPictureLayerImplTest, RasterScaleChangeWithoutAnimation) {
contents_scale = 0.75f;
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale);
// The scale is clamped to the native scale.
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 1.5f);
@@ -3532,17 +3639,13 @@ TEST_F(LegacySWPictureLayerImplTest, RasterScaleChangeWithoutAnimation) {
// contents scale.
contents_scale = 2.f;
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 1.5f);
// Ditto.
contents_scale = 20.f;
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 1.5f);
// Disabling the will-change hint will once again make the raster scale update
@@ -3552,9 +3655,7 @@ TEST_F(LegacySWPictureLayerImplTest, RasterScaleChangeWithoutAnimation) {
contents_scale = 3.f;
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 3.f);
}
@@ -3567,13 +3668,8 @@ TEST_F(LegacySWPictureLayerImplTest, TinyRasterScale) {
float contents_scale = 0.01f;
float device_scale = 1.5f;
float page_scale = 1.f;
- float maximum_animation_scale = 1.f;
- float starting_animation_scale = kNotScaled;
- bool animating_transform = false;
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 0.01f);
// If we change the layer contents scale after setting will change
@@ -3582,9 +3678,7 @@ TEST_F(LegacySWPictureLayerImplTest, TinyRasterScale) {
GetTransformNode(active_layer())->will_change_transform = true;
GetTransformNode(pending_layer())->will_change_transform = true;
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale);
// The scale is clamped to the native scale.
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 0.01f);
@@ -3592,25 +3686,19 @@ TEST_F(LegacySWPictureLayerImplTest, TinyRasterScale) {
// contents scale.
contents_scale = 0.02f;
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 0.01f);
// ... unless the difference is very big.
contents_scale = 0.12f;
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 0.12f);
// Bigger scale will be clamped to the native scale.
contents_scale = 0.5f;
- SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale,
- maximum_animation_scale,
- starting_animation_scale, animating_transform);
+ SetContentsScaleOnBothLayers(contents_scale, device_scale, page_scale);
EXPECT_BOTH_EQ(HighResTiling()->contents_scale_key(), 1.5f);
}
@@ -3690,24 +3778,18 @@ TEST_F(NoLowResPictureLayerImplTest, ManageTilingsCreatesTilings) {
ResetTilingsAndRasterScales();
SetupDrawPropertiesAndUpdateTiles(active_layer(),
- 6.f, // ideal contents scale
- 3.f, // device scale
- 2.f, // page scale
- 1.f, // maximum animation scale
- 0.f, // starting animation scale
- false);
+ 6.f, // ideal contents scale
+ 3.f, // device scale
+ 2.f); // page scale
ASSERT_EQ(1u, active_layer()->tilings()->num_tilings());
EXPECT_FLOAT_EQ(
6.f, active_layer()->tilings()->tiling_at(0)->contents_scale_key());
// If we change the page scale factor, then we should get new tilings.
SetupDrawPropertiesAndUpdateTiles(active_layer(),
- 6.6f, // ideal contents scale
- 3.f, // device scale
- 2.2f, // page scale
- 1.f, // maximum animation scale
- 0.f, // starting animation scale
- false);
+ 6.6f, // ideal contents scale
+ 3.f, // device scale
+ 2.2f); // page scale
ASSERT_EQ(2u, active_layer()->tilings()->num_tilings());
EXPECT_FLOAT_EQ(
6.6f, active_layer()->tilings()->tiling_at(0)->contents_scale_key());
@@ -3716,10 +3798,7 @@ TEST_F(NoLowResPictureLayerImplTest, ManageTilingsCreatesTilings) {
SetupDrawPropertiesAndUpdateTiles(active_layer(),
7.26f, // ideal contents scale
3.3f, // device scale
- 2.2f, // page scale
- 1.f, // maximum animation scale
- 0.f, // starting animation scale
- false);
+ 2.2f); // page scale
ASSERT_EQ(3u, active_layer()->tilings()->num_tilings());
EXPECT_FLOAT_EQ(
7.26f, active_layer()->tilings()->tiling_at(0)->contents_scale_key());
@@ -3729,10 +3808,7 @@ TEST_F(NoLowResPictureLayerImplTest, ManageTilingsCreatesTilings) {
SetupDrawPropertiesAndUpdateTiles(active_layer(),
7.26f, // ideal contents scale
2.2f, // device scale
- 3.3f, // page scale
- 1.f, // maximum animation scale
- 0.f, // starting animation scale
- false);
+ 3.3f); // page scale
ASSERT_EQ(3u, active_layer()->tilings()->num_tilings());
EXPECT_FLOAT_EQ(
7.26f, active_layer()->tilings()->tiling_at(0)->contents_scale_key());
@@ -3748,24 +3824,18 @@ TEST_F(NoLowResPictureLayerImplTest, PendingLayerOnlyHasHighResTiling) {
ResetTilingsAndRasterScales();
SetupDrawPropertiesAndUpdateTiles(pending_layer(),
- 6.f, // ideal contents scale
- 3.f, // device scale
- 2.f, // page scale
- 1.f, // maximum animation scale
- 0.f, // starting animation scale
- false);
+ 6.f, // ideal contents scale
+ 3.f, // device scale
+ 2.f); // page scale
ASSERT_EQ(1u, pending_layer()->tilings()->num_tilings());
EXPECT_FLOAT_EQ(
6.f, pending_layer()->tilings()->tiling_at(0)->contents_scale_key());
// If we change the page scale factor, then we should get new tilings.
SetupDrawPropertiesAndUpdateTiles(pending_layer(),
- 6.6f, // ideal contents scale
- 3.f, // device scale
- 2.2f, // page scale
- 1.f, // maximum animation scale
- 0.f, // starting animation scale
- false);
+ 6.6f, // ideal contents scale
+ 3.f, // device scale
+ 2.2f); // page scale
ASSERT_EQ(1u, pending_layer()->tilings()->num_tilings());
EXPECT_FLOAT_EQ(
6.6f, pending_layer()->tilings()->tiling_at(0)->contents_scale_key());
@@ -3774,10 +3844,7 @@ TEST_F(NoLowResPictureLayerImplTest, PendingLayerOnlyHasHighResTiling) {
SetupDrawPropertiesAndUpdateTiles(pending_layer(),
7.26f, // ideal contents scale
3.3f, // device scale
- 2.2f, // page scale
- 1.f, // maximum animation scale
- 0.f, // starting animation scale
- false);
+ 2.2f); // page scale
ASSERT_EQ(1u, pending_layer()->tilings()->num_tilings());
EXPECT_FLOAT_EQ(
7.26f, pending_layer()->tilings()->tiling_at(0)->contents_scale_key());
@@ -3787,10 +3854,7 @@ TEST_F(NoLowResPictureLayerImplTest, PendingLayerOnlyHasHighResTiling) {
SetupDrawPropertiesAndUpdateTiles(pending_layer(),
7.26f, // ideal contents scale
2.2f, // device scale
- 3.3f, // page scale
- 1.f, // maximum animation scale
- 0.f, // starting animation scale
- false);
+ 3.3f); // page scale
ASSERT_EQ(1u, pending_layer()->tilings()->num_tilings());
EXPECT_FLOAT_EQ(
7.26f, pending_layer()->tilings()->tiling_at(0)->contents_scale_key());
@@ -3871,8 +3935,7 @@ TEST_F(NoLowResPictureLayerImplTest, CleanUpTilings) {
GetTransformNode(active_layer())->will_change_transform = true;
ResetTilingsAndRasterScales();
- SetContentsScaleOnBothLayers(scale, device_scale, page_scale, 1.f, 0.f,
- false);
+ SetContentsScaleOnBothLayers(scale, device_scale, page_scale);
ASSERT_EQ(1u, active_layer()->tilings()->num_tilings());
// Ensure UpdateTiles won't remove any tilings. Note this is unrelated to
@@ -3895,8 +3958,7 @@ TEST_F(NoLowResPictureLayerImplTest, CleanUpTilings) {
// Changing the ideal but not creating new tilings.
scale *= 1.5f;
page_scale *= 1.5f;
- SetContentsScaleOnBothLayers(scale, device_scale, page_scale, 1.f, 0.f,
- false);
+ SetContentsScaleOnBothLayers(scale, device_scale, page_scale);
ASSERT_EQ(1u, active_layer()->tilings()->num_tilings());
// The tilings are still our target scale, so they aren't removed.
@@ -3909,7 +3971,7 @@ TEST_F(NoLowResPictureLayerImplTest, CleanUpTilings) {
// Create a 1.2 scale tiling. Now we have 1.0 and 1.2 tilings. Ideal = 1.2.
scale /= 4.f;
page_scale /= 4.f;
- SetContentsScaleOnBothLayers(1.2f, device_scale, page_scale, 1.f, 0.f, false);
+ SetContentsScaleOnBothLayers(1.2f, device_scale, page_scale);
ASSERT_EQ(2u, active_layer()->tilings()->num_tilings());
EXPECT_FLOAT_EQ(
1.f, active_layer()->tilings()->tiling_at(1)->contents_scale_key());
@@ -3924,7 +3986,7 @@ TEST_F(NoLowResPictureLayerImplTest, CleanUpTilings) {
ASSERT_EQ(2u, active_layer()->tilings()->num_tilings());
// Now move the ideal scale to 0.5. Our target stays 1.2.
- SetContentsScaleOnBothLayers(0.5f, device_scale, page_scale, 1.f, 0.f, false);
+ SetContentsScaleOnBothLayers(0.5f, device_scale, page_scale);
// The high resolution tiling is between target and ideal, so is not
// removed. The low res tiling for the old ideal=1.0 scale is removed.
@@ -3933,7 +3995,7 @@ TEST_F(NoLowResPictureLayerImplTest, CleanUpTilings) {
ASSERT_EQ(2u, active_layer()->tilings()->num_tilings());
// Now move the ideal scale to 1.0. Our target stays 1.2.
- SetContentsScaleOnBothLayers(1.f, device_scale, page_scale, 1.f, 0.f, false);
+ SetContentsScaleOnBothLayers(1.f, device_scale, page_scale);
// All the tilings are between are target and the ideal, so they are not
// removed.
@@ -3943,7 +4005,7 @@ TEST_F(NoLowResPictureLayerImplTest, CleanUpTilings) {
// Now move the ideal scale to 1.1 on the active layer. Our target stays 1.2.
SetupDrawPropertiesAndUpdateTiles(active_layer(), 1.1f, device_scale,
- page_scale, 1.f, 0.f, false);
+ page_scale);
// Because the pending layer's ideal scale is still 1.0, our tilings fall
// in the range [1.0,1.2] and are kept.
@@ -3954,7 +4016,7 @@ TEST_F(NoLowResPictureLayerImplTest, CleanUpTilings) {
// Move the ideal scale on the pending layer to 1.1 as well. Our target stays
// 1.2 still.
SetupDrawPropertiesAndUpdateTiles(pending_layer(), 1.1f, device_scale,
- page_scale, 1.f, 0.f, false);
+ page_scale);
// Our 1.0 tiling now falls outside the range between our ideal scale and our
// target raster scale. But it is in our used tilings set, so nothing is
@@ -3991,12 +4053,9 @@ TEST_F(NoLowResPictureLayerImplTest, ReleaseTileResources) {
// This should create new tilings.
SetupDrawPropertiesAndUpdateTiles(pending_layer(),
- 1.3f, // ideal contents scale
- 2.7f, // device scale
- 3.2f, // page scale
- 1.f, // maximum animation scale
- 0.f, // starting animation scale
- false);
+ 1.3f, // ideal contents scale
+ 2.7f, // device scale
+ 3.2f); // page scale
EXPECT_EQ(1u, pending_layer()->tilings()->num_tilings());
}
@@ -4008,8 +4067,7 @@ TEST_F(LegacySWPictureLayerImplTest, SharedQuadStateContainsMaxTilingScale) {
SetupDefaultTrees(layer_bounds);
ResetTilingsAndRasterScales();
- SetupDrawPropertiesAndUpdateTiles(active_layer(), 2.5f, 1.f, 1.f, 1.f, 0.f,
- false);
+ SetupDrawPropertiesAndUpdateTiles(active_layer(), 2.5f, 1.f, 1.f);
float max_contents_scale = active_layer()->MaximumTilingContentsScale();
EXPECT_EQ(2.5f, max_contents_scale);
@@ -4894,8 +4952,7 @@ TEST_F(LegacySWPictureLayerImplTest, ChangeInViewportAllowsTilingUpdates) {
// Update tiles.
pending_layer()->draw_properties().visible_layer_rect = viewport;
pending_layer()->draw_properties().screen_space_transform = transform;
- SetupDrawPropertiesAndUpdateTiles(pending_layer(), 1.f, 1.f, 1.f, 1.f, 0.f,
- false);
+ SetupDrawPropertiesAndUpdateTiles(pending_layer(), 1.f, 1.f, 1.f);
pending_layer()->HighResTiling()->UpdateAllRequiredStateForTesting();
// Ensure we can't activate.
@@ -4908,8 +4965,7 @@ TEST_F(LegacySWPictureLayerImplTest, ChangeInViewportAllowsTilingUpdates) {
// Update tiles.
pending_layer()->draw_properties().visible_layer_rect = viewport;
pending_layer()->draw_properties().screen_space_transform = transform;
- SetupDrawPropertiesAndUpdateTiles(pending_layer(), 1.f, 1.f, 1.f, 1.f, 0.f,
- false);
+ SetupDrawPropertiesAndUpdateTiles(pending_layer(), 1.f, 1.f, 1.f);
pending_layer()->HighResTiling()->UpdateAllRequiredStateForTesting();
// Make sure all viewport tiles (viewport from the tiling) are ready to draw.
@@ -4961,9 +5017,9 @@ TEST_F(LegacySWPictureLayerImplTest, CloneMissingRecordings) {
// dropped recordings). This will cause us to be missing some tiles.
SetupPendingTreeWithFixedTileSize(partial_raster_source, tile_size,
Region(gfx::Rect(layer_bounds)));
- EXPECT_EQ(3u * 3u, pending_tiling->AllTilesForTesting().size());
+ EXPECT_EQ(4u * 4u, pending_tiling->AllTilesForTesting().size());
EXPECT_FALSE(pending_tiling->TileAt(0, 0));
- EXPECT_FALSE(pending_tiling->TileAt(1, 1));
+ EXPECT_TRUE(pending_tiling->TileAt(1, 1));
EXPECT_TRUE(pending_tiling->TileAt(2, 2));
// Active is not affected yet.
@@ -4971,9 +5027,9 @@ TEST_F(LegacySWPictureLayerImplTest, CloneMissingRecordings) {
// Activate the tree. The same tiles go missing on the active tree.
ActivateTree();
- EXPECT_EQ(3u * 3u, active_tiling->AllTilesForTesting().size());
+ EXPECT_EQ(4u * 4u, active_tiling->AllTilesForTesting().size());
EXPECT_FALSE(active_tiling->TileAt(0, 0));
- EXPECT_FALSE(active_tiling->TileAt(1, 1));
+ EXPECT_TRUE(active_tiling->TileAt(1, 1));
EXPECT_TRUE(active_tiling->TileAt(2, 2));
// Now put a full recording on the pending tree again. We'll get all our tiles
@@ -4986,7 +5042,7 @@ TEST_F(LegacySWPictureLayerImplTest, CloneMissingRecordings) {
Tile::Id tile22 = pending_tiling->TileAt(2, 2)->id();
// Active is not affected yet.
- EXPECT_EQ(3u * 3u, active_tiling->AllTilesForTesting().size());
+ EXPECT_EQ(4u * 4u, active_tiling->AllTilesForTesting().size());
// Activate the tree. The tiles are moved to the active tree.
ActivateTree();
@@ -5161,7 +5217,7 @@ TEST_F(LegacySWPictureLayerImplTest, UpdateLCDTextPushToActiveTree) {
SetupPendingTree(FakeRasterSource::CreateFilledWithText(gfx::Size(200, 200)));
float page_scale = 4.f;
SetupDrawPropertiesAndUpdateTiles(pending_layer(), page_scale, 1.0f,
- page_scale, 1.0f, 0.f, false);
+ page_scale);
EXPECT_TRUE(pending_layer()->can_use_lcd_text());
EXPECT_TRUE(pending_layer()->HighResTiling()->can_use_lcd_text());
ActivateTree();
@@ -5178,7 +5234,7 @@ TEST_F(LegacySWPictureLayerImplTest, UpdateLCDTextPushToActiveTree) {
SetupPendingTree(FakeRasterSource::CreateFilledWithText(gfx::Size(200, 200)));
SetupDrawPropertiesAndUpdateTiles(pending_layer(), page_scale, 1.0f,
- page_scale, 1.0f, 0.f, false);
+ page_scale);
pending_layer()->SetContentsOpaque(false);
pending_layer()->UpdateTiles();
EXPECT_FALSE(pending_layer()->can_use_lcd_text());
@@ -5376,7 +5432,7 @@ TEST_F(NoLowResPictureLayerImplTest, LowResWasHighResCollision) {
ResetTilingsAndRasterScales();
float page_scale = 2.f;
- SetContentsScaleOnBothLayers(page_scale, 1.0f, page_scale, 1.0f, 0.f, false);
+ SetContentsScaleOnBothLayers(page_scale, 1.0f, page_scale);
EXPECT_BOTH_EQ(num_tilings(), 1u);
EXPECT_BOTH_EQ(tilings()->tiling_at(0)->contents_scale_key(), page_scale);
@@ -5390,7 +5446,7 @@ TEST_F(NoLowResPictureLayerImplTest, LowResWasHighResCollision) {
// Zoom out to exactly the low res factor so that the previous high res
// would be equal to the current low res (if it were possible to have one).
float zoomed = page_scale / low_res_factor;
- SetContentsScaleOnBothLayers(zoomed, 1.0f, zoomed, 1.0f, 0.f, false);
+ SetContentsScaleOnBothLayers(zoomed, 1.0f, zoomed);
EXPECT_EQ(1u, pending_layer()->num_tilings());
EXPECT_EQ(zoomed,
pending_layer()->tilings()->tiling_at(0)->contents_scale_key());
@@ -5408,7 +5464,7 @@ TEST_F(LegacySWPictureLayerImplTest, HighResWasLowResCollision) {
float low_res = page_scale * low_res_factor;
float extra_low_res = low_res * low_res_factor;
SetupDrawPropertiesAndUpdateTiles(active_layer(), page_scale, 1.0f,
- page_scale, 1.0f, 0.f, false);
+ page_scale);
EXPECT_EQ(2u, active_layer()->tilings()->num_tilings());
EXPECT_EQ(page_scale,
active_layer()->tilings()->tiling_at(0)->contents_scale_key());
@@ -5431,8 +5487,7 @@ TEST_F(LegacySWPictureLayerImplTest, HighResWasLowResCollision) {
// Zoom in to exactly the low res factor so that the previous low res
// would be equal to the current high res.
- SetupDrawPropertiesAndUpdateTiles(active_layer(), low_res, 1.0f, low_res,
- 1.0f, 0.f, false);
+ SetupDrawPropertiesAndUpdateTiles(active_layer(), low_res, 1.0f, low_res);
// 3 tilings. The old high res, the new high res (old low res) and the new low
// res.
EXPECT_EQ(3u, active_layer()->num_tilings());
@@ -5479,8 +5534,7 @@ TEST_F(LegacySWPictureLayerImplTest, CompositedImageCalculateContentsScale) {
SetupRootProperties(pending_layer_ptr);
UpdateDrawProperties(pending_tree);
- SetupDrawPropertiesAndUpdateTiles(pending_layer_ptr, 2.f, 3.f, 4.f, 1.f, 1.f,
- false);
+ SetupDrawPropertiesAndUpdateTiles(pending_layer_ptr, 2.f, 3.f, 4.f);
EXPECT_FLOAT_EQ(1.f, pending_layer_ptr->MaximumTilingContentsScale());
}
@@ -5509,12 +5563,9 @@ TEST_F(LegacySWPictureLayerImplTest, CompositedImageIgnoreIdealContentsScale) {
const float suggested_ideal_contents_scale = 2.f;
const float device_scale_factor = 3.f;
const float page_scale_factor = 4.f;
- const float animation_contents_scale = 1.f;
- const bool animating_transform_to_screen = false;
- SetupDrawPropertiesAndUpdateTiles(
- pending_layer_ptr, suggested_ideal_contents_scale, device_scale_factor,
- page_scale_factor, animation_contents_scale, animation_contents_scale,
- animating_transform_to_screen);
+ SetupDrawPropertiesAndUpdateTiles(pending_layer_ptr,
+ suggested_ideal_contents_scale,
+ device_scale_factor, page_scale_factor);
EXPECT_EQ(1.f,
pending_layer_ptr->tilings()->tiling_at(0)->contents_scale_key());
@@ -5523,10 +5574,9 @@ TEST_F(LegacySWPictureLayerImplTest, CompositedImageIgnoreIdealContentsScale) {
FakePictureLayerImpl* active_layer = static_cast<FakePictureLayerImpl*>(
host_impl()->active_tree()->root_layer());
- SetupDrawPropertiesAndUpdateTiles(
- active_layer, suggested_ideal_contents_scale, device_scale_factor,
- page_scale_factor, animation_contents_scale, animation_contents_scale,
- animating_transform_to_screen);
+ SetupDrawPropertiesAndUpdateTiles(active_layer,
+ suggested_ideal_contents_scale,
+ device_scale_factor, page_scale_factor);
EXPECT_EQ(1.f, active_layer->tilings()->tiling_at(0)->contents_scale_key());
active_layer->set_visible_layer_rect(layer_rect);
@@ -5571,7 +5621,7 @@ TEST_F(LegacySWPictureLayerImplTest, CompositedImageRasterScaleChanges) {
break;
}
SetupDrawPropertiesAndUpdateTiles(pending_layer(), ideal_contents_scale,
- 1.f, 1.f, 1.f, 1.f, false);
+ 1.f, 1.f);
EXPECT_FLOAT_EQ(expected_contents_scale,
pending_layer()
->picture_layer_tiling_set()
@@ -5594,7 +5644,7 @@ TEST_F(LegacySWPictureLayerImplTest, CompositedImageRasterScaleChanges) {
break;
}
SetupDrawPropertiesAndUpdateTiles(pending_layer(), ideal_contents_scale,
- 1.f, 1.f, 1.f, 1.f, false);
+ 1.f, 1.f);
EXPECT_FLOAT_EQ(expected_contents_scale,
pending_layer()
->picture_layer_tiling_set()
@@ -5614,8 +5664,7 @@ TEST_F(LegacySWPictureLayerImplTest, CompositedImageRasterOnChange) {
// Set an image size that is smaller than the layer bounds.
gfx::Size image_size(200, 200);
pending_layer()->SetDirectlyCompositedImageSize(image_size);
- SetupDrawPropertiesAndUpdateTiles(pending_layer(), 1.f, 1.f, 1.f, 1.f, 1.f,
- false);
+ SetupDrawPropertiesAndUpdateTiles(pending_layer(), 1.f, 1.f, 1.f);
EXPECT_FLOAT_EQ(0.5f, pending_layer()
->picture_layer_tiling_set()
->FindTilingWithResolution(HIGH_RESOLUTION)
@@ -5623,8 +5672,7 @@ TEST_F(LegacySWPictureLayerImplTest, CompositedImageRasterOnChange) {
// Change the bounds and ensure we recalculated raster scale.
pending_layer()->SetBounds(gfx::Size(320, 320));
- SetupDrawPropertiesAndUpdateTiles(pending_layer(), 1.f, 1.f, 1.f, 1.f, 1.f,
- false);
+ SetupDrawPropertiesAndUpdateTiles(pending_layer(), 1.f, 1.f, 1.f);
EXPECT_FLOAT_EQ(0.625f, pending_layer()
->picture_layer_tiling_set()
->FindTilingWithResolution(HIGH_RESOLUTION)
@@ -5635,8 +5683,7 @@ TEST_F(LegacySWPictureLayerImplTest, CompositedImageRasterOnChange) {
// is less than 4x the ideal source scale).
pending_layer()->SetBounds(layer_bounds);
pending_layer()->SetDirectlyCompositedImageSize(gfx::Size(2000, 2000));
- SetupDrawPropertiesAndUpdateTiles(pending_layer(), 1.f, 1.f, 1.f, 1.f, 1.f,
- false);
+ SetupDrawPropertiesAndUpdateTiles(pending_layer(), 1.f, 1.f, 1.f);
EXPECT_FLOAT_EQ(2.5f, pending_layer()
->picture_layer_tiling_set()
->FindTilingWithResolution(HIGH_RESOLUTION)
@@ -5645,8 +5692,7 @@ TEST_F(LegacySWPictureLayerImplTest, CompositedImageRasterOnChange) {
// Update the bounds to no longer match the aspect ratio, but still compute
// the same raster scale.
pending_layer()->SetBounds(gfx::Size(600, 500));
- SetupDrawPropertiesAndUpdateTiles(pending_layer(), 1.f, 1.f, 1.f, 1.f, 1.f,
- false);
+ SetupDrawPropertiesAndUpdateTiles(pending_layer(), 1.f, 1.f, 1.f);
EXPECT_FLOAT_EQ(4.f, pending_layer()
->picture_layer_tiling_set()
->FindTilingWithResolution(HIGH_RESOLUTION)
@@ -5655,8 +5701,7 @@ TEST_F(LegacySWPictureLayerImplTest, CompositedImageRasterOnChange) {
// Update the bounds and and bump up the ideal scale so that the scale down
// restriction is lifted.
pending_layer()->SetBounds(layer_bounds);
- SetupDrawPropertiesAndUpdateTiles(pending_layer(), 4.f, 1.f, 1.f, 1.f, 1.f,
- false);
+ SetupDrawPropertiesAndUpdateTiles(pending_layer(), 4.f, 1.f, 1.f);
EXPECT_FLOAT_EQ(5.f, pending_layer()
->picture_layer_tiling_set()
->FindTilingWithResolution(HIGH_RESOLUTION)
@@ -5664,15 +5709,13 @@ TEST_F(LegacySWPictureLayerImplTest, CompositedImageRasterOnChange) {
// Lower the ideal scale to see that the clamping still applied as it is
// lowered.
- SetupDrawPropertiesAndUpdateTiles(pending_layer(), 0.5f, 1.f, 1.f, 1.f, 1.f,
- false);
+ SetupDrawPropertiesAndUpdateTiles(pending_layer(), 0.5f, 1.f, 1.f);
EXPECT_FLOAT_EQ(1.25f, pending_layer()
->picture_layer_tiling_set()
->FindTilingWithResolution(HIGH_RESOLUTION)
->contents_scale_key());
- SetupDrawPropertiesAndUpdateTiles(pending_layer(), 0.25f, 1.f, 1.f, 1.f, 1.f,
- false);
+ SetupDrawPropertiesAndUpdateTiles(pending_layer(), 0.25f, 1.f, 1.f);
EXPECT_FLOAT_EQ(0.625f, pending_layer()
->picture_layer_tiling_set()
->FindTilingWithResolution(HIGH_RESOLUTION)
@@ -5690,8 +5733,7 @@ TEST_F(LegacySWPictureLayerImplTest, CompositedImageRasterOptOutTransitions) {
// in to directly composited images.
pending_layer()->SetBounds(layer_bounds);
pending_layer()->SetDirectlyCompositedImageSize(layer_bounds);
- SetupDrawPropertiesAndUpdateTiles(pending_layer(), 0.3f, 1.f, 1.f, 1.f, 1.f,
- false);
+ SetupDrawPropertiesAndUpdateTiles(pending_layer(), 0.3f, 1.f, 1.f);
EXPECT_FLOAT_EQ(1.f, pending_layer()
->picture_layer_tiling_set()
->FindTilingWithResolution(HIGH_RESOLUTION)
@@ -5702,8 +5744,7 @@ TEST_F(LegacySWPictureLayerImplTest, CompositedImageRasterOptOutTransitions) {
// 0.1f (matching the ideal source scale).
gfx::Size image_size(300, 300);
pending_layer()->SetDirectlyCompositedImageSize(image_size);
- SetupDrawPropertiesAndUpdateTiles(pending_layer(), 0.2f, 1.f, 1.f, 1.f, 1.f,
- false);
+ SetupDrawPropertiesAndUpdateTiles(pending_layer(), 0.2f, 1.f, 1.f);
EXPECT_FLOAT_EQ(0.2f, pending_layer()
->picture_layer_tiling_set()
->FindTilingWithResolution(HIGH_RESOLUTION)
@@ -5714,8 +5755,7 @@ TEST_F(LegacySWPictureLayerImplTest, CompositedImageRasterOptOutTransitions) {
pending_layer()->SetBounds(ScaleToFlooredSize(layer_bounds, 2));
pending_layer()->SetDirectlyCompositedImageSize(
ScaleToFlooredSize(image_size, 2));
- SetupDrawPropertiesAndUpdateTiles(pending_layer(), 0.2f, 1.f, 1.f, 1.f, 1.f,
- false);
+ SetupDrawPropertiesAndUpdateTiles(pending_layer(), 0.2f, 1.f, 1.f);
EXPECT_FLOAT_EQ(0.46875, pending_layer()
->picture_layer_tiling_set()
->FindTilingWithResolution(HIGH_RESOLUTION)
@@ -5731,7 +5771,7 @@ TEST_F(LegacySWPictureLayerImplTest,
Region());
// Start with scale & translation of * 2.25 + (0.25, 0.5).
- SetupDrawProperties(pending_layer(), 2.25f, 1.5f, 1.f, 2.25f, 2.25f, false);
+ SetupDrawProperties(pending_layer(), 2.25f, 1.5f, 1.f);
gfx::Transform translate1;
translate1.Translate(0.25f, 0.5f);
pending_layer()->draw_properties().screen_space_transform.ConcatTransform(
@@ -5751,7 +5791,7 @@ TEST_F(LegacySWPictureLayerImplTest,
// Change to scale & translation of * 2.25 + (0.75, 0.25).
// Verifies that layer movement updates raster translation.
- SetupDrawProperties(pending_layer(), 2.25f, 1.5f, 1.f, 2.25f, 2.25f, false);
+ SetupDrawProperties(pending_layer(), 2.25f, 1.5f, 1.f);
gfx::Transform translate2;
translate2.Translate(0.75f, 0.25f);
pending_layer()->draw_properties().screen_space_transform.ConcatTransform(
@@ -5771,7 +5811,7 @@ TEST_F(LegacySWPictureLayerImplTest,
// Now change the device scale factor but keep the same total scale. Old tiles
// with the same scale would become non-ideal and deleted on pending layers.
- SetupDrawProperties(pending_layer(), 2.25f, 1.0f, 1.f, 2.25f, 2.25f, false);
+ SetupDrawProperties(pending_layer(), 2.25f, 1.0f, 1.f);
pending_layer()->draw_properties().screen_space_transform.ConcatTransform(
translate2);
pending_layer()->draw_properties().target_space_transform =
@@ -5797,7 +5837,7 @@ TEST_F(LegacySWPictureLayerImplTest,
Region());
// Start with scale & translation of * 2.25 + (0.25, 0.5) on the active layer.
- SetupDrawProperties(active_layer(), 2.25f, 1.5f, 1.f, 2.25f, 2.25f, false);
+ SetupDrawProperties(active_layer(), 2.25f, 1.5f, 1.f);
gfx::Transform translate1;
translate1.Translate(0.25f, 0.5f);
active_layer()->draw_properties().screen_space_transform.ConcatTransform(
@@ -5817,7 +5857,7 @@ TEST_F(LegacySWPictureLayerImplTest,
}
// Create a pending layer with the same scale but different translation.
- SetupDrawProperties(pending_layer(), 2.25f, 1.5f, 1.f, 2.25f, 2.25f, false);
+ SetupDrawProperties(pending_layer(), 2.25f, 1.5f, 1.f);
gfx::Transform translate2;
translate2.Translate(0.75f, 0.25f);
pending_layer()->draw_properties().screen_space_transform.ConcatTransform(
diff --git a/chromium/cc/layers/picture_layer_unittest.cc b/chromium/cc/layers/picture_layer_unittest.cc
index 94cd8ecc191..f0f15a7cbb2 100644
--- a/chromium/cc/layers/picture_layer_unittest.cc
+++ b/chromium/cc/layers/picture_layer_unittest.cc
@@ -160,8 +160,7 @@ TEST(PictureLayerTest, ClearVisibleRectWhenNoTiling) {
gfx::Size layer_size(50, 50);
FakeContentLayerClient client;
client.set_bounds(layer_size);
- client.add_draw_image(CreateDiscardablePaintImage(layer_size), gfx::Point(),
- PaintFlags());
+ client.add_draw_image(CreateDiscardablePaintImage(layer_size), gfx::Point());
scoped_refptr<PictureLayer> layer = PictureLayer::Create(&client);
layer->SetBounds(gfx::Size(10, 10));
diff --git a/chromium/cc/layers/render_surface_impl.cc b/chromium/cc/layers/render_surface_impl.cc
index a1eb58ca267..25d5ca89aa5 100644
--- a/chromium/cc/layers/render_surface_impl.cc
+++ b/chromium/cc/layers/render_surface_impl.cc
@@ -45,7 +45,7 @@ RenderSurfaceImpl::RenderSurfaceImpl(LayerTreeImpl* layer_tree_impl,
ancestor_property_changed_(false),
contributes_to_drawn_surface_(false),
is_render_surface_list_member_(false),
- can_use_cached_backdrop_filtered_result_(false),
+ intersects_damage_under_(true),
nearest_occlusion_immune_ancestor_(nullptr) {
damage_tracker_ = DamageTracker::Create();
}
@@ -157,10 +157,19 @@ bool RenderSurfaceImpl::HasCopyRequest() const {
return OwningEffectNode()->has_copy_request;
}
+viz::SubtreeCaptureId RenderSurfaceImpl::SubtreeCaptureId() const {
+ return OwningEffectNode()->subtree_capture_id;
+}
+
bool RenderSurfaceImpl::ShouldCacheRenderSurface() const {
return OwningEffectNode()->cache_render_surface;
}
+bool RenderSurfaceImpl::CopyOfOutputRequired() const {
+ return HasCopyRequest() || ShouldCacheRenderSurface() ||
+ SubtreeCaptureId().is_valid();
+}
+
int RenderSurfaceImpl::TransformTreeIndex() const {
return OwningEffectNode()->transform_id;
}
@@ -210,7 +219,7 @@ gfx::Rect RenderSurfaceImpl::CalculateExpandedClipForFilters(
}
gfx::Rect RenderSurfaceImpl::CalculateClippedAccumulatedContentRect() {
- if (ShouldCacheRenderSurface() || HasCopyRequest() || !is_clipped())
+ if (CopyOfOutputRequired() || !is_clipped())
return accumulated_content_rect();
if (accumulated_content_rect().IsEmpty())
@@ -377,6 +386,7 @@ RenderSurfaceImpl::CreateRenderPass() {
pass->backdrop_filters = BackdropFilters();
pass->backdrop_filter_bounds = BackdropFilterBounds();
pass->generate_mipmap = TrilinearFiltering();
+ pass->subtree_capture_id = SubtreeCaptureId();
pass->cache_render_pass = ShouldCacheRenderSurface();
pass->has_damage_from_contributing_content =
HasDamageFromeContributingContent();
@@ -413,7 +423,7 @@ void RenderSurfaceImpl::AppendQuads(DrawMode draw_mode,
}
LayerImpl* mask_layer = BackdropMaskLayer();
- viz::ResourceId mask_resource_id = 0;
+ viz::ResourceId mask_resource_id = viz::kInvalidResourceId;
gfx::Size mask_texture_size;
gfx::RectF mask_uv_rect;
gfx::Vector2dF surface_contents_scale =
@@ -452,13 +462,12 @@ void RenderSurfaceImpl::AppendQuads(DrawMode draw_mode,
gfx::RectF tex_coord_rect(gfx::Rect(content_rect().size()));
auto* quad =
render_pass->CreateAndAppendDrawQuad<viz::CompositorRenderPassDrawQuad>();
- quad->SetAll(shared_quad_state, content_rect(), unoccluded_content_rect,
- /*needs_blending=*/true, render_pass_id(), mask_resource_id,
- mask_uv_rect, mask_texture_size, surface_contents_scale,
- gfx::PointF(), tex_coord_rect,
- !layer_tree_impl_->settings().enable_edge_anti_aliasing,
- OwningEffectNode()->backdrop_filter_quality,
- can_use_cached_backdrop_filtered_result_);
+ quad->SetAll(
+ shared_quad_state, content_rect(), unoccluded_content_rect,
+ /*needs_blending=*/true, render_pass_id(), mask_resource_id, mask_uv_rect,
+ mask_texture_size, surface_contents_scale, gfx::PointF(), tex_coord_rect,
+ !layer_tree_impl_->settings().enable_edge_anti_aliasing,
+ OwningEffectNode()->backdrop_filter_quality, intersects_damage_under_);
}
} // namespace cc
diff --git a/chromium/cc/layers/render_surface_impl.h b/chromium/cc/layers/render_surface_impl.h
index 0dc37664806..105e04a7067 100644
--- a/chromium/cc/layers/render_surface_impl.h
+++ b/chromium/cc/layers/render_surface_impl.h
@@ -18,6 +18,7 @@
#include "cc/trees/property_tree.h"
#include "components/viz/common/quads/compositor_render_pass.h"
#include "components/viz/common/quads/shared_quad_state.h"
+#include "components/viz/common/surfaces/subtree_capture_id.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/mask_filter_info.h"
@@ -122,14 +123,10 @@ class CC_EXPORT RenderSurfaceImpl {
return is_render_surface_list_member_;
}
- void set_can_use_cached_backdrop_filtered_result(
- bool can_use_cached_backdrop_filtered_result) {
- can_use_cached_backdrop_filtered_result_ =
- can_use_cached_backdrop_filtered_result;
- }
- bool can_use_cached_backdrop_filtered_result() const {
- return can_use_cached_backdrop_filtered_result_;
+ void set_intersects_damage_under(bool intersects_damage_under) {
+ intersects_damage_under_ = intersects_damage_under;
}
+ bool intersects_damage_under() const { return intersects_damage_under_; }
void CalculateContentRectFromAccumulatedContentRect(int max_texture_size);
void SetContentRectToViewport();
@@ -178,8 +175,15 @@ class CC_EXPORT RenderSurfaceImpl {
bool HasCopyRequest() const;
+ viz::SubtreeCaptureId SubtreeCaptureId() const;
+
bool ShouldCacheRenderSurface() const;
+ // Returns true if it's required to copy the output of this surface (i.e. when
+ // it has copy requests, should be cached, or has a valid subtree capture ID),
+ // and should be e.g. immune from occlusion, etc. Returns false otherise.
+ bool CopyOfOutputRequired() const;
+
void ResetPropertyChangedFlags();
bool SurfacePropertyChanged() const;
bool SurfacePropertyChangedOnlyFromDescendant() const;
@@ -260,7 +264,7 @@ class CC_EXPORT RenderSurfaceImpl {
bool contributes_to_drawn_surface_ : 1;
bool is_render_surface_list_member_ : 1;
- bool can_use_cached_backdrop_filtered_result_ : 1;
+ bool intersects_damage_under_ : 1;
Occlusion occlusion_in_content_space_;
diff --git a/chromium/cc/layers/render_surface_impl_unittest.cc b/chromium/cc/layers/render_surface_impl_unittest.cc
index e5f5a504372..e4216685d59 100644
--- a/chromium/cc/layers/render_surface_impl_unittest.cc
+++ b/chromium/cc/layers/render_surface_impl_unittest.cc
@@ -119,7 +119,7 @@ TEST(RenderSurfaceLayerImplTest, AppendQuadsWithScaledMask) {
// Mask layers don't use quad's mask functionality.
EXPECT_EQ(gfx::RectF(), quad->mask_uv_rect);
EXPECT_EQ(gfx::Vector2dF(2.f, 2.f), quad->filters_scale);
- EXPECT_EQ(0u, quad->mask_resource_id());
+ EXPECT_EQ(viz::kInvalidResourceId, quad->mask_resource_id());
}
TEST(RenderSurfaceLayerImplTest, ResourcelessAppendQuadsSkipMask) {
@@ -129,7 +129,7 @@ TEST(RenderSurfaceLayerImplTest, ResourcelessAppendQuadsSkipMask) {
const viz::CompositorRenderPassDrawQuad* quad =
viz::CompositorRenderPassDrawQuad::MaterialCast(
render_pass->quad_list.front());
- EXPECT_EQ(0u, quad->mask_resource_id());
+ EXPECT_EQ(viz::kInvalidResourceId, quad->mask_resource_id());
}
TEST(RenderSurfaceLayerImplTest,
diff --git a/chromium/cc/layers/render_surface_unittest.cc b/chromium/cc/layers/render_surface_unittest.cc
index 250f71bd69f..ee59a342c1c 100644
--- a/chromium/cc/layers/render_surface_unittest.cc
+++ b/chromium/cc/layers/render_surface_unittest.cc
@@ -70,8 +70,9 @@ class FakePictureLayerImplForRenderSurfaceTest : public FakePictureLayerImpl {
bool needs_blending = false;
for (const auto& rect : quad_rects_) {
auto* quad = render_pass->CreateAndAppendDrawQuad<viz::TileDrawQuad>();
- quad->SetNew(shared_quad_state, rect, rect, needs_blending, 0,
- gfx::RectF(rect), bounds(), false, false, false);
+ quad->SetNew(shared_quad_state, rect, rect, needs_blending,
+ viz::kInvalidResourceId, gfx::RectF(rect), bounds(), false,
+ false, false);
}
}
diff --git a/chromium/cc/layers/texture_layer_impl.cc b/chromium/cc/layers/texture_layer_impl.cc
index 33bdf59fcc0..569643a891a 100644
--- a/chromium/cc/layers/texture_layer_impl.cc
+++ b/chromium/cc/layers/texture_layer_impl.cc
@@ -7,6 +7,8 @@
#include <stddef.h>
#include <stdint.h>
+#include <memory>
+#include <utility>
#include <vector>
#include "base/logging.h"
@@ -102,7 +104,7 @@ bool TextureLayerImpl::WillDraw(
own_resource_ = false;
}
- return resource_id_;
+ return resource_id_ != viz::kInvalidResourceId;
}
void TextureLayerImpl::AppendQuads(viz::CompositorRenderPass* render_pass,
@@ -289,7 +291,7 @@ void TextureLayerImpl::FreeTransferableResource() {
DCHECK(!own_resource_);
auto* resource_provider = layer_tree_impl()->resource_provider();
resource_provider->RemoveImportedResource(resource_id_);
- resource_id_ = 0;
+ resource_id_ = viz::kInvalidResourceId;
}
}
diff --git a/chromium/cc/layers/texture_layer_impl.h b/chromium/cc/layers/texture_layer_impl.h
index d7cc7fed89f..6ab05573472 100644
--- a/chromium/cc/layers/texture_layer_impl.h
+++ b/chromium/cc/layers/texture_layer_impl.h
@@ -5,7 +5,9 @@
#ifndef CC_LAYERS_TEXTURE_LAYER_IMPL_H_
#define CC_LAYERS_TEXTURE_LAYER_IMPL_H_
+#include <memory>
#include <string>
+#include <vector>
#include "base/callback.h"
#include "base/containers/flat_map.h"
@@ -100,7 +102,7 @@ class CC_EXPORT TextureLayerImpl : public LayerImpl {
// Local ResourceId for the TransferableResource, to be used with the
// compositor's viz::ClientResourceProvider in order to refer to the
// TransferableResource given to it.
- viz::ResourceId resource_id_ = 0;
+ viz::ResourceId resource_id_ = viz::kInvalidResourceId;
std::unique_ptr<viz::SingleReleaseCallback> release_callback_;
// As a pending layer, the set of SharedBitmapIds and the underlying
diff --git a/chromium/cc/layers/texture_layer_unittest.cc b/chromium/cc/layers/texture_layer_unittest.cc
index 3511e89eed6..fdc4f74623b 100644
--- a/chromium/cc/layers/texture_layer_unittest.cc
+++ b/chromium/cc/layers/texture_layer_unittest.cc
@@ -1004,6 +1004,7 @@ class TextureLayerChangeInvisibleMailboxTest
++prepare_called_;
if (!resource_changed_)
return false;
+ resource_changed_ = false;
*resource = resource_;
*release_callback = viz::SingleReleaseCallback::Create(base::BindOnce(
&TextureLayerChangeInvisibleMailboxTest::ResourceReleased,
diff --git a/chromium/cc/layers/ui_resource_layer_impl.cc b/chromium/cc/layers/ui_resource_layer_impl.cc
index 40eb09f5b1f..48ba1eb42a6 100644
--- a/chromium/cc/layers/ui_resource_layer_impl.cc
+++ b/chromium/cc/layers/ui_resource_layer_impl.cc
@@ -4,6 +4,8 @@
#include "cc/layers/ui_resource_layer_impl.h"
+#include <memory>
+
#include "base/strings/stringprintf.h"
#include "base/trace_event/traced_value.h"
#include "cc/base/math_util.h"
@@ -102,7 +104,7 @@ void UIResourceLayerImpl::AppendQuads(viz::CompositorRenderPass* render_pass,
viz::ResourceId resource =
ui_resource_id_
? layer_tree_impl()->ResourceIdForUIResource(ui_resource_id_)
- : 0;
+ : viz::kInvalidResourceId;
bool are_contents_opaque =
resource ? (layer_tree_impl()->IsUIResourceOpaque(ui_resource_id_) ||
contents_opaque())
diff --git a/chromium/cc/layers/video_layer_impl_unittest.cc b/chromium/cc/layers/video_layer_impl_unittest.cc
index 00af2c84846..6a205ea443b 100644
--- a/chromium/cc/layers/video_layer_impl_unittest.cc
+++ b/chromium/cc/layers/video_layer_impl_unittest.cc
@@ -395,7 +395,7 @@ TEST(VideoLayerImplTest, NativeYUVFrameGeneratesYUVQuad) {
gfx::Size(10, 10), gfx::Rect(10, 10), gfx::Size(10, 10),
base::TimeDelta());
ASSERT_TRUE(video_frame);
- video_frame->metadata()->allow_overlay = true;
+ video_frame->metadata().allow_overlay = true;
FakeVideoFrameProvider provider;
provider.set_frame(video_frame);
@@ -438,7 +438,7 @@ TEST(VideoLayerImplTest, NativeARGBFrameGeneratesTextureQuad) {
media::PIXEL_FORMAT_ARGB, mailbox_holders, base::DoNothing(),
resource_size, gfx::Rect(10, 10), resource_size, base::TimeDelta());
ASSERT_TRUE(video_frame);
- video_frame->metadata()->allow_overlay = true;
+ video_frame->metadata().allow_overlay = true;
FakeVideoFrameProvider provider;
provider.set_frame(video_frame);
diff --git a/chromium/cc/metrics/OWNERS b/chromium/cc/metrics/OWNERS
index 0cb4f83e792..39db757e54a 100644
--- a/chromium/cc/metrics/OWNERS
+++ b/chromium/cc/metrics/OWNERS
@@ -1,2 +1,4 @@
per-file ukm_smoothness_data.h=set noparent
per-file ukm_smoothness_data.h=file://ipc/SECURITY_OWNERS
+per-file shared_metrics_buffer.h=set noparent
+per-file shared_metrics_buffer.h=file://ipc/SECURITY_OWNERS
diff --git a/chromium/cc/metrics/compositor_frame_reporter.cc b/chromium/cc/metrics/compositor_frame_reporter.cc
index 93d0e2352a7..fcad7a8cd4e 100644
--- a/chromium/cc/metrics/compositor_frame_reporter.cc
+++ b/chromium/cc/metrics/compositor_frame_reporter.cc
@@ -75,6 +75,102 @@ constexpr const char* GetVizBreakdownName(VizBreakdown stage) {
}
}
+// Returns the name of the event dispatch breakdown of EventLatency histograms
+// between `start_stage` and `end_stage`.
+constexpr const char* GetEventLatencyDispatchBreakdownName(
+ EventMetrics::DispatchStage start_stage,
+ EventMetrics::DispatchStage end_stage) {
+ switch (start_stage) {
+ case EventMetrics::DispatchStage::kGenerated:
+ DCHECK_EQ(end_stage,
+ EventMetrics::DispatchStage::kArrivedInRendererCompositor);
+ return "GenerationToRendererCompositor";
+ case EventMetrics::DispatchStage::kArrivedInRendererCompositor:
+ switch (end_stage) {
+ case EventMetrics::DispatchStage::kRendererCompositorStarted:
+ return "RendererCompositorQueueingDelay";
+ case EventMetrics::DispatchStage::kRendererMainStarted:
+ return "RendererCompositorToMain";
+ default:
+ NOTREACHED();
+ return nullptr;
+ }
+ case EventMetrics::DispatchStage::kRendererCompositorStarted:
+ DCHECK_EQ(end_stage,
+ EventMetrics::DispatchStage::kRendererCompositorFinished);
+ return "RendererCompositorProcessing";
+ case EventMetrics::DispatchStage::kRendererCompositorFinished:
+ DCHECK_EQ(end_stage, EventMetrics::DispatchStage::kRendererMainStarted);
+ return "RendererCompositorToMain";
+ case EventMetrics::DispatchStage::kRendererMainStarted:
+ DCHECK_EQ(end_stage, EventMetrics::DispatchStage::kRendererMainFinished);
+ return "RendererMainProcessing";
+ case EventMetrics::DispatchStage::kRendererMainFinished:
+ NOTREACHED();
+ return nullptr;
+ }
+}
+
+// Returns the name of EventLatency breakdown between `dispatch_stage` and
+// `compositor_stage`.
+constexpr const char* GetEventLatencyDispatchToCompositorBreakdownName(
+ EventMetrics::DispatchStage dispatch_stage,
+ CompositorFrameReporter::StageType compositor_stage) {
+ switch (dispatch_stage) {
+ case EventMetrics::DispatchStage::kRendererCompositorFinished:
+ switch (compositor_stage) {
+ case CompositorFrameReporter::StageType::
+ kBeginImplFrameToSendBeginMainFrame:
+ return "RendererCompositorFinishedToBeginImplFrame";
+ case CompositorFrameReporter::StageType::kSendBeginMainFrameToCommit:
+ return "RendererCompositorFinishedToSendBeginMainFrame";
+ case CompositorFrameReporter::StageType::kCommit:
+ return "RendererCompositorFinishedToCommit";
+ case CompositorFrameReporter::StageType::kEndCommitToActivation:
+ return "RendererCompositorFinishedToEndCommit";
+ case CompositorFrameReporter::StageType::kActivation:
+ return "RendererCompositorFinishedToActivation";
+ case CompositorFrameReporter::StageType::
+ kEndActivateToSubmitCompositorFrame:
+ return "RendererCompositorFinishedToEndActivate";
+ case CompositorFrameReporter::StageType::
+ kSubmitCompositorFrameToPresentationCompositorFrame:
+ return "RendererCompositorFinishedToSubmitCompositorFrame";
+ default:
+ NOTREACHED();
+ return nullptr;
+ }
+ break;
+ case EventMetrics::DispatchStage::kRendererMainFinished:
+ switch (compositor_stage) {
+ case CompositorFrameReporter::StageType::
+ kBeginImplFrameToSendBeginMainFrame:
+ return "RendererMainFinishedToBeginImplFrame";
+ case CompositorFrameReporter::StageType::kSendBeginMainFrameToCommit:
+ return "RendererMainFinishedToSendBeginMainFrame";
+ case CompositorFrameReporter::StageType::kCommit:
+ return "RendererMainFinishedToCommit";
+ case CompositorFrameReporter::StageType::kEndCommitToActivation:
+ return "RendererMainFinishedToEndCommit";
+ case CompositorFrameReporter::StageType::kActivation:
+ return "RendererMainFinishedToActivation";
+ case CompositorFrameReporter::StageType::
+ kEndActivateToSubmitCompositorFrame:
+ return "RendererMainFinishedToEndActivate";
+ case CompositorFrameReporter::StageType::
+ kSubmitCompositorFrameToPresentationCompositorFrame:
+ return "RendererMainFinishedToSubmitCompositorFrame";
+ default:
+ NOTREACHED();
+ return nullptr;
+ }
+ break;
+ default:
+ NOTREACHED();
+ return nullptr;
+ }
+}
+
// Names for CompositorFrameReporter::StageType, which should be updated in case
// of changes to the enum.
constexpr const char* GetStageName(int stage_type_index,
@@ -201,10 +297,8 @@ constexpr int kEventLatencyEventTypeCount =
static_cast<int>(EventMetrics::EventType::kMaxValue) + 1;
constexpr int kEventLatencyScrollTypeCount =
static_cast<int>(EventMetrics::ScrollType::kMaxValue) + 1;
-constexpr int kMaxEventLatencyHistogramBaseIndex =
- kEventLatencyEventTypeCount * kEventLatencyScrollTypeCount;
constexpr int kMaxEventLatencyHistogramIndex =
- kMaxEventLatencyHistogramBaseIndex * (kStageTypeCount + kAllBreakdownCount);
+ kEventLatencyEventTypeCount * kEventLatencyScrollTypeCount;
constexpr base::TimeDelta kEventLatencyHistogramMin =
base::TimeDelta::FromMicroseconds(1);
constexpr base::TimeDelta kEventLatencyHistogramMax =
@@ -241,37 +335,203 @@ base::TimeTicks ComputeSafeDeadlineForFrame(const viz::BeginFrameArgs& args) {
return args.frame_time + (args.interval * 1.5);
}
-#define REPORT_VIZ_TRACE_EVENT(start_time, end_time, index, trace_func) \
- if (start_time <= end_time) { \
- const char* substage_name = \
- GetVizBreakdownName(static_cast<VizBreakdown>(index)); \
- trace_func(start_time, end_time, substage_name); \
+bool IsScrollActive(const CompositorFrameReporter::ActiveTrackers& trackers) {
+ return trackers.test(
+ static_cast<size_t>(FrameSequenceTrackerType::kWheelScroll)) ||
+ trackers.test(
+ static_cast<size_t>(FrameSequenceTrackerType::kTouchScroll)) ||
+ trackers.test(
+ static_cast<size_t>(FrameSequenceTrackerType::kScrollbarScroll));
+}
+
+} // namespace
+
+// CompositorFrameReporter::ProcessedBlinkBreakdown::Iterator ==================
+
+CompositorFrameReporter::ProcessedBlinkBreakdown::Iterator::Iterator(
+ const ProcessedBlinkBreakdown* owner)
+ : owner_(owner) {}
+
+CompositorFrameReporter::ProcessedBlinkBreakdown::Iterator::~Iterator() =
+ default;
+
+bool CompositorFrameReporter::ProcessedBlinkBreakdown::Iterator::IsValid()
+ const {
+ return index_ < base::size(owner_->list_);
+}
+
+void CompositorFrameReporter::ProcessedBlinkBreakdown::Iterator::Advance() {
+ DCHECK(IsValid());
+ index_++;
+}
+
+BlinkBreakdown
+CompositorFrameReporter::ProcessedBlinkBreakdown::Iterator::GetBreakdown()
+ const {
+ DCHECK(IsValid());
+ return static_cast<BlinkBreakdown>(index_);
+}
+
+base::TimeDelta
+CompositorFrameReporter::ProcessedBlinkBreakdown::Iterator::GetLatency() const {
+ DCHECK(IsValid());
+ return owner_->list_[index_];
+}
+
+// CompositorFrameReporter::ProcessedBlinkBreakdown ============================
+
+CompositorFrameReporter::ProcessedBlinkBreakdown::ProcessedBlinkBreakdown(
+ base::TimeTicks blink_start_time,
+ base::TimeTicks begin_main_frame_start,
+ const BeginMainFrameMetrics& blink_breakdown) {
+ if (blink_start_time.is_null())
+ return;
+
+ list_[static_cast<int>(BlinkBreakdown::kHandleInputEvents)] =
+ blink_breakdown.handle_input_events;
+ list_[static_cast<int>(BlinkBreakdown::kAnimate)] = blink_breakdown.animate;
+ list_[static_cast<int>(BlinkBreakdown::kStyleUpdate)] =
+ blink_breakdown.style_update;
+ list_[static_cast<int>(BlinkBreakdown::kLayoutUpdate)] =
+ blink_breakdown.layout_update;
+ list_[static_cast<int>(BlinkBreakdown::kPrepaint)] = blink_breakdown.prepaint;
+ list_[static_cast<int>(BlinkBreakdown::kCompositingInputs)] =
+ blink_breakdown.compositing_inputs;
+ list_[static_cast<int>(BlinkBreakdown::kCompositingAssignments)] =
+ blink_breakdown.compositing_assignments;
+ list_[static_cast<int>(BlinkBreakdown::kPaint)] = blink_breakdown.paint;
+ list_[static_cast<int>(BlinkBreakdown::kCompositeCommit)] =
+ blink_breakdown.composite_commit;
+ list_[static_cast<int>(BlinkBreakdown::kUpdateLayers)] =
+ blink_breakdown.update_layers;
+ list_[static_cast<int>(BlinkBreakdown::kBeginMainSentToStarted)] =
+ begin_main_frame_start - blink_start_time;
+}
+
+CompositorFrameReporter::ProcessedBlinkBreakdown::~ProcessedBlinkBreakdown() =
+ default;
+
+CompositorFrameReporter::ProcessedBlinkBreakdown::Iterator
+CompositorFrameReporter::ProcessedBlinkBreakdown::CreateIterator() const {
+ return Iterator(this);
+}
+
+// CompositorFrameReporter::ProcessedVizBreakdown::Iterator ====================
+
+CompositorFrameReporter::ProcessedVizBreakdown::Iterator::Iterator(
+ const ProcessedVizBreakdown* owner,
+ bool skip_swap_start_to_swap_end)
+ : owner_(owner), skip_swap_start_to_swap_end_(skip_swap_start_to_swap_end) {
+ DCHECK(owner_);
+}
+
+CompositorFrameReporter::ProcessedVizBreakdown::Iterator::~Iterator() = default;
+
+bool CompositorFrameReporter::ProcessedVizBreakdown::Iterator::IsValid() const {
+ return index_ < base::size(owner_->list_) && owner_->list_[index_];
+}
+
+void CompositorFrameReporter::ProcessedVizBreakdown::Iterator::Advance() {
+ DCHECK(IsValid());
+ index_++;
+ if (static_cast<VizBreakdown>(index_) == VizBreakdown::kSwapStartToSwapEnd &&
+ skip_swap_start_to_swap_end_) {
+ index_++;
}
+}
+
+VizBreakdown
+CompositorFrameReporter::ProcessedVizBreakdown::Iterator::GetBreakdown() const {
+ DCHECK(IsValid());
+ return static_cast<VizBreakdown>(index_);
+}
+
+base::TimeTicks
+CompositorFrameReporter::ProcessedVizBreakdown::Iterator::GetStartTime() const {
+ DCHECK(IsValid());
+ return owner_->list_[index_]->first;
+}
+
+base::TimeTicks
+CompositorFrameReporter::ProcessedVizBreakdown::Iterator::GetEndTime() const {
+ DCHECK(IsValid());
+ return owner_->list_[index_]->second;
+}
-#define REPORT_VIZ_BREAKDOWN_TRACES(trace_func) \
- size_t start_to_buffer_available = \
- static_cast<size_t>(VizBreakdown::kSwapStartToBufferAvailable); \
- bool has_ready_timings = !!viz_breakdown_list_[start_to_buffer_available]; \
- for (size_t i = 0; i < start_to_buffer_available; i++) { \
- if (!viz_breakdown_list_[i]) { \
- break; \
- } \
- if (i == static_cast<size_t>(VizBreakdown::kSwapStartToSwapEnd) && \
- has_ready_timings) { \
- size_t latch_to_swap_end = \
- static_cast<size_t>(VizBreakdown::kLatchToSwapEnd); \
- for (size_t j = start_to_buffer_available; j <= latch_to_swap_end; \
- j++) { \
- REPORT_VIZ_TRACE_EVENT(viz_breakdown_list_[j]->first, \
- viz_breakdown_list_[j]->second, j, trace_func); \
- } \
- } else { \
- REPORT_VIZ_TRACE_EVENT(viz_breakdown_list_[i]->first, \
- viz_breakdown_list_[i]->second, i, trace_func); \
- } \
+base::TimeDelta
+CompositorFrameReporter::ProcessedVizBreakdown::Iterator::GetDuration() const {
+ DCHECK(IsValid());
+ return owner_->list_[index_]->second - owner_->list_[index_]->first;
+}
+
+// CompositorFrameReporter::ProcessedVizBreakdown ==============================
+
+CompositorFrameReporter::ProcessedVizBreakdown::ProcessedVizBreakdown(
+ base::TimeTicks viz_start_time,
+ const viz::FrameTimingDetails& viz_breakdown) {
+ if (viz_start_time.is_null())
+ return;
+
+ // Check if `viz_breakdown` is set. Testing indicates that sometimes the
+ // received_compositor_frame_timestamp can be earlier than the given
+ // `viz_start_time`. Avoid reporting negative times.
+ if (viz_breakdown.received_compositor_frame_timestamp.is_null() ||
+ viz_breakdown.received_compositor_frame_timestamp < viz_start_time) {
+ return;
}
+ list_[static_cast<int>(VizBreakdown::kSubmitToReceiveCompositorFrame)] =
+ std::make_pair(viz_start_time,
+ viz_breakdown.received_compositor_frame_timestamp);
-} // namespace
+ if (viz_breakdown.draw_start_timestamp.is_null())
+ return;
+ list_[static_cast<int>(VizBreakdown::kReceivedCompositorFrameToStartDraw)] =
+ std::make_pair(viz_breakdown.received_compositor_frame_timestamp,
+ viz_breakdown.draw_start_timestamp);
+
+ if (viz_breakdown.swap_timings.is_null())
+ return;
+ list_[static_cast<int>(VizBreakdown::kStartDrawToSwapStart)] =
+ std::make_pair(viz_breakdown.draw_start_timestamp,
+ viz_breakdown.swap_timings.swap_start);
+
+ list_[static_cast<int>(VizBreakdown::kSwapStartToSwapEnd)] =
+ std::make_pair(viz_breakdown.swap_timings.swap_start,
+ viz_breakdown.swap_timings.swap_end);
+
+ list_[static_cast<int>(VizBreakdown::kSwapEndToPresentationCompositorFrame)] =
+ std::make_pair(viz_breakdown.swap_timings.swap_end,
+ viz_breakdown.presentation_feedback.timestamp);
+ swap_start_ = viz_breakdown.swap_timings.swap_start;
+
+ if (viz_breakdown.presentation_feedback.ready_timestamp.is_null())
+ return;
+ buffer_ready_available_ = true;
+ list_[static_cast<int>(VizBreakdown::kSwapStartToBufferAvailable)] =
+ std::make_pair(viz_breakdown.swap_timings.swap_start,
+ viz_breakdown.presentation_feedback.available_timestamp);
+ list_[static_cast<int>(VizBreakdown::kBufferAvailableToBufferReady)] =
+ std::make_pair(viz_breakdown.presentation_feedback.available_timestamp,
+ viz_breakdown.presentation_feedback.ready_timestamp);
+ list_[static_cast<int>(VizBreakdown::kBufferReadyToLatch)] =
+ std::make_pair(viz_breakdown.presentation_feedback.ready_timestamp,
+ viz_breakdown.presentation_feedback.latch_timestamp);
+ list_[static_cast<int>(VizBreakdown::kLatchToSwapEnd)] =
+ std::make_pair(viz_breakdown.presentation_feedback.latch_timestamp,
+ viz_breakdown.swap_timings.swap_end);
+}
+
+CompositorFrameReporter::ProcessedVizBreakdown::~ProcessedVizBreakdown() =
+ default;
+
+CompositorFrameReporter::ProcessedVizBreakdown::Iterator
+CompositorFrameReporter::ProcessedVizBreakdown::CreateIterator(
+ bool skip_swap_start_to_swap_end_if_breakdown_available) const {
+ return Iterator(this, skip_swap_start_to_swap_end_if_breakdown_available &&
+ buffer_ready_available_);
+}
+
+// CompositorFrameReporter =====================================================
CompositorFrameReporter::CompositorFrameReporter(
const ActiveTrackers& active_trackers,
@@ -288,11 +548,15 @@ CompositorFrameReporter::CompositorFrameReporter(
dropped_frame_counter_(dropped_frame_counter),
smooth_thread_(smooth_thread),
layer_tree_host_id_(layer_tree_host_id) {
- dropped_frame_counter_->OnBeginFrame(args);
+ dropped_frame_counter_->OnBeginFrame(args, IsScrollActive(active_trackers_));
}
std::unique_ptr<CompositorFrameReporter>
CompositorFrameReporter::CopyReporterAtBeginImplStage() {
+ // If |this| reporter is dependent on another reporter to decide about partial
+ // update, then |this| should not have any such dependents.
+ DCHECK(!partial_update_decider_);
+
if (stage_history_.empty() ||
stage_history_.front().stage_type !=
StageType::kBeginImplFrameToSendBeginMainFrame ||
@@ -309,11 +573,11 @@ CompositorFrameReporter::CopyReporterAtBeginImplStage() {
StageType::kBeginImplFrameToSendBeginMainFrame;
new_reporter->current_stage_.start_time = stage_history_.front().start_time;
new_reporter->set_tick_clock(tick_clock_);
- new_reporter->cloned_from_ = weak_factory_.GetWeakPtr();
- // TODO(https://crbug.com/1127872) Check |cloned_to_| is null before replacing
- // it.
- cloned_to_ = new_reporter->GetWeakPtr();
+ // Set up the new reporter so that it depends on |this| for partial update
+ // information.
+ new_reporter->SetPartialUpdateDecider(weak_factory_.GetWeakPtr());
+
return new_reporter;
}
@@ -418,8 +682,10 @@ void CompositorFrameReporter::TerminateReporter() {
if (frame_termination_status_ == FrameTerminationStatus::kUnknown)
TerminateFrame(FrameTerminationStatus::kUnknown, Now());
- PopulateBlinkBreakdownList();
- PopulateVizBreakdownList();
+ 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_);
DCHECK_EQ(current_stage_.start_time, base::TimeTicks());
switch (frame_termination_status_) {
@@ -434,21 +700,34 @@ void CompositorFrameReporter::TerminateReporter() {
case FrameTerminationStatus::kReplacedByNewReporter:
EnableReportType(FrameReportType::kDroppedFrame);
break;
- case FrameTerminationStatus::kDidNotProduceFrame:
- if (frame_skip_reason_.has_value() &&
- frame_skip_reason() == FrameSkippedReason::kNoDamage) {
- // If this reporter was cloned, and the cloned repoter was marked as
+ case FrameTerminationStatus::kDidNotProduceFrame: {
+ const bool no_update_from_main =
+ frame_skip_reason_.has_value() &&
+ frame_skip_reason() == FrameSkippedReason::kNoDamage;
+ const bool no_update_from_compositor =
+ !has_partial_update_ && frame_skip_reason_.has_value() &&
+ frame_skip_reason() == FrameSkippedReason::kWaitingOnMain;
+
+ if (no_update_from_main) {
+ // If this reporter was cloned, and the cloned reporter was marked as
// containing 'partial update' (i.e. missing desired updates from the
// main-thread), but this reporter terminated with 'no damage', then
- // reset the 'partial update' flag from the cloned reporter.
- if (cloned_to_ && cloned_to_->has_partial_update())
- cloned_to_->set_has_partial_update(false);
- } else {
- // If no frames were produced, it was not due to no-damage, then it is a
- // dropped frame.
+ // reset the 'partial update' flag from the cloned reporter (as well as
+ // other depending reporters).
+ while (!partial_update_dependents_.empty()) {
+ auto dependent = partial_update_dependents_.front();
+ if (dependent)
+ dependent->set_has_partial_update(false);
+ partial_update_dependents_.pop();
+ }
+ } else if (!no_update_from_compositor) {
+ // If rather main thread has damage or compositor thread has partial
+ // damage, then it's a dropped frame.
EnableReportType(FrameReportType::kDroppedFrame);
}
+
break;
+ }
case FrameTerminationStatus::kUnknown:
break;
}
@@ -485,6 +764,11 @@ void CompositorFrameReporter::TerminateReporter() {
dropped_frame_counter_->OnEndFrame(args_,
IsDroppedFrameAffectingSmoothness());
}
+
+ if (discarded_partial_update_dependents_count_ > 0)
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ "Graphics.Smoothness.Diagnostic.DiscardedDependentCount",
+ discarded_partial_update_dependents_count_, 1, 1000, 50);
}
void CompositorFrameReporter::EndCurrentStage(base::TimeTicks end_time) {
@@ -513,7 +797,8 @@ void CompositorFrameReporter::ReportCompositorLatencyHistograms() const {
UMA_HISTOGRAM_ENUMERATION("CompositorLatency.Type", report_type);
if (latency_ukm_reporter_) {
latency_ukm_reporter_->ReportCompositorLatencyUkm(
- report_type, stage_history_, active_trackers_, viz_breakdown_);
+ report_type, stage_history_, active_trackers_,
+ *processed_blink_breakdown_, *processed_viz_breakdown_);
}
bool any_active_interaction = false;
for (size_t fst_type = 0; fst_type < active_trackers_.size(); ++fst_type) {
@@ -601,29 +886,25 @@ void CompositorFrameReporter::ReportStageHistogramWithBreakdown(
void CompositorFrameReporter::ReportCompositorLatencyBlinkBreakdowns(
FrameSequenceTrackerType frame_sequence_tracker_type) const {
- for (size_t i = 0; i < base::size(blink_breakdown_list_); i++) {
- ReportCompositorLatencyHistogram(frame_sequence_tracker_type,
- kBlinkBreakdownInitialIndex + i,
- blink_breakdown_list_[i]);
+ DCHECK(processed_blink_breakdown_);
+ for (auto it = processed_blink_breakdown_->CreateIterator(); it.IsValid();
+ it.Advance()) {
+ ReportCompositorLatencyHistogram(
+ frame_sequence_tracker_type,
+ kBlinkBreakdownInitialIndex + static_cast<size_t>(it.GetBreakdown()),
+ it.GetLatency());
}
}
void CompositorFrameReporter::ReportCompositorLatencyVizBreakdowns(
FrameSequenceTrackerType frame_sequence_tracker_type) const {
- for (size_t i = 0; i < base::size(viz_breakdown_list_); i++) {
- if (!viz_breakdown_list_[i]) {
-#if DCHECK_IS_ON()
- // Remaining breakdowns should be unset.
- for (; i < base::size(viz_breakdown_list_); i++)
- DCHECK(!viz_breakdown_list_[i]);
-#endif
- break;
- }
- const base::TimeTicks start_time = viz_breakdown_list_[i]->first;
- const base::TimeTicks end_time = viz_breakdown_list_[i]->second;
- ReportCompositorLatencyHistogram(frame_sequence_tracker_type,
- kVizBreakdownInitialIndex + i,
- end_time - start_time);
+ DCHECK(processed_viz_breakdown_);
+ for (auto it = processed_viz_breakdown_->CreateIterator(false); it.IsValid();
+ it.Advance()) {
+ ReportCompositorLatencyHistogram(
+ frame_sequence_tracker_type,
+ kVizBreakdownInitialIndex + static_cast<size_t>(it.GetBreakdown()),
+ it.GetDuration());
}
}
@@ -670,8 +951,16 @@ void CompositorFrameReporter::ReportCompositorLatencyHistogram(
}
void CompositorFrameReporter::ReportEventLatencyHistograms() const {
+ const StageData& total_latency_stage = stage_history_.back();
+ DCHECK_EQ(StageType::kTotalLatency, total_latency_stage.stage_type);
+
+ const std::string total_latency_stage_name =
+ GetStageName(static_cast<int>(StageType::kTotalLatency));
+ const std::string total_latency_histogram_name =
+ "EventLatency." + total_latency_stage_name;
+
for (const auto& event_metrics : events_metrics_) {
- DCHECK_NE(event_metrics, nullptr);
+ DCHECK(event_metrics);
const std::string histogram_base_name =
GetEventLatencyHistogramBaseName(*event_metrics);
const int event_type_index = static_cast<int>(event_metrics->type());
@@ -679,156 +968,67 @@ void CompositorFrameReporter::ReportEventLatencyHistograms() const {
event_metrics->scroll_type()
? static_cast<int>(*event_metrics->scroll_type())
: 0;
- const int histogram_base_index =
+ const int event_histogram_index =
event_type_index * kEventLatencyScrollTypeCount + scroll_type_index;
+ const base::TimeTicks generated_timestamp =
+ event_metrics->GetDispatchStageTimestamp(
+ EventMetrics::DispatchStage::kGenerated);
+ DCHECK_LT(generated_timestamp, total_latency_stage.end_time);
+
// For scroll events, report total latency up to gpu-swap-begin. This is
// useful in comparing new EventLatency metrics with LatencyInfo-based
// scroll event latency metrics.
- if (event_metrics->scroll_type() &&
+ if (event_metrics->ShouldReportScrollingTotalLatency() &&
!viz_breakdown_.swap_timings.is_null()) {
const base::TimeDelta swap_begin_latency =
- viz_breakdown_.swap_timings.swap_start - event_metrics->time_stamp();
- const std::string swap_begin_histogram_name =
+ viz_breakdown_.swap_timings.swap_start - generated_timestamp;
+ const std::string event_swap_begin_histogram_name =
histogram_base_name + ".TotalLatencyToSwapBegin";
- // Note: There's a 1:1 mapping between `histogram_base_index` and
- // `swap_begin_histogram_name` which allows the use of
+ // Note: There's a 1:1 mapping between `event_histogram_index` and
+ // `event_swap_begin_histogram_name` which allows the use of
// `STATIC_HISTOGRAM_POINTER_GROUP()` to cache histogram objects.
STATIC_HISTOGRAM_POINTER_GROUP(
- swap_begin_histogram_name, histogram_base_index,
- kMaxEventLatencyHistogramBaseIndex,
+ event_swap_begin_histogram_name, event_histogram_index,
+ kMaxEventLatencyHistogramIndex,
AddTimeMicrosecondsGranularity(swap_begin_latency),
base::Histogram::FactoryMicrosecondsTimeGet(
- swap_begin_histogram_name, kEventLatencyHistogramMin,
+ event_swap_begin_histogram_name, kEventLatencyHistogramMin,
kEventLatencyHistogramMax, kEventLatencyHistogramBucketCount,
base::HistogramBase::kUmaTargetedHistogramFlag));
}
- // It is possible for an event to arrive in the compositor in the middle of
- // a frame (e.g. the browser received the event *after* renderer received a
- // begin-impl, and the event reached the compositor before that frame
- // ended). To handle such cases, find the first stage that happens after the
- // event's arrival in the browser.
- auto stage_it =
- std::find_if(stage_history_.begin(), stage_history_.end(),
- [&event_metrics](const StageData& stage) {
- return stage.start_time > event_metrics->time_stamp();
- });
- // TODO(crbug.com/1079116): Ideally, at least the start time of
- // SubmitCompositorFrameToPresentationCompositorFrame stage should be
- // greater than the event time stamp, but apparently, this is not always the
- // case (see crbug.com/1093698). For now, skip to the next event in such
- // cases. Hopefully, the work to reduce discrepancies between the new
- // EventLatency and the old Event.Latency metrics would fix this issue. If
- // not, we need to reconsider investigating this issue.
- if (stage_it == stage_history_.end())
- continue;
-
- const base::TimeDelta b2r_latency =
- stage_it->start_time - event_metrics->time_stamp();
- const std::string b2r_histogram_name =
- histogram_base_name + ".BrowserToRendererCompositor";
- // Note: There's a 1:1 mapping between `histogram_base_index` and
- // `b2r_histogram_name` which allows the use of
+ // Report total latency up to presentation for the event.
+ const base::TimeDelta total_latency =
+ total_latency_stage.end_time - generated_timestamp;
+ const std::string event_total_latency_histogram_name =
+ base::StrCat({histogram_base_name, ".", total_latency_stage_name});
+ // Note: There's a 1:1 mapping between `event_histogram_index` and
+ // `event_total_latency_histogram_name` which allows the use of
// `STATIC_HISTOGRAM_POINTER_GROUP()` to cache histogram objects.
STATIC_HISTOGRAM_POINTER_GROUP(
- b2r_histogram_name, histogram_base_index,
- kMaxEventLatencyHistogramBaseIndex,
- AddTimeMicrosecondsGranularity(b2r_latency),
+ event_total_latency_histogram_name, event_histogram_index,
+ kMaxEventLatencyHistogramIndex,
+ AddTimeMicrosecondsGranularity(total_latency),
base::Histogram::FactoryMicrosecondsTimeGet(
- b2r_histogram_name, kEventLatencyHistogramMin,
+ event_total_latency_histogram_name, kEventLatencyHistogramMin,
kEventLatencyHistogramMax, kEventLatencyHistogramBucketCount,
base::HistogramBase::kUmaTargetedHistogramFlag));
- for (; stage_it != stage_history_.end(); ++stage_it) {
- // Total latency is calculated since the event timestamp.
- const base::TimeTicks start_time =
- stage_it->stage_type == StageType::kTotalLatency
- ? event_metrics->time_stamp()
- : stage_it->start_time;
- const base::TimeDelta latency = stage_it->end_time - start_time;
- const int stage_type_index = static_cast<int>(stage_it->stage_type);
- ReportEventLatencyHistogram(histogram_base_index, histogram_base_name,
- stage_type_index, latency);
-
- switch (stage_it->stage_type) {
- case StageType::kSendBeginMainFrameToCommit:
- ReportEventLatencyBlinkBreakdowns(histogram_base_index,
- histogram_base_name);
- break;
- case StageType::kSubmitCompositorFrameToPresentationCompositorFrame:
- ReportEventLatencyVizBreakdowns(histogram_base_index,
- histogram_base_name);
- break;
- case StageType::kTotalLatency:
- UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES(
- "EventLatency.TotalLatency", latency, kEventLatencyHistogramMin,
- kEventLatencyHistogramMax, kEventLatencyHistogramBucketCount);
- break;
- default:
- break;
- }
- }
+ // Also, report total latency up to presentation for all event types in an
+ // aggregate histogram.
+ UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES(
+ total_latency_histogram_name, total_latency, kEventLatencyHistogramMin,
+ kEventLatencyHistogramMax, kEventLatencyHistogramBucketCount);
}
if (latency_ukm_reporter_) {
latency_ukm_reporter_->ReportEventLatencyUkm(
- events_metrics_, stage_history_, viz_breakdown_);
+ events_metrics_, stage_history_, *processed_blink_breakdown_,
+ *processed_viz_breakdown_);
}
}
-void CompositorFrameReporter::ReportEventLatencyBlinkBreakdowns(
- int histogram_base_index,
- const std::string& histogram_base_name) const {
- for (size_t i = 0; i < base::size(blink_breakdown_list_); i++) {
- ReportEventLatencyHistogram(histogram_base_index, histogram_base_name,
- kBlinkBreakdownInitialIndex + i,
- blink_breakdown_list_[i]);
- }
-}
-
-void CompositorFrameReporter::ReportEventLatencyVizBreakdowns(
- int histogram_base_index,
- const std::string& histogram_base_name) const {
- for (size_t i = 0; i < base::size(viz_breakdown_list_); i++) {
- if (!viz_breakdown_list_[i]) {
-#if DCHECK_IS_ON()
- // Remaining breakdowns should be unset.
- for (; i < base::size(viz_breakdown_list_); i++)
- DCHECK(!viz_breakdown_list_[i]);
-#endif
- break;
- }
- const base::TimeTicks start_time = viz_breakdown_list_[i]->first;
- const base::TimeTicks end_time = viz_breakdown_list_[i]->second;
- ReportEventLatencyHistogram(histogram_base_index, histogram_base_name,
- kVizBreakdownInitialIndex + i,
- end_time - start_time);
- }
-}
-
-void CompositorFrameReporter::ReportEventLatencyHistogram(
- int histogram_base_index,
- const std::string& histogram_base_name,
- int stage_type_index,
- base::TimeDelta latency) const {
- const std::string histogram_name =
- base::StrCat({histogram_base_name, ".", GetStageName(stage_type_index)});
- const int histogram_index =
- histogram_base_index * (kStageTypeCount + kAllBreakdownCount) +
- stage_type_index;
- // Note: There's a 1:1 mapping between `histogram_index` and `histogram_name`
- // which allows the use of `STATIC_HISTOGRAM_POINTER_GROUP()` to cache
- // histogram objects.
- STATIC_HISTOGRAM_POINTER_GROUP(
- histogram_name, histogram_index, kMaxEventLatencyHistogramIndex,
- AddTimeMicrosecondsGranularity(latency),
- base::Histogram::FactoryMicrosecondsTimeGet(
- histogram_name, kEventLatencyHistogramMin, kEventLatencyHistogramMax,
- kEventLatencyHistogramBucketCount,
- base::HistogramBase::kUmaTargetedHistogramFlag));
-}
-
void CompositorFrameReporter::ReportCompositorLatencyTraceEvents() const {
if (stage_history_.empty())
return;
@@ -840,8 +1040,8 @@ void CompositorFrameReporter::ReportCompositorLatencyTraceEvents() const {
const auto trace_track = perfetto::Track(reinterpret_cast<uint64_t>(this));
TRACE_EVENT_BEGIN(
- "cc,benchmark", "PipelineReporter", trace_track,
- stage_history_.front().start_time, [&](perfetto::EventContext context) {
+ "cc,benchmark", "PipelineReporter", trace_track, args_.frame_time,
+ [&](perfetto::EventContext context) {
using perfetto::protos::pbzero::ChromeFrameReporter;
bool frame_dropped = TestReportType(FrameReportType::kDroppedFrame);
ChromeFrameReporter::State state;
@@ -851,7 +1051,7 @@ void CompositorFrameReporter::ReportCompositorLatencyTraceEvents() const {
FrameTerminationStatus::kDidNotProduceFrame) {
state = ChromeFrameReporter::STATE_NO_UPDATE_DESIRED;
} else {
- state = has_partial_update()
+ state = has_partial_update_
? ChromeFrameReporter::STATE_PRESENTED_PARTIAL
: ChromeFrameReporter::STATE_PRESENTED_ALL;
}
@@ -881,17 +1081,23 @@ void CompositorFrameReporter::ReportCompositorLatencyTraceEvents() const {
if (stage.start_time == stage.end_time)
continue;
const char* stage_name = GetStageName(stage_type_index);
- TRACE_EVENT_BEGIN("cc,benchmark", stage_name, trace_track,
- stage.start_time);
+ TRACE_EVENT_BEGIN("cc,benchmark", perfetto::StaticString{stage_name},
+ trace_track, stage.start_time);
if (stage.stage_type ==
StageType::kSubmitCompositorFrameToPresentationCompositorFrame) {
- REPORT_VIZ_BREAKDOWN_TRACES([&](base::TimeTicks start_time,
- base::TimeTicks end_time,
- const char* substage_name) {
- TRACE_EVENT_BEGIN("cc,benchmark", substage_name, trace_track,
+ DCHECK(processed_viz_breakdown_);
+ for (auto it = processed_viz_breakdown_->CreateIterator(true);
+ it.IsValid(); it.Advance()) {
+ base::TimeTicks start_time = it.GetStartTime();
+ base::TimeTicks end_time = it.GetEndTime();
+ if (start_time >= end_time)
+ continue;
+ const char* breakdown_name = GetVizBreakdownName(it.GetBreakdown());
+ TRACE_EVENT_BEGIN("cc,benchmark",
+ perfetto::StaticString{breakdown_name}, trace_track,
start_time);
TRACE_EVENT_END("cc,benchmark", trace_track, end_time);
- });
+ }
}
TRACE_EVENT_END("cc,benchmark", trace_track, stage.end_time);
}
@@ -901,36 +1107,83 @@ void CompositorFrameReporter::ReportCompositorLatencyTraceEvents() const {
}
void CompositorFrameReporter::ReportEventLatencyTraceEvents() const {
+ // TODO(mohsen): This function is becoming large and there is concerns about
+ // having this in the compositor critical path. crbug.com/1072740 is
+ // considering doing the reporting off-thread, but as a short-term solution,
+ // we should investigate whether we can skip this function entirely if tracing
+ // is off and whether that has any positive impact or not.
for (const auto& event_metrics : events_metrics_) {
+ const base::TimeTicks generated_timestamp =
+ event_metrics->GetDispatchStageTimestamp(
+ EventMetrics::DispatchStage::kGenerated);
+
const auto trace_id = TRACE_ID_LOCAL(event_metrics.get());
TRACE_EVENT_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP1(
- "cc,input", "EventLatency", trace_id, event_metrics->time_stamp(),
- "event", event_metrics->GetTypeName());
-
- // Find the first stage that happens after the event's arrival in the
- // browser.
- auto stage_it =
- std::find_if(stage_history_.begin(), stage_history_.end(),
- [&event_metrics](const StageData& stage) {
- return stage.start_time > event_metrics->time_stamp();
- });
+ "cc,input", "EventLatency", trace_id, generated_timestamp, "event",
+ event_metrics->GetTypeName());
+
+ // Event dispatch stages.
+ 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());
+
+ // Find the end dispatch stage.
+ 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;
+
+ const char* breakdown_name =
+ GetEventLatencyDispatchBreakdownName(dispatch_stage, end_stage);
+ TRACE_EVENT_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0(
+ "cc,input", breakdown_name, trace_id, dispatch_timestamp);
+ TRACE_EVENT_NESTABLE_ASYNC_END_WITH_TIMESTAMP0("cc,input", breakdown_name,
+ trace_id, end_timestamp);
+
+ dispatch_stage = end_stage;
+ dispatch_timestamp = end_timestamp;
+ }
+
+ // Find the first compositor stage that happens after the final dispatch
+ // stage.
+ auto stage_it = std::find_if(stage_history_.begin(), stage_history_.end(),
+ [dispatch_timestamp](const StageData& stage) {
+ return stage.start_time > dispatch_timestamp;
+ });
// TODO(crbug.com/1079116): Ideally, at least the start time of
// SubmitCompositorFrameToPresentationCompositorFrame stage should be
- // greater than the event time stamp, but apparently, this is not always the
- // case (see crbug.com/1093698). For now, skip to the next event in such
- // cases. Hopefully, the work to reduce discrepancies between the new
- // EventLatency and the old Event.Latency metrics would fix this issue. If
- // not, we need to reconsider investigating this issue.
+ // greater than the final event dispatch timestamp, but apparently, this is
+ // not always the case (see crbug.com/1093698). For now, skip to the next
+ // event in such cases. Hopefully, the work to reduce discrepancies between
+ // the new EventLatency and the old Event.Latency metrics would fix this
+ // issue. If not, we need to reconsider investigating this issue.
if (stage_it == stage_history_.end())
continue;
+ DCHECK(dispatch_stage ==
+ EventMetrics::DispatchStage::kRendererCompositorFinished ||
+ dispatch_stage ==
+ EventMetrics::DispatchStage::kRendererMainFinished);
+ const char* d2c_breakdown_name =
+ GetEventLatencyDispatchToCompositorBreakdownName(dispatch_stage,
+ stage_it->stage_type);
TRACE_EVENT_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0(
- "cc,input", "BrowserToRendererCompositor", trace_id,
- event_metrics->time_stamp());
+ "cc,input", d2c_breakdown_name, trace_id, dispatch_timestamp);
TRACE_EVENT_NESTABLE_ASYNC_END_WITH_TIMESTAMP0(
- "cc,input", "BrowserToRendererCompositor", trace_id,
- stage_it->start_time);
+ "cc,input", d2c_breakdown_name, trace_id, stage_it->start_time);
+ // Compositor stages.
for (; stage_it != stage_history_.end(); ++stage_it) {
const int stage_type_index = static_cast<int>(stage_it->stage_type);
CHECK_LT(stage_type_index, static_cast<int>(StageType::kStageTypeCount));
@@ -947,14 +1200,19 @@ void CompositorFrameReporter::ReportEventLatencyTraceEvents() const {
if (stage_it->stage_type ==
StageType::kSubmitCompositorFrameToPresentationCompositorFrame) {
- REPORT_VIZ_BREAKDOWN_TRACES([&](base::TimeTicks start_time,
- base::TimeTicks end_time,
- const char* substage_name) {
+ DCHECK(processed_viz_breakdown_);
+ for (auto it = processed_viz_breakdown_->CreateIterator(true);
+ it.IsValid(); it.Advance()) {
+ base::TimeTicks start_time = it.GetStartTime();
+ base::TimeTicks end_time = it.GetEndTime();
+ if (start_time >= end_time)
+ continue;
+ const char* breakdown_name = GetVizBreakdownName(it.GetBreakdown());
TRACE_EVENT_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0(
- "cc,input", substage_name, trace_id, start_time);
+ "cc,input", breakdown_name, trace_id, start_time);
TRACE_EVENT_NESTABLE_ASYNC_END_WITH_TIMESTAMP0(
- "cc,input", substage_name, trace_id, end_time);
- });
+ "cc,input", breakdown_name, trace_id, end_time);
+ }
}
TRACE_EVENT_NESTABLE_ASYNC_END_WITH_TIMESTAMP0(
@@ -965,92 +1223,6 @@ void CompositorFrameReporter::ReportEventLatencyTraceEvents() const {
}
}
-void CompositorFrameReporter::PopulateBlinkBreakdownList() {
- if (blink_start_time_.is_null())
- return;
-
- blink_breakdown_list_[static_cast<int>(BlinkBreakdown::kHandleInputEvents)] =
- blink_breakdown_.handle_input_events;
- blink_breakdown_list_[static_cast<int>(BlinkBreakdown::kAnimate)] =
- blink_breakdown_.animate;
- blink_breakdown_list_[static_cast<int>(BlinkBreakdown::kStyleUpdate)] =
- blink_breakdown_.style_update;
- blink_breakdown_list_[static_cast<int>(BlinkBreakdown::kLayoutUpdate)] =
- blink_breakdown_.layout_update;
- blink_breakdown_list_[static_cast<int>(BlinkBreakdown::kPrepaint)] =
- blink_breakdown_.prepaint;
- blink_breakdown_list_[static_cast<int>(BlinkBreakdown::kCompositingInputs)] =
- blink_breakdown_.compositing_inputs;
- blink_breakdown_list_[static_cast<int>(
- BlinkBreakdown::kCompositingAssignments)] =
- blink_breakdown_.compositing_assignments;
- blink_breakdown_list_[static_cast<int>(BlinkBreakdown::kPaint)] =
- blink_breakdown_.paint;
- blink_breakdown_list_[static_cast<int>(BlinkBreakdown::kCompositeCommit)] =
- blink_breakdown_.composite_commit;
- blink_breakdown_list_[static_cast<int>(BlinkBreakdown::kUpdateLayers)] =
- blink_breakdown_.update_layers;
- blink_breakdown_list_[static_cast<int>(
- BlinkBreakdown::kBeginMainSentToStarted)] =
- begin_main_frame_start_ - blink_start_time_;
-}
-
-void CompositorFrameReporter::PopulateVizBreakdownList() {
- if (viz_start_time_.is_null())
- return;
-
- // Check if viz_breakdown is set. Testing indicates that sometimes the
- // received_compositor_frame_timestamp can be earlier than the given
- // |start_time|. Avoid reporting negative times.
- if (viz_breakdown_.received_compositor_frame_timestamp.is_null() ||
- viz_breakdown_.received_compositor_frame_timestamp < viz_start_time_) {
- return;
- }
- viz_breakdown_list_[static_cast<int>(
- VizBreakdown::kSubmitToReceiveCompositorFrame)] =
- std::make_pair(viz_start_time_,
- viz_breakdown_.received_compositor_frame_timestamp);
-
- if (viz_breakdown_.draw_start_timestamp.is_null())
- return;
- viz_breakdown_list_[static_cast<int>(
- VizBreakdown::kReceivedCompositorFrameToStartDraw)] =
- std::make_pair(viz_breakdown_.received_compositor_frame_timestamp,
- viz_breakdown_.draw_start_timestamp);
-
- if (viz_breakdown_.swap_timings.is_null())
- return;
- viz_breakdown_list_[static_cast<int>(VizBreakdown::kStartDrawToSwapStart)] =
- std::make_pair(viz_breakdown_.draw_start_timestamp,
- viz_breakdown_.swap_timings.swap_start);
-
- viz_breakdown_list_[static_cast<int>(VizBreakdown::kSwapStartToSwapEnd)] =
- std::make_pair(viz_breakdown_.swap_timings.swap_start,
- viz_breakdown_.swap_timings.swap_end);
-
- viz_breakdown_list_[static_cast<int>(
- VizBreakdown::kSwapEndToPresentationCompositorFrame)] =
- std::make_pair(viz_breakdown_.swap_timings.swap_end,
- viz_breakdown_.presentation_feedback.timestamp);
-
- if (viz_breakdown_.presentation_feedback.ready_timestamp.is_null())
- return;
- viz_breakdown_list_[static_cast<int>(
- VizBreakdown::kSwapStartToBufferAvailable)] =
- std::make_pair(viz_breakdown_.swap_timings.swap_start,
- viz_breakdown_.presentation_feedback.available_timestamp);
- viz_breakdown_list_[static_cast<int>(
- VizBreakdown::kBufferAvailableToBufferReady)] =
- std::make_pair(viz_breakdown_.presentation_feedback.available_timestamp,
- viz_breakdown_.presentation_feedback.ready_timestamp);
- viz_breakdown_list_[static_cast<int>(VizBreakdown::kBufferReadyToLatch)] =
- std::make_pair(viz_breakdown_.presentation_feedback.ready_timestamp,
- viz_breakdown_.presentation_feedback.latch_timestamp);
- viz_breakdown_list_[static_cast<int>(VizBreakdown::kLatchToSwapEnd)] =
- std::make_pair(viz_breakdown_.presentation_feedback.latch_timestamp,
- viz_breakdown_.swap_timings.swap_end);
-}
-
base::TimeDelta CompositorFrameReporter::SumOfStageHistory() const {
base::TimeDelta sum;
for (const StageData& stage : stage_history_)
@@ -1089,8 +1261,41 @@ base::WeakPtr<CompositorFrameReporter> CompositorFrameReporter::GetWeakPtr() {
void CompositorFrameReporter::AdoptReporter(
std::unique_ptr<CompositorFrameReporter> reporter) {
- DCHECK_EQ(cloned_to_.get(), reporter.get());
- own_cloned_to_ = std::move(reporter);
+ // If |this| reporter is dependent on another reporter to decide about partial
+ // update, then |this| should not have any such dependents.
+ DCHECK(!partial_update_decider_);
+ DCHECK(!partial_update_dependents_.empty());
+ owned_partial_update_dependents_.push(std::move(reporter));
+ DiscardOldPartialUpdateReporters();
+}
+
+void CompositorFrameReporter::SetPartialUpdateDecider(
+ base::WeakPtr<CompositorFrameReporter> decider) {
+ DCHECK(decider);
+ has_partial_update_ = true;
+ partial_update_decider_ = decider;
+ decider->partial_update_dependents_.push(GetWeakPtr());
+ DCHECK(partial_update_dependents_.empty());
+}
+
+void CompositorFrameReporter::DiscardOldPartialUpdateReporters() {
+ DCHECK_LE(owned_partial_update_dependents_.size(),
+ partial_update_dependents_.size());
+ while (owned_partial_update_dependents_.size() > 300u) {
+ auto& dependent = owned_partial_update_dependents_.front();
+ dependent->set_has_partial_update(false);
+ partial_update_dependents_.pop();
+ owned_partial_update_dependents_.pop();
+ discarded_partial_update_dependents_count_++;
+ }
+}
+
+bool CompositorFrameReporter::MightHavePartialUpdate() const {
+ return !!partial_update_decider_;
+}
+
+size_t CompositorFrameReporter::GetPartialUpdateDependentsCount() const {
+ return partial_update_dependents_.size();
}
} // namespace cc
diff --git a/chromium/cc/metrics/compositor_frame_reporter.h b/chromium/cc/metrics/compositor_frame_reporter.h
index 6c5cb9ba86d..0e9f0001b06 100644
--- a/chromium/cc/metrics/compositor_frame_reporter.h
+++ b/chromium/cc/metrics/compositor_frame_reporter.h
@@ -7,6 +7,7 @@
#include <bitset>
#include <memory>
+#include <queue>
#include <string>
#include <utility>
#include <vector>
@@ -140,6 +141,88 @@ class CC_EXPORT CompositorFrameReporter {
kSmoothBoth
};
+ // Holds a processed list of Blink breakdowns with an `Iterator` class to
+ // easily iterator over them.
+ class CC_EXPORT ProcessedBlinkBreakdown {
+ public:
+ class Iterator {
+ public:
+ explicit Iterator(const ProcessedBlinkBreakdown* owner);
+ ~Iterator();
+
+ bool IsValid() const;
+ void Advance();
+ BlinkBreakdown GetBreakdown() const;
+ base::TimeDelta GetLatency() const;
+
+ private:
+ const ProcessedBlinkBreakdown* owner_;
+
+ size_t index_ = 0;
+ };
+
+ ProcessedBlinkBreakdown(base::TimeTicks blink_start_time,
+ base::TimeTicks begin_main_frame_start,
+ const BeginMainFrameMetrics& blink_breakdown);
+ ~ProcessedBlinkBreakdown();
+
+ ProcessedBlinkBreakdown(const ProcessedBlinkBreakdown&) = delete;
+ ProcessedBlinkBreakdown& operator=(const ProcessedBlinkBreakdown&) = delete;
+
+ // Returns a new iterator for the Blink breakdowns.
+ Iterator CreateIterator() const;
+
+ private:
+ base::TimeDelta list_[static_cast<int>(BlinkBreakdown::kBreakdownCount)];
+ };
+
+ // Holds a processed list of Viz breakdowns with an `Iterator` class to easily
+ // iterate over them.
+ class CC_EXPORT ProcessedVizBreakdown {
+ public:
+ class Iterator {
+ public:
+ Iterator(const ProcessedVizBreakdown* owner,
+ bool skip_swap_start_to_swap_end);
+ ~Iterator();
+
+ bool IsValid() const;
+ void Advance();
+ VizBreakdown GetBreakdown() const;
+ base::TimeTicks GetStartTime() const;
+ base::TimeTicks GetEndTime() const;
+ base::TimeDelta GetDuration() const;
+
+ private:
+ const ProcessedVizBreakdown* owner_;
+ const bool skip_swap_start_to_swap_end_;
+
+ size_t index_ = 0;
+ };
+
+ ProcessedVizBreakdown(base::TimeTicks viz_start_time,
+ const viz::FrameTimingDetails& viz_breakdown);
+ ~ProcessedVizBreakdown();
+
+ ProcessedVizBreakdown(const ProcessedVizBreakdown&) = delete;
+ ProcessedVizBreakdown& operator=(const ProcessedVizBreakdown&) = delete;
+
+ // Returns a new iterator for the Viz breakdowns. If buffer ready breakdowns
+ // are available, `skip_swap_start_to_swap_end_if_breakdown_available` can
+ // be used to skip `kSwapStartToSwapEnd` breakdown.
+ Iterator CreateIterator(
+ bool skip_swap_start_to_swap_end_if_breakdown_available) const;
+
+ base::TimeTicks swap_start() const { return swap_start_; }
+
+ private:
+ base::Optional<std::pair<base::TimeTicks, base::TimeTicks>>
+ list_[static_cast<int>(VizBreakdown::kBreakdownCount)];
+
+ bool buffer_ready_available_ = false;
+ base::TimeTicks swap_start_;
+ };
+
using ActiveTrackers =
std::bitset<static_cast<size_t>(FrameSequenceTrackerType::kMaxType)>;
@@ -156,6 +239,11 @@ class CC_EXPORT CompositorFrameReporter {
CompositorFrameReporter& operator=(const CompositorFrameReporter& reporter) =
delete;
+ // Creates and returns a clone of the reporter, only if it is currently in the
+ // 'begin impl frame' stage. For any other state, it returns null.
+ // This is used only when there is a partial update. So the cloned reporter
+ // depends in this reporter to decide whether it contains be partial updates
+ // or complete updates.
std::unique_ptr<CompositorFrameReporter> CopyReporterAtBeginImplStage();
// Note that the started stage may be reported to UMA. If the histogram is
@@ -200,10 +288,10 @@ class CC_EXPORT CompositorFrameReporter {
tick_clock_ = tick_clock;
}
- bool has_partial_update() const { return has_partial_update_; }
- void set_has_partial_update(bool has_partial_update) {
- has_partial_update_ = has_partial_update;
- }
+ void SetPartialUpdateDecider(base::WeakPtr<CompositorFrameReporter> decider);
+
+ bool MightHavePartialUpdate() const;
+ size_t GetPartialUpdateDependentsCount() const;
const viz::BeginFrameId& frame_id() const { return args_.frame_id; }
@@ -214,11 +302,18 @@ class CC_EXPORT CompositorFrameReporter {
// If this is a cloned reporter, then this returns a weak-ptr to the original
// reporter this was cloned from (using |CopyReporterAtBeginImplStage()|).
- base::WeakPtr<CompositorFrameReporter> cloned_from() { return cloned_from_; }
- protected:
+ base::WeakPtr<CompositorFrameReporter> partial_update_decider() {
+ return partial_update_decider_;
+ }
+
base::WeakPtr<CompositorFrameReporter> GetWeakPtr();
+ protected:
+ void set_has_partial_update(bool has_partial_update) {
+ has_partial_update_ = has_partial_update;
+ }
+
private:
void TerminateReporter();
void EndCurrentStage(base::TimeTicks end_time);
@@ -238,16 +333,6 @@ class CC_EXPORT CompositorFrameReporter {
base::TimeDelta time_delta) const;
void ReportEventLatencyHistograms() const;
- void ReportEventLatencyBlinkBreakdowns(
- int histogram_base_index,
- const std::string& histogram_base_name) const;
- void ReportEventLatencyVizBreakdowns(
- int histogram_base_index,
- const std::string& histogram_base_name) const;
- void ReportEventLatencyHistogram(int histogram_base_index,
- const std::string& histogram_base_name,
- int stage_type_index,
- base::TimeDelta latency) const;
void ReportCompositorLatencyTraceEvents() const;
void ReportEventLatencyTraceEvents() const;
@@ -259,12 +344,12 @@ class CC_EXPORT CompositorFrameReporter {
return report_types_.test(static_cast<size_t>(report_type));
}
- void PopulateBlinkBreakdownList();
- void PopulateVizBreakdownList();
-
// This method is only used for DCheck
base::TimeDelta SumOfStageHistory() const;
+ // Terminating reporters in partial_update_dependents_ after a limit.
+ void DiscardOldPartialUpdateReporters();
+
base::TimeTicks Now() const;
bool IsDroppedFrameAffectingSmoothness() const;
@@ -276,13 +361,11 @@ class CC_EXPORT CompositorFrameReporter {
BeginMainFrameMetrics blink_breakdown_;
base::TimeTicks blink_start_time_;
- base::TimeDelta
- blink_breakdown_list_[static_cast<int>(BlinkBreakdown::kBreakdownCount)];
+ std::unique_ptr<ProcessedBlinkBreakdown> processed_blink_breakdown_;
viz::FrameTimingDetails viz_breakdown_;
base::TimeTicks viz_start_time_;
- base::Optional<std::pair<base::TimeTicks, base::TimeTicks>>
- viz_breakdown_list_[static_cast<int>(VizBreakdown::kBreakdownCount)];
+ std::unique_ptr<ProcessedVizBreakdown> processed_viz_breakdown_;
// Stage data is recorded here. On destruction these stages will be reported
// to UMA if the termination status is |kPresentedFrame|. Reported data will
@@ -324,18 +407,24 @@ class CC_EXPORT CompositorFrameReporter {
const SmoothThread smooth_thread_;
const int layer_tree_host_id_;
- // If this is a cloned pointer, then |cloned_from_| is a weak pointer to the
- // original reporter this was cloned from.
- base::WeakPtr<CompositorFrameReporter> cloned_from_;
-
- // If this reporter was cloned, then |cloned_to_| is a weak pointer to the
- // cloned repoter.
- base::WeakPtr<CompositorFrameReporter> cloned_to_;
-
- // A cloned reporter is not originally owned by the original reporter.
- // However, it can 'adopt' it (using |AdoptReporter()| if the cloned reporter
- // needs to stay alive until the original reporter terminates.
- std::unique_ptr<CompositorFrameReporter> own_cloned_to_;
+ // 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
+ // frames contained partial updates (i.e. main-thread made some visual
+ // updates, but were not included in the frame), or complete updates.
+ // In such cases, |partial_update_dependents_| for A contains all the frames
+ // that depend on A for deciding whether they had partial updates or not, and
+ // |partial_update_decider_| is set to A for all these reporters.
+ std::queue<base::WeakPtr<CompositorFrameReporter>> partial_update_dependents_;
+ base::WeakPtr<CompositorFrameReporter> partial_update_decider_;
+ uint32_t discarded_partial_update_dependents_count_ = 0;
+
+ // From the above example, it may be necessary for A to keep all the
+ // dependents alive until A terminates, so that the dependents can set their
+ // |has_partial_update_| flags correctly. This is done by passing ownership of
+ // these reporters (using |AdoptReporter()|).
+ std::queue<std::unique_ptr<CompositorFrameReporter>>
+ owned_partial_update_dependents_;
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 8455ec95bac..e7a38ba77fc 100644
--- a/chromium/cc/metrics/compositor_frame_reporter_unittest.cc
+++ b/chromium/cc/metrics/compositor_frame_reporter_unittest.cc
@@ -4,6 +4,7 @@
#include "cc/metrics/compositor_frame_reporter.h"
+#include <algorithm>
#include <memory>
#include <utility>
#include <vector>
@@ -80,6 +81,40 @@ class CompositorFrameReporterTest : public testing::Test {
return viz_breakdown;
}
+ std::unique_ptr<EventMetrics> CreateEventMetrics(
+ ui::EventType type,
+ base::Optional<EventMetrics::ScrollUpdateType> scroll_update_type,
+ base::Optional<ui::ScrollInputType> scroll_input_type) {
+ const base::TimeTicks event_time = AdvanceNowByMs(3);
+ AdvanceNowByMs(3);
+ std::unique_ptr<EventMetrics> metrics = EventMetrics::CreateForTesting(
+ type, scroll_update_type, scroll_input_type, event_time,
+ &test_tick_clock_);
+ if (metrics) {
+ AdvanceNowByMs(3);
+ metrics->SetDispatchStageTimestamp(
+ EventMetrics::DispatchStage::kRendererCompositorStarted);
+ AdvanceNowByMs(3);
+ metrics->SetDispatchStageTimestamp(
+ EventMetrics::DispatchStage::kRendererCompositorFinished);
+ }
+
+ return metrics;
+ }
+
+ std::vector<base::TimeTicks> GetEventTimestamps(
+ const EventMetrics::List& events_metrics) {
+ std::vector<base::TimeTicks> event_times;
+ event_times.reserve(events_metrics.size());
+ std::transform(events_metrics.cbegin(), events_metrics.cend(),
+ std::back_inserter(event_times),
+ [](const auto& event_metrics) {
+ return event_metrics->GetDispatchStageTimestamp(
+ EventMetrics::DispatchStage::kGenerated);
+ });
+ return event_times;
+ }
+
// This should be defined before |pipeline_reporter_| so it is created before
// and destroyed after that.
base::SimpleTestTickClock test_tick_clock_;
@@ -238,19 +273,16 @@ TEST_F(CompositorFrameReporterTest,
EventLatencyTotalForPresentedFrameReported) {
base::HistogramTester histogram_tester;
- const base::TimeTicks event_time = Now();
std::unique_ptr<EventMetrics> event_metrics_ptrs[] = {
- EventMetrics::Create(ui::ET_TOUCH_PRESSED, base::nullopt, event_time,
- base::nullopt),
- EventMetrics::Create(ui::ET_TOUCH_MOVED, base::nullopt, event_time,
- base::nullopt),
- EventMetrics::Create(ui::ET_TOUCH_MOVED, base::nullopt, event_time,
- base::nullopt),
+ CreateEventMetrics(ui::ET_TOUCH_PRESSED, base::nullopt, base::nullopt),
+ CreateEventMetrics(ui::ET_TOUCH_MOVED, base::nullopt, base::nullopt),
+ CreateEventMetrics(ui::ET_TOUCH_MOVED, base::nullopt, base::nullopt),
};
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)));
+ std::vector<base::TimeTicks> event_times = GetEventTimestamps(events_metrics);
AdvanceNowByMs(3);
pipeline_reporter_->StartStage(
@@ -269,171 +301,46 @@ TEST_F(CompositorFrameReporterTest,
Now());
pipeline_reporter_->SetEventsMetrics(std::move(events_metrics));
- AdvanceNowByMs(3);
- const base::TimeTicks presentation_time = Now();
+ const base::TimeTicks presentation_time = AdvanceNowByMs(3);
pipeline_reporter_->TerminateFrame(
CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame,
presentation_time);
pipeline_reporter_ = nullptr;
- const int latency_ms = (presentation_time - event_time).InMicroseconds();
- histogram_tester.ExpectTotalCount("EventLatency.TouchPressed.TotalLatency",
- 1);
- histogram_tester.ExpectTotalCount("EventLatency.TouchMoved.TotalLatency", 2);
- histogram_tester.ExpectTotalCount("EventLatency.TotalLatency", 3);
- histogram_tester.ExpectBucketCount("EventLatency.TouchPressed.TotalLatency",
- latency_ms, 1);
- histogram_tester.ExpectBucketCount("EventLatency.TouchMoved.TotalLatency",
- latency_ms, 2);
- histogram_tester.ExpectBucketCount("EventLatency.TotalLatency", latency_ms,
- 3);
-}
-
-// Tests that when a frame is presented to the user, event latency breakdown
-// metrics are reported properly.
-TEST_F(CompositorFrameReporterTest,
- EventLatencyBreakdownsForPresentedFrameReported) {
- base::HistogramTester histogram_tester;
-
- const base::TimeTicks event_time = Now();
- std::unique_ptr<EventMetrics> event_metrics_ptrs[] = {
- EventMetrics::Create(ui::ET_TOUCH_PRESSED, base::nullopt, event_time,
- base::nullopt),
+ struct {
+ const char* name;
+ const base::HistogramBase::Count count;
+ } expected_counts[] = {
+ {"EventLatency.TouchPressed.TotalLatency", 1},
+ {"EventLatency.TouchMoved.TotalLatency", 2},
+ {"EventLatency.TotalLatency", 3},
};
- 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)));
-
- auto begin_impl_time = AdvanceNowByMs(2);
- pipeline_reporter_->StartStage(
- CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame,
- begin_impl_time);
-
- auto begin_main_time = AdvanceNowByMs(3);
- pipeline_reporter_->StartStage(
- CompositorFrameReporter::StageType::kSendBeginMainFrameToCommit,
- begin_main_time);
-
- auto begin_main_start_time = AdvanceNowByMs(4);
- std::unique_ptr<BeginMainFrameMetrics> blink_breakdown =
- BuildBlinkBreakdown();
- // Make a copy of the breakdown to use in verifying expectations in the end.
- BeginMainFrameMetrics blink_breakdown_copy = *blink_breakdown;
- pipeline_reporter_->SetBlinkBreakdown(std::move(blink_breakdown),
- begin_main_start_time);
- auto begin_commit_time = AdvanceNowByMs(5);
- pipeline_reporter_->StartStage(CompositorFrameReporter::StageType::kCommit,
- begin_commit_time);
-
- auto end_commit_time = AdvanceNowByMs(6);
- pipeline_reporter_->StartStage(
- CompositorFrameReporter::StageType::kEndCommitToActivation,
- end_commit_time);
-
- auto begin_activation_time = AdvanceNowByMs(7);
- pipeline_reporter_->StartStage(
- CompositorFrameReporter::StageType::kActivation, begin_activation_time);
-
- auto end_activation_time = AdvanceNowByMs(8);
- pipeline_reporter_->StartStage(
- CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame,
- end_activation_time);
-
- auto submit_time = AdvanceNowByMs(9);
- pipeline_reporter_->StartStage(
- CompositorFrameReporter::StageType::
- kSubmitCompositorFrameToPresentationCompositorFrame,
- submit_time);
- pipeline_reporter_->SetEventsMetrics(std::move(events_metrics));
-
- AdvanceNowByMs(10);
- viz::FrameTimingDetails viz_breakdown = BuildVizBreakdown();
- pipeline_reporter_->SetVizBreakdown(viz_breakdown);
- pipeline_reporter_->TerminateFrame(
- CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame,
- viz_breakdown.presentation_feedback.timestamp);
-
- pipeline_reporter_ = nullptr;
+ for (const auto& expected_count : expected_counts) {
+ histogram_tester.ExpectTotalCount(expected_count.name,
+ expected_count.count);
+ }
struct {
const char* name;
- const base::TimeDelta latency;
+ const base::HistogramBase::Sample latency_ms;
} expected_latencies[] = {
- {"EventLatency.TouchPressed.BrowserToRendererCompositor",
- begin_impl_time - event_time},
- {"EventLatency.TouchPressed.BeginImplFrameToSendBeginMainFrame",
- begin_main_time - begin_impl_time},
- {"EventLatency.TouchPressed.SendBeginMainFrameToCommit",
- begin_commit_time - begin_main_time},
- {"EventLatency.TouchPressed.SendBeginMainFrameToCommit.HandleInputEvents",
- blink_breakdown_copy.handle_input_events},
- {"EventLatency.TouchPressed.SendBeginMainFrameToCommit.Animate",
- blink_breakdown_copy.animate},
- {"EventLatency.TouchPressed.SendBeginMainFrameToCommit.StyleUpdate",
- blink_breakdown_copy.style_update},
- {"EventLatency.TouchPressed.SendBeginMainFrameToCommit.LayoutUpdate",
- blink_breakdown_copy.layout_update},
- {"EventLatency.TouchPressed.SendBeginMainFrameToCommit.CompositingInputs",
- blink_breakdown_copy.compositing_inputs},
- {"EventLatency.TouchPressed.SendBeginMainFrameToCommit.Prepaint",
- blink_breakdown_copy.prepaint},
- {"EventLatency.TouchPressed.SendBeginMainFrameToCommit"
- ".CompositingAssignments",
- blink_breakdown_copy.compositing_assignments},
- {"EventLatency.TouchPressed.SendBeginMainFrameToCommit.Paint",
- blink_breakdown_copy.paint},
- {"EventLatency.TouchPressed.SendBeginMainFrameToCommit.CompositeCommit",
- blink_breakdown_copy.composite_commit},
- {"EventLatency.TouchPressed.SendBeginMainFrameToCommit.UpdateLayers",
- blink_breakdown_copy.update_layers},
- {"EventLatency.TouchPressed.SendBeginMainFrameToCommit."
- "BeginMainSentToStarted",
- begin_main_start_time - begin_main_time},
- {"EventLatency.TouchPressed.Commit", end_commit_time - begin_commit_time},
- {"EventLatency.TouchPressed.EndCommitToActivation",
- begin_activation_time - end_commit_time},
- {"EventLatency.TouchPressed.Activation",
- end_activation_time - begin_activation_time},
- {"EventLatency.TouchPressed.EndActivateToSubmitCompositorFrame",
- submit_time - end_activation_time},
- {"EventLatency.TouchPressed."
- "SubmitCompositorFrameToPresentationCompositorFrame",
- viz_breakdown.presentation_feedback.timestamp - submit_time},
- {"EventLatency.TouchPressed."
- "SubmitCompositorFrameToPresentationCompositorFrame."
- "SubmitToReceiveCompositorFrame",
- viz_breakdown.received_compositor_frame_timestamp - submit_time},
- {"EventLatency.TouchPressed."
- "SubmitCompositorFrameToPresentationCompositorFrame."
- "ReceivedCompositorFrameToStartDraw",
- viz_breakdown.draw_start_timestamp -
- viz_breakdown.received_compositor_frame_timestamp},
- {"EventLatency.TouchPressed."
- "SubmitCompositorFrameToPresentationCompositorFrame."
- "StartDrawToSwapStart",
- viz_breakdown.swap_timings.swap_start -
- viz_breakdown.draw_start_timestamp},
- {"EventLatency.TouchPressed."
- "SubmitCompositorFrameToPresentationCompositorFrame.SwapStartToSwapEnd",
- viz_breakdown.swap_timings.swap_end -
- viz_breakdown.swap_timings.swap_start},
- {"EventLatency.TouchPressed."
- "SubmitCompositorFrameToPresentationCompositorFrame."
- "SwapEndToPresentationCompositorFrame",
- viz_breakdown.presentation_feedback.timestamp -
- viz_breakdown.swap_timings.swap_end},
{"EventLatency.TouchPressed.TotalLatency",
- viz_breakdown.presentation_feedback.timestamp - event_time},
+ (presentation_time - event_times[0]).InMicroseconds()},
+ {"EventLatency.TouchMoved.TotalLatency",
+ (presentation_time - event_times[1]).InMicroseconds()},
+ {"EventLatency.TouchMoved.TotalLatency",
+ (presentation_time - event_times[2]).InMicroseconds()},
+ {"EventLatency.TotalLatency",
+ (presentation_time - event_times[0]).InMicroseconds()},
{"EventLatency.TotalLatency",
- viz_breakdown.presentation_feedback.timestamp - event_time},
+ (presentation_time - event_times[1]).InMicroseconds()},
+ {"EventLatency.TotalLatency",
+ (presentation_time - event_times[2]).InMicroseconds()},
};
-
for (const auto& expected_latency : expected_latencies) {
- histogram_tester.ExpectTotalCount(expected_latency.name, 1);
- histogram_tester.ExpectBucketCount(
- expected_latency.name, expected_latency.latency.InMicroseconds(), 1);
+ histogram_tester.ExpectBucketCount(expected_latency.name,
+ expected_latency.latency_ms, 1);
}
}
@@ -443,21 +350,21 @@ TEST_F(CompositorFrameReporterTest,
EventLatencyScrollTotalForPresentedFrameReported) {
base::HistogramTester histogram_tester;
- const base::TimeTicks event_time = Now();
std::unique_ptr<EventMetrics> event_metrics_ptrs[] = {
- EventMetrics::Create(ui::ET_GESTURE_SCROLL_BEGIN, base::nullopt,
- event_time, ui::ScrollInputType::kWheel),
- EventMetrics::Create(ui::ET_GESTURE_SCROLL_UPDATE,
- EventMetrics::ScrollUpdateType::kStarted, event_time,
- ui::ScrollInputType::kWheel),
- EventMetrics::Create(ui::ET_GESTURE_SCROLL_UPDATE,
- EventMetrics::ScrollUpdateType::kContinued,
- event_time, ui::ScrollInputType::kWheel),
+ CreateEventMetrics(ui::ET_GESTURE_SCROLL_BEGIN, base::nullopt,
+ ui::ScrollInputType::kWheel),
+ CreateEventMetrics(ui::ET_GESTURE_SCROLL_UPDATE,
+ EventMetrics::ScrollUpdateType::kStarted,
+ ui::ScrollInputType::kWheel),
+ CreateEventMetrics(ui::ET_GESTURE_SCROLL_UPDATE,
+ EventMetrics::ScrollUpdateType::kContinued,
+ ui::ScrollInputType::kWheel),
};
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)));
+ std::vector<base::TimeTicks> event_times = GetEventTimestamps(events_metrics);
AdvanceNowByMs(3);
pipeline_reporter_->StartStage(
@@ -485,32 +392,48 @@ TEST_F(CompositorFrameReporterTest,
pipeline_reporter_ = nullptr;
- const int total_latency_ms =
- (viz_breakdown.presentation_feedback.timestamp - event_time)
- .InMicroseconds();
- const int swap_begin_latency_ms =
- (viz_breakdown.swap_timings.swap_start - event_time).InMicroseconds();
struct {
const char* name;
- const int64_t latency_ms;
- } expected_metrics[] = {
- {"EventLatency.GestureScrollBegin.Wheel.TotalLatency", total_latency_ms},
+ const base::HistogramBase::Count count;
+ } expected_counts[] = {
+ {"EventLatency.GestureScrollBegin.Wheel.TotalLatency", 1},
+ {"EventLatency.GestureScrollBegin.Wheel.TotalLatencyToSwapBegin", 1},
+ {"EventLatency.FirstGestureScrollUpdate.Wheel.TotalLatency", 1},
+ {"EventLatency.FirstGestureScrollUpdate.Wheel.TotalLatencyToSwapBegin",
+ 1},
+ {"EventLatency.GestureScrollUpdate.Wheel.TotalLatency", 1},
+ {"EventLatency.GestureScrollUpdate.Wheel.TotalLatencyToSwapBegin", 1},
+ {"EventLatency.TotalLatency", 3},
+ };
+ for (const auto& expected_count : expected_counts) {
+ histogram_tester.ExpectTotalCount(expected_count.name,
+ expected_count.count);
+ }
+
+ const base::TimeTicks presentation_time =
+ viz_breakdown.presentation_feedback.timestamp;
+ const base::TimeTicks swap_begin_time = viz_breakdown.swap_timings.swap_start;
+ struct {
+ const char* name;
+ const base::HistogramBase::Sample latency_ms;
+ } expected_latencies[] = {
+ {"EventLatency.GestureScrollBegin.Wheel.TotalLatency",
+ (presentation_time - event_times[0]).InMicroseconds()},
{"EventLatency.GestureScrollBegin.Wheel.TotalLatencyToSwapBegin",
- swap_begin_latency_ms},
+ (swap_begin_time - event_times[0]).InMicroseconds()},
{"EventLatency.FirstGestureScrollUpdate.Wheel.TotalLatency",
- total_latency_ms},
+ (presentation_time - event_times[1]).InMicroseconds()},
{"EventLatency.FirstGestureScrollUpdate.Wheel.TotalLatencyToSwapBegin",
- swap_begin_latency_ms},
- {"EventLatency.GestureScrollUpdate.Wheel.TotalLatency", total_latency_ms},
+ (swap_begin_time - event_times[1]).InMicroseconds()},
+ {"EventLatency.GestureScrollUpdate.Wheel.TotalLatency",
+ (presentation_time - event_times[2]).InMicroseconds()},
{"EventLatency.GestureScrollUpdate.Wheel.TotalLatencyToSwapBegin",
- swap_begin_latency_ms},
+ (swap_begin_time - event_times[2]).InMicroseconds()},
};
- for (const auto& expected_metric : expected_metrics) {
- histogram_tester.ExpectTotalCount(expected_metric.name, 1);
- histogram_tester.ExpectBucketCount(expected_metric.name,
- expected_metric.latency_ms, 1);
+ for (const auto& expected_latency : expected_latencies) {
+ histogram_tester.ExpectBucketCount(expected_latency.name,
+ expected_latency.latency_ms, 1);
}
- histogram_tester.ExpectTotalCount("EventLatency.TotalLatency", 3);
}
// Tests that when the frame is not presented to the user, event latency metrics
@@ -519,14 +442,10 @@ TEST_F(CompositorFrameReporterTest,
EventLatencyForDidNotPresentFrameNotReported) {
base::HistogramTester histogram_tester;
- const base::TimeTicks event_time = Now();
std::unique_ptr<EventMetrics> event_metrics_ptrs[] = {
- EventMetrics::Create(ui::ET_TOUCH_PRESSED, base::nullopt, event_time,
- base::nullopt),
- EventMetrics::Create(ui::ET_TOUCH_MOVED, base::nullopt, event_time,
- base::nullopt),
- EventMetrics::Create(ui::ET_TOUCH_MOVED, base::nullopt, event_time,
- base::nullopt),
+ CreateEventMetrics(ui::ET_TOUCH_PRESSED, base::nullopt, base::nullopt),
+ CreateEventMetrics(ui::ET_TOUCH_MOVED, base::nullopt, base::nullopt),
+ CreateEventMetrics(ui::ET_TOUCH_MOVED, base::nullopt, base::nullopt),
};
EXPECT_THAT(event_metrics_ptrs, Each(NotNull()));
EventMetrics::List events_metrics(
diff --git a/chromium/cc/metrics/compositor_frame_reporting_controller.cc b/chromium/cc/metrics/compositor_frame_reporting_controller.cc
index 2ff29e6ba97..dec573d13d9 100644
--- a/chromium/cc/metrics/compositor_frame_reporting_controller.cc
+++ b/chromium/cc/metrics/compositor_frame_reporting_controller.cc
@@ -6,6 +6,7 @@
#include <utility>
+#include "base/trace_event/trace_event.h"
#include "cc/metrics/compositor_frame_reporter.h"
#include "cc/metrics/dropped_frame_counter.h"
#include "cc/metrics/latency_ukm_reporter.h"
@@ -221,6 +222,10 @@ void CompositorFrameReportingController::DidSubmitCompositorFrame(
AdvanceReporterStage(PipelineStage::kBeginImplFrame,
PipelineStage::kActivate);
impl_reporter = std::move(reporters_[PipelineStage::kActivate]);
+ auto partial_update_decider =
+ HasOutstandingUpdatesFromMain(current_frame_id);
+ if (partial_update_decider)
+ impl_reporter->SetPartialUpdateDecider(partial_update_decider);
} else if (CanSubmitMainFrame(current_frame_id)) {
auto& reporter = reporters_[PipelineStage::kBeginMainFrame];
reporter->StartStage(StageType::kEndActivateToSubmitCompositorFrame,
@@ -235,10 +240,6 @@ void CompositorFrameReportingController::DidSubmitCompositorFrame(
if (reporter) {
reporter->StartStage(StageType::kEndActivateToSubmitCompositorFrame,
reporter->impl_frame_finish_time());
- // If the frame does not include any new updates from the main thread,
- // then flag the frame as containing only partial updates.
- if (!is_activated_frame_new)
- reporter->set_has_partial_update(true);
impl_reporter = std::move(reporter);
}
}
@@ -306,20 +307,40 @@ void CompositorFrameReportingController::DidNotProduceFrame(
// BeginMain stage, but the main-thread can make updates, which can be
// submitted with the next frame.
stage_reporter->OnDidNotProduceFrame(skip_reason);
+ if (skip_reason == FrameSkippedReason::kWaitingOnMain)
+ SetPartialUpdateDeciderWhenWaitingOnMain(stage_reporter);
+
break;
}
}
+}
- // If the compositor has no updates, and the main-thread has not responded to
- // the begin-main-frame yet, then it is essentially a dropped frame. To handle
- // this case, keep the reporter for the main-thread, but recreate a reporter
- // for the dropped-frame.
- if (skip_reason == FrameSkippedReason::kWaitingOnMain) {
- auto reporter = RestoreReporterAtBeginImpl(id);
- if (reporter) {
- reporter->OnDidNotProduceFrame(skip_reason);
- reporter->TerminateFrame(FrameTerminationStatus::kDidNotProduceFrame,
- Now());
+void CompositorFrameReportingController::
+ SetPartialUpdateDeciderWhenWaitingOnMain(
+ std::unique_ptr<CompositorFrameReporter>& stage_reporter) {
+ // If the compositor has no updates, and the main-thread has not responded
+ // to the begin-main-frame yet, then depending on main thread having
+ // update or not this would be a NoFrameProduced or a DroppedFrame. To
+ // handle this case , keep the reporter for the main-thread, but recreate
+ // a reporter for the current frame and link it to the reporter it depends
+ // on.
+ auto reporter = RestoreReporterAtBeginImpl(stage_reporter->frame_id());
+ if (reporter) {
+ reporter->OnDidNotProduceFrame(FrameSkippedReason::kWaitingOnMain);
+ reporter->TerminateFrame(FrameTerminationStatus::kDidNotProduceFrame,
+ Now());
+ stage_reporter->AdoptReporter(std::move(reporter));
+ } else {
+ // The stage_reporter in this case was waiting for main, so needs to
+ // be adopted by the reporter which is waiting on Main thread's work
+ auto partial_update_decider =
+ HasOutstandingUpdatesFromMain(stage_reporter->frame_id());
+ if (partial_update_decider) {
+ stage_reporter->SetPartialUpdateDecider(partial_update_decider);
+ stage_reporter->OnDidNotProduceFrame(FrameSkippedReason::kWaitingOnMain);
+ stage_reporter->TerminateFrame(
+ FrameTerminationStatus::kDidNotProduceFrame, Now());
+ partial_update_decider->AdoptReporter(std::move(stage_reporter));
}
}
}
@@ -362,8 +383,8 @@ void CompositorFrameReportingController::DidPresentCompositorFrame(
// the original reporter, so that the cloned reporter stays alive until the
// original reporter is terminated, and the cloned reporter's 'partial
// update' flag can be unset if necessary.
- if (reporter->has_partial_update()) {
- auto orig_reporter = reporter->cloned_from();
+ if (reporter->MightHavePartialUpdate()) {
+ auto orig_reporter = reporter->partial_update_decider();
if (orig_reporter)
orig_reporter->AdoptReporter(std::move(reporter));
}
@@ -409,12 +430,27 @@ void CompositorFrameReportingController::RemoveActiveTracker(
void CompositorFrameReportingController::SetThreadAffectsSmoothness(
FrameSequenceMetrics::ThreadType thread_type,
bool affects_smoothness) {
+ auto current_smooth_thread = GetSmoothThread();
+
if (thread_type == FrameSequenceMetrics::ThreadType::kCompositor) {
is_compositor_thread_driving_smoothness_ = affects_smoothness;
} else {
DCHECK_EQ(thread_type, FrameSequenceMetrics::ThreadType::kMain);
is_main_thread_driving_smoothness_ = affects_smoothness;
}
+
+ // keep the history for the last 3 seconds.
+ if (!smooth_thread_history_.empty()) {
+ auto expired_smooth_thread = smooth_thread_history_.lower_bound(
+ Now() - base::TimeDelta::FromSeconds(3))--;
+ smooth_thread_history_.erase(smooth_thread_history_.begin(),
+ expired_smooth_thread);
+ }
+
+ // Only trackes the history if there is a change in smooth_thread_
+ if (current_smooth_thread != GetSmoothThread()) {
+ smooth_thread_history_.insert(std::make_pair(Now(), current_smooth_thread));
+ }
}
void CompositorFrameReportingController::AdvanceReporterStage(
@@ -487,6 +523,37 @@ CompositorFrameReportingController::GetSmoothThread() const {
: SmoothThread::kSmoothNone;
}
+CompositorFrameReporter::SmoothThread
+CompositorFrameReportingController::GetSmoothThreadAtTime(
+ base::TimeTicks timestamp) const {
+ if (smooth_thread_history_.lower_bound(timestamp) ==
+ smooth_thread_history_.end())
+ return GetSmoothThread();
+ return smooth_thread_history_.lower_bound(timestamp)->second;
+}
+
+base::WeakPtr<CompositorFrameReporter>
+CompositorFrameReportingController::HasOutstandingUpdatesFromMain(
+ const viz::BeginFrameId& id) const {
+ // Any unterminated reporter in the 'main frame', or 'commit' stages, then
+ // that indicates some pending updates from the main thread.
+ {
+ const auto& reporter = reporters_[PipelineStage::kBeginMainFrame];
+ if (reporter && reporter->frame_id() < id &&
+ !reporter->did_abort_main_frame()) {
+ return reporter->GetWeakPtr();
+ }
+ }
+ {
+ const auto& reporter = reporters_[PipelineStage::kCommit];
+ if (reporter && reporter->frame_id() < id) {
+ DCHECK(!reporter->did_abort_main_frame());
+ return reporter->GetWeakPtr();
+ }
+ }
+ return {};
+}
+
void CompositorFrameReportingController::CreateReportersForDroppedFrames(
const viz::BeginFrameArgs& old_args,
const viz::BeginFrameArgs& new_args) const {
@@ -512,8 +579,8 @@ void CompositorFrameReportingController::CreateReportersForDroppedFrames(
viz::BeginFrameArgs::NORMAL);
auto reporter = std::make_unique<CompositorFrameReporter>(
active_trackers_, args, latency_ukm_reporter_.get(),
- should_report_metrics_, GetSmoothThread(), layer_tree_host_id_,
- dropped_frame_counter_);
+ should_report_metrics_, GetSmoothThreadAtTime(timestamp),
+ layer_tree_host_id_, dropped_frame_counter_);
reporter->set_tick_clock(tick_clock_);
reporter->StartStage(StageType::kBeginImplFrameToSendBeginMainFrame,
timestamp);
diff --git a/chromium/cc/metrics/compositor_frame_reporting_controller.h b/chromium/cc/metrics/compositor_frame_reporting_controller.h
index 7b62bc3bc67..9054c0a325a 100644
--- a/chromium/cc/metrics/compositor_frame_reporting_controller.h
+++ b/chromium/cc/metrics/compositor_frame_reporting_controller.h
@@ -5,6 +5,7 @@
#ifndef CC_METRICS_COMPOSITOR_FRAME_REPORTING_CONTROLLER_H_
#define CC_METRICS_COMPOSITOR_FRAME_REPORTING_CONTROLLER_H_
+#include <map>
#include <memory>
#include <vector>
@@ -82,6 +83,9 @@ class CC_EXPORT CompositorFrameReportingController {
void SetThreadAffectsSmoothness(FrameSequenceMetrics::ThreadType thread_type,
bool affects_smoothness);
+ bool is_main_thread_driving_smoothness() const {
+ return is_main_thread_driving_smoothness_;
+ }
void set_tick_clock(const base::TickClock* tick_clock) {
DCHECK(tick_clock);
@@ -118,6 +122,14 @@ class CC_EXPORT CompositorFrameReportingController {
std::unique_ptr<CompositorFrameReporter> RestoreReporterAtBeginImpl(
const viz::BeginFrameId& id);
CompositorFrameReporter::SmoothThread GetSmoothThread() const;
+ CompositorFrameReporter::SmoothThread GetSmoothThreadAtTime(
+ base::TimeTicks timestamp) const;
+
+ // Checks whether there are reporters containing updates from the main
+ // thread, and returns a weak-ptr to that reporter (if any). Otherwise returns
+ // null.
+ base::WeakPtr<CompositorFrameReporter> HasOutstandingUpdatesFromMain(
+ const viz::BeginFrameId& id) const;
// If the display-compositor skips over some frames (e.g. when the gpu is
// busy, or the client is non-responsive), then it will not issue any
@@ -129,6 +141,11 @@ class CC_EXPORT CompositorFrameReportingController {
const viz::BeginFrameArgs& old_args,
const viz::BeginFrameArgs& new_args) const;
+ // The arg is a reference to the unique_ptr, because depending on the state
+ // that reporter is in, its ownership might be pass or not.
+ void SetPartialUpdateDeciderWhenWaitingOnMain(
+ std::unique_ptr<CompositorFrameReporter>& reporter);
+
const bool should_report_metrics_;
const int layer_tree_host_id_;
@@ -139,6 +156,10 @@ class CC_EXPORT CompositorFrameReportingController {
bool is_compositor_thread_driving_smoothness_ = false;
bool is_main_thread_driving_smoothness_ = false;
+ // Sorted history of smooththread. Element i indicating the smooththread from
+ // timestamp of element i-1 until timestamp of element i.
+ std::map<base::TimeTicks, CompositorFrameReporter::SmoothThread>
+ smooth_thread_history_;
// The latency reporter passed to each CompositorFrameReporter. Owned here
// because it must be common among all reporters.
diff --git a/chromium/cc/metrics/compositor_frame_reporting_controller_unittest.cc b/chromium/cc/metrics/compositor_frame_reporting_controller_unittest.cc
index c964ecdd8bb..8f13ac70623 100644
--- a/chromium/cc/metrics/compositor_frame_reporting_controller_unittest.cc
+++ b/chromium/cc/metrics/compositor_frame_reporting_controller_unittest.cc
@@ -55,6 +55,39 @@ class TestCompositorFrameReportingController
reporters()[i] = nullptr;
}
}
+
+ size_t GetBlockingReportersCount() {
+ size_t count = 0;
+ const PipelineStage kStages[] = {
+ PipelineStage::kBeginImplFrame,
+ PipelineStage::kBeginMainFrame,
+ PipelineStage::kCommit,
+ PipelineStage::kActivate,
+ };
+ for (auto stage : kStages) {
+ auto& reporter = reporters()[stage];
+ if (reporter && reporter->GetPartialUpdateDependentsCount() > 0) {
+ ++count;
+ }
+ }
+ return count;
+ }
+
+ size_t GetBlockedReportersCount() {
+ size_t count = 0;
+ const PipelineStage kStages[] = {
+ PipelineStage::kBeginImplFrame,
+ PipelineStage::kBeginMainFrame,
+ PipelineStage::kCommit,
+ PipelineStage::kActivate,
+ };
+ for (auto stage : kStages) {
+ auto& reporter = reporters()[stage];
+ if (reporter)
+ count += reporter->GetPartialUpdateDependentsCount();
+ }
+ return count;
+ }
};
class CompositorFrameReportingControllerTest : public testing::Test {
@@ -186,6 +219,39 @@ class CompositorFrameReportingControllerTest : public testing::Test {
return test_tick_clock_.NowTicks();
}
+ std::unique_ptr<EventMetrics> CreateEventMetrics(
+ ui::EventType type,
+ base::Optional<EventMetrics::ScrollUpdateType> scroll_update_type,
+ base::Optional<ui::ScrollInputType> scroll_input_type) {
+ const base::TimeTicks event_time = AdvanceNowByMs(10);
+ AdvanceNowByMs(10);
+ std::unique_ptr<EventMetrics> metrics = EventMetrics::CreateForTesting(
+ type, scroll_update_type, scroll_input_type, event_time,
+ &test_tick_clock_);
+ if (metrics) {
+ AdvanceNowByMs(10);
+ metrics->SetDispatchStageTimestamp(
+ EventMetrics::DispatchStage::kRendererCompositorStarted);
+ AdvanceNowByMs(10);
+ metrics->SetDispatchStageTimestamp(
+ EventMetrics::DispatchStage::kRendererCompositorFinished);
+ }
+ return metrics;
+ }
+
+ std::vector<base::TimeTicks> GetEventTimestamps(
+ const EventMetrics::List& events_metrics) {
+ std::vector<base::TimeTicks> event_times;
+ event_times.reserve(events_metrics.size());
+ std::transform(events_metrics.cbegin(), events_metrics.cend(),
+ std::back_inserter(event_times),
+ [](const auto& event_metrics) {
+ return event_metrics->GetDispatchStageTimestamp(
+ EventMetrics::DispatchStage::kGenerated);
+ });
+ return event_times;
+ }
+
protected:
// This should be defined before |reporting_controller_| so it is created
// before and destroyed after that.
@@ -380,31 +446,6 @@ TEST_F(CompositorFrameReportingControllerTest,
"CompositorLatency.DroppedFrame.EndActivateToSubmitCompositorFrame", 0);
}
-TEST_F(CompositorFrameReportingControllerTest, ImplFrameCausedNoDamage) {
- base::HistogramTester histogram_tester;
-
- SimulateBeginImplFrame();
- reporting_controller_.OnFinishImplFrame(args_.frame_id);
- reporting_controller_.DidNotProduceFrame(args_.frame_id,
- FrameSkippedReason::kNoDamage);
- SimulateBeginImplFrame();
- histogram_tester.ExpectTotalCount(
- "CompositorLatency.DroppedFrame.BeginImplFrameToSendBeginMainFrame", 0);
- histogram_tester.ExpectBucketCount(
- "CompositorLatency.Type",
- CompositorFrameReporter::FrameReportType::kDroppedFrame, 0);
-
- reporting_controller_.OnFinishImplFrame(args_.frame_id);
- reporting_controller_.DidNotProduceFrame(args_.frame_id,
- FrameSkippedReason::kWaitingOnMain);
- SimulateBeginImplFrame();
- histogram_tester.ExpectTotalCount(
- "CompositorLatency.DroppedFrame.BeginImplFrameToSendBeginMainFrame", 1);
- histogram_tester.ExpectBucketCount(
- "CompositorLatency.Type",
- CompositorFrameReporter::FrameReportType::kDroppedFrame, 1);
-}
-
TEST_F(CompositorFrameReportingControllerTest, MainFrameCausedNoDamage) {
base::HistogramTester histogram_tester;
viz::BeginFrameId current_id_1(1, 1);
@@ -1059,19 +1100,16 @@ TEST_F(CompositorFrameReportingControllerTest,
EventLatencyTotalForPresentedFrameReported) {
base::HistogramTester histogram_tester;
- const base::TimeTicks event_time = AdvanceNowByMs(10);
std::unique_ptr<EventMetrics> event_metrics_ptrs[] = {
- EventMetrics::Create(ui::ET_TOUCH_PRESSED, base::nullopt, event_time,
- base::nullopt),
- EventMetrics::Create(ui::ET_TOUCH_MOVED, base::nullopt, event_time,
- base::nullopt),
- EventMetrics::Create(ui::ET_TOUCH_MOVED, base::nullopt, event_time,
- base::nullopt),
+ CreateEventMetrics(ui::ET_TOUCH_PRESSED, base::nullopt, base::nullopt),
+ CreateEventMetrics(ui::ET_TOUCH_MOVED, base::nullopt, base::nullopt),
+ CreateEventMetrics(ui::ET_TOUCH_MOVED, base::nullopt, base::nullopt),
};
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)));
+ std::vector<base::TimeTicks> event_times = GetEventTimestamps(events_metrics);
// Submit a compositor frame and notify CompositorFrameReporter of the events
// affecting the frame.
@@ -1085,131 +1123,39 @@ TEST_F(CompositorFrameReportingControllerTest,
reporting_controller_.DidPresentCompositorFrame(*next_token_, details);
// Verify that EventLatency histograms are recorded.
- const int64_t latency_ms = (presentation_time - event_time).InMicroseconds();
- histogram_tester.ExpectTotalCount("EventLatency.TouchPressed.TotalLatency",
- 1);
- histogram_tester.ExpectTotalCount("EventLatency.TouchMoved.TotalLatency", 2);
- histogram_tester.ExpectTotalCount("EventLatency.TotalLatency", 3);
- histogram_tester.ExpectBucketCount("EventLatency.TouchPressed.TotalLatency",
- latency_ms, 1);
- histogram_tester.ExpectBucketCount("EventLatency.TouchMoved.TotalLatency",
- latency_ms, 2);
- histogram_tester.ExpectBucketCount("EventLatency.TotalLatency", latency_ms,
- 3);
-}
-
-// Tests that EventLatency breakdown histograms are reported properly when a
-// frame is presented to the user.
-TEST_F(CompositorFrameReportingControllerTest,
- EventLatencyBreakdownsForPresentedFrameReported) {
- base::HistogramTester histogram_tester;
-
- const base::TimeTicks event_time = AdvanceNowByMs(10);
- std::unique_ptr<EventMetrics> event_metrics_ptrs[] = {
- EventMetrics::Create(ui::ET_TOUCH_PRESSED, base::nullopt, event_time,
- base::nullopt),
+ struct {
+ const char* name;
+ const base::HistogramBase::Count count;
+ } expected_counts[] = {
+ {"EventLatency.TouchPressed.TotalLatency", 1},
+ {"EventLatency.TouchMoved.TotalLatency", 2},
+ {"EventLatency.TotalLatency", 3},
};
- 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)));
-
- // Do a commit with a breakdown of blink stages.
- std::unique_ptr<BeginMainFrameMetrics> blink_breakdown =
- BuildBlinkBreakdown();
- // Make a copy of the breakdown to use in verifying expectations in the end.
- BeginMainFrameMetrics blink_breakdown_copy = *blink_breakdown;
- SimulateCommit(std::move(blink_breakdown));
-
- // Submit a compositor frame and notify CompositorFrameReporter of the events
- // affecting the frame.
- ++next_token_;
- SimulateSubmitCompositorFrame(*next_token_, {std::move(events_metrics), {}});
-
- // Present the submitted compositor frame to the user.
- AdvanceNowByMs(10);
- viz::FrameTimingDetails viz_breakdown = BuildVizBreakdown();
- reporting_controller_.DidPresentCompositorFrame(*next_token_, viz_breakdown);
+ for (const auto& expected_count : expected_counts) {
+ histogram_tester.ExpectTotalCount(expected_count.name,
+ expected_count.count);
+ }
- // Verify that EventLatency histograms are recorded.
struct {
const char* name;
- const base::TimeDelta latency;
+ const base::HistogramBase::Sample latency_ms;
} expected_latencies[] = {
- {"EventLatency.TouchPressed.BrowserToRendererCompositor",
- begin_impl_time_ - event_time},
- {"EventLatency.TouchPressed.BeginImplFrameToSendBeginMainFrame",
- begin_main_time_ - begin_impl_time_},
- {"EventLatency.TouchPressed.SendBeginMainFrameToCommit",
- begin_commit_time_ - begin_main_time_},
- {"EventLatency.TouchPressed.SendBeginMainFrameToCommit.HandleInputEvents",
- blink_breakdown_copy.handle_input_events},
- {"EventLatency.TouchPressed.SendBeginMainFrameToCommit.Animate",
- blink_breakdown_copy.animate},
- {"EventLatency.TouchPressed.SendBeginMainFrameToCommit.StyleUpdate",
- blink_breakdown_copy.style_update},
- {"EventLatency.TouchPressed.SendBeginMainFrameToCommit.LayoutUpdate",
- blink_breakdown_copy.layout_update},
- {"EventLatency.TouchPressed.SendBeginMainFrameToCommit.CompositingInputs",
- blink_breakdown_copy.compositing_inputs},
- {"EventLatency.TouchPressed.SendBeginMainFrameToCommit.Prepaint",
- blink_breakdown_copy.prepaint},
- {"EventLatency.TouchPressed.SendBeginMainFrameToCommit."
- "CompositingAssignments",
- blink_breakdown_copy.compositing_assignments},
- {"EventLatency.TouchPressed.SendBeginMainFrameToCommit.Paint",
- blink_breakdown_copy.paint},
- {"EventLatency.TouchPressed.SendBeginMainFrameToCommit.CompositeCommit",
- blink_breakdown_copy.composite_commit},
- {"EventLatency.TouchPressed.SendBeginMainFrameToCommit.UpdateLayers",
- blink_breakdown_copy.update_layers},
- {"EventLatency.TouchPressed.SendBeginMainFrameToCommit."
- "BeginMainSentToStarted",
- begin_main_start_time_ - begin_main_time_},
- {"EventLatency.TouchPressed.Commit",
- end_commit_time_ - begin_commit_time_},
- {"EventLatency.TouchPressed.EndCommitToActivation",
- begin_activation_time_ - end_commit_time_},
- {"EventLatency.TouchPressed.Activation",
- end_activation_time_ - begin_activation_time_},
- {"EventLatency.TouchPressed.EndActivateToSubmitCompositorFrame",
- submit_time_ - end_activation_time_},
- {"EventLatency.TouchPressed."
- "SubmitCompositorFrameToPresentationCompositorFrame",
- viz_breakdown.presentation_feedback.timestamp - submit_time_},
- {"EventLatency.TouchPressed."
- "SubmitCompositorFrameToPresentationCompositorFrame."
- "SubmitToReceiveCompositorFrame",
- viz_breakdown.received_compositor_frame_timestamp - submit_time_},
- {"EventLatency.TouchPressed."
- "SubmitCompositorFrameToPresentationCompositorFrame."
- "ReceivedCompositorFrameToStartDraw",
- viz_breakdown.draw_start_timestamp -
- viz_breakdown.received_compositor_frame_timestamp},
- {"EventLatency.TouchPressed."
- "SubmitCompositorFrameToPresentationCompositorFrame."
- "StartDrawToSwapStart",
- viz_breakdown.swap_timings.swap_start -
- viz_breakdown.draw_start_timestamp},
- {"EventLatency.TouchPressed."
- "SubmitCompositorFrameToPresentationCompositorFrame.SwapStartToSwapEnd",
- viz_breakdown.swap_timings.swap_end -
- viz_breakdown.swap_timings.swap_start},
- {"EventLatency.TouchPressed."
- "SubmitCompositorFrameToPresentationCompositorFrame."
- "SwapEndToPresentationCompositorFrame",
- viz_breakdown.presentation_feedback.timestamp -
- viz_breakdown.swap_timings.swap_end},
{"EventLatency.TouchPressed.TotalLatency",
- viz_breakdown.presentation_feedback.timestamp - event_time},
+ (presentation_time - event_times[0]).InMicroseconds()},
+ {"EventLatency.TouchMoved.TotalLatency",
+ (presentation_time - event_times[1]).InMicroseconds()},
+ {"EventLatency.TouchMoved.TotalLatency",
+ (presentation_time - event_times[2]).InMicroseconds()},
+ {"EventLatency.TotalLatency",
+ (presentation_time - event_times[0]).InMicroseconds()},
{"EventLatency.TotalLatency",
- viz_breakdown.presentation_feedback.timestamp - event_time},
+ (presentation_time - event_times[1]).InMicroseconds()},
+ {"EventLatency.TotalLatency",
+ (presentation_time - event_times[2]).InMicroseconds()},
};
-
for (const auto& expected_latency : expected_latencies) {
- histogram_tester.ExpectTotalCount(expected_latency.name, 1);
- histogram_tester.ExpectBucketCount(
- expected_latency.name, expected_latency.latency.InMicroseconds(), 1);
+ histogram_tester.ExpectBucketCount(expected_latency.name,
+ expected_latency.latency_ms, 1);
}
}
@@ -1219,21 +1165,21 @@ TEST_F(CompositorFrameReportingControllerTest,
EventLatencyScrollTotalForPresentedFrameReported) {
base::HistogramTester histogram_tester;
- const base::TimeTicks event_time = AdvanceNowByMs(10);
std::unique_ptr<EventMetrics> event_metrics_ptrs[] = {
- EventMetrics::Create(ui::ET_GESTURE_SCROLL_BEGIN, base::nullopt,
- event_time, ui::ScrollInputType::kWheel),
- EventMetrics::Create(ui::ET_GESTURE_SCROLL_UPDATE,
- EventMetrics::ScrollUpdateType::kStarted, event_time,
- ui::ScrollInputType::kWheel),
- EventMetrics::Create(ui::ET_GESTURE_SCROLL_UPDATE,
- EventMetrics::ScrollUpdateType::kContinued,
- event_time, ui::ScrollInputType::kWheel),
+ CreateEventMetrics(ui::ET_GESTURE_SCROLL_BEGIN, base::nullopt,
+ ui::ScrollInputType::kWheel),
+ CreateEventMetrics(ui::ET_GESTURE_SCROLL_UPDATE,
+ EventMetrics::ScrollUpdateType::kStarted,
+ ui::ScrollInputType::kWheel),
+ CreateEventMetrics(ui::ET_GESTURE_SCROLL_UPDATE,
+ EventMetrics::ScrollUpdateType::kContinued,
+ ui::ScrollInputType::kWheel),
};
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)));
+ std::vector<base::TimeTicks> event_times = GetEventTimestamps(events_metrics);
// Submit a compositor frame and notify CompositorFrameReporter of the events
// affecting the frame.
@@ -1250,31 +1196,48 @@ TEST_F(CompositorFrameReportingControllerTest,
reporting_controller_.DidPresentCompositorFrame(*next_token_, details);
// Verify that EventLatency histograms are recorded.
- const int64_t total_latency_ms =
- (details.presentation_feedback.timestamp - event_time).InMicroseconds();
- const int64_t swap_begin_latency_ms =
- (details.swap_timings.swap_start - event_time).InMicroseconds();
struct {
const char* name;
- const int64_t latency_ms;
- } expected_metrics[] = {
- {"EventLatency.GestureScrollBegin.Wheel.TotalLatency", total_latency_ms},
+ const base::HistogramBase::Count count;
+ } expected_counts[] = {
+ {"EventLatency.GestureScrollBegin.Wheel.TotalLatency", 1},
+ {"EventLatency.GestureScrollBegin.Wheel.TotalLatencyToSwapBegin", 1},
+ {"EventLatency.FirstGestureScrollUpdate.Wheel.TotalLatency", 1},
+ {"EventLatency.FirstGestureScrollUpdate.Wheel.TotalLatencyToSwapBegin",
+ 1},
+ {"EventLatency.GestureScrollUpdate.Wheel.TotalLatency", 1},
+ {"EventLatency.GestureScrollUpdate.Wheel.TotalLatencyToSwapBegin", 1},
+ {"EventLatency.TotalLatency", 3},
+ };
+ for (const auto& expected_count : expected_counts) {
+ histogram_tester.ExpectTotalCount(expected_count.name,
+ expected_count.count);
+ }
+
+ const base::TimeTicks presentation_time =
+ details.presentation_feedback.timestamp;
+ const base::TimeTicks swap_begin_time = details.swap_timings.swap_start;
+ struct {
+ const char* name;
+ const base::HistogramBase::Sample latency_ms;
+ } expected_latencies[] = {
+ {"EventLatency.GestureScrollBegin.Wheel.TotalLatency",
+ (presentation_time - event_times[0]).InMicroseconds()},
{"EventLatency.GestureScrollBegin.Wheel.TotalLatencyToSwapBegin",
- swap_begin_latency_ms},
+ (swap_begin_time - event_times[0]).InMicroseconds()},
{"EventLatency.FirstGestureScrollUpdate.Wheel.TotalLatency",
- total_latency_ms},
+ (presentation_time - event_times[1]).InMicroseconds()},
{"EventLatency.FirstGestureScrollUpdate.Wheel.TotalLatencyToSwapBegin",
- swap_begin_latency_ms},
- {"EventLatency.GestureScrollUpdate.Wheel.TotalLatency", total_latency_ms},
+ (swap_begin_time - event_times[1]).InMicroseconds()},
+ {"EventLatency.GestureScrollUpdate.Wheel.TotalLatency",
+ (presentation_time - event_times[2]).InMicroseconds()},
{"EventLatency.GestureScrollUpdate.Wheel.TotalLatencyToSwapBegin",
- swap_begin_latency_ms},
+ (swap_begin_time - event_times[2]).InMicroseconds()},
};
- for (const auto& expected_metric : expected_metrics) {
- histogram_tester.ExpectTotalCount(expected_metric.name, 1);
- histogram_tester.ExpectBucketCount(expected_metric.name,
- expected_metric.latency_ms, 1);
+ for (const auto& expected_latency : expected_latencies) {
+ histogram_tester.ExpectBucketCount(expected_latency.name,
+ expected_latency.latency_ms, 1);
}
- histogram_tester.ExpectTotalCount("EventLatency.TotalLatency", 3);
}
// Tests that EventLatency histograms are not reported when the frame is dropped
@@ -1283,14 +1246,10 @@ TEST_F(CompositorFrameReportingControllerTest,
EventLatencyForDidNotPresentFrameNotReported) {
base::HistogramTester histogram_tester;
- const base::TimeTicks event_time = AdvanceNowByMs(10);
std::unique_ptr<EventMetrics> event_metrics_ptrs[] = {
- EventMetrics::Create(ui::ET_TOUCH_PRESSED, base::nullopt, event_time,
- base::nullopt),
- EventMetrics::Create(ui::ET_TOUCH_MOVED, base::nullopt, event_time,
- base::nullopt),
- EventMetrics::Create(ui::ET_TOUCH_MOVED, base::nullopt, event_time,
- base::nullopt),
+ CreateEventMetrics(ui::ET_TOUCH_PRESSED, base::nullopt, base::nullopt),
+ CreateEventMetrics(ui::ET_TOUCH_MOVED, base::nullopt, base::nullopt),
+ CreateEventMetrics(ui::ET_TOUCH_MOVED, base::nullopt, base::nullopt),
};
EXPECT_THAT(event_metrics_ptrs, Each(NotNull()));
EventMetrics::List events_metrics(
@@ -1319,6 +1278,10 @@ TEST_F(CompositorFrameReportingControllerTest,
TEST_F(CompositorFrameReportingControllerTest,
NewMainUpdateIsNotPartialUpdate) {
+ // Start a frame with main-thread update. Submit the frame (and present)
+ // before the main-thread responds. This creates two reporters: R1C and R1M
+ // (R1C for the submitted frame with updates from compositor-thread, and R1M
+ // for the pending main-thread frame).
SimulateBeginMainFrame();
reporting_controller_.OnFinishImplFrame(current_id_);
reporting_controller_.DidSubmitCompositorFrame(1u, current_id_, {}, {});
@@ -1326,6 +1289,7 @@ TEST_F(CompositorFrameReportingControllerTest,
details.presentation_feedback.timestamp = AdvanceNowByMs(10);
reporting_controller_.DidPresentCompositorFrame(1u, details);
+ // The main-thread responds now, triggering a commit and activation.
reporting_controller_.WillCommit();
reporting_controller_.DidCommit();
reporting_controller_.WillActivate();
@@ -1333,6 +1297,9 @@ TEST_F(CompositorFrameReportingControllerTest,
const auto previous_id = current_id_;
+ // Start a new frame with main-thread update. Submit the frame (and present)
+ // before the main-thread responds. This also again creates two reporters: R2C
+ // and R2M.
SimulateBeginMainFrame();
reporting_controller_.OnFinishImplFrame(current_id_);
reporting_controller_.DidSubmitCompositorFrame(1u, current_id_, previous_id,
@@ -1340,8 +1307,13 @@ TEST_F(CompositorFrameReportingControllerTest,
details.presentation_feedback.timestamp = AdvanceNowByMs(10);
reporting_controller_.DidPresentCompositorFrame(1u, details);
- EXPECT_EQ(3u, dropped_counter.total_frames());
+ // In total, two frames have been completed: R1C, and R1M.
+ // R2C has been presented, but it is blocked on R2M to know whether R2C
+ // contains partial update, or complete updates. So it is kept alive.
+ EXPECT_EQ(2u, dropped_counter.total_frames());
EXPECT_EQ(1u, dropped_counter.total_main_dropped());
+ EXPECT_EQ(1u, reporting_controller_.GetBlockingReportersCount());
+ EXPECT_EQ(1u, reporting_controller_.GetBlockedReportersCount());
reporting_controller_.ResetReporters();
reporting_controller_.SetDroppedFrameCounter(nullptr);
@@ -1409,5 +1381,115 @@ TEST_F(CompositorFrameReportingControllerTest,
EXPECT_EQ(kSkipFramesActual, dropped_counter.total_compositor_dropped());
}
+TEST_F(CompositorFrameReportingControllerTest,
+ CompositorFrameBlockedOnMainFrameWithNoDamage) {
+ viz::BeginFrameId current_id_1(1, 1);
+ viz::BeginFrameArgs args_1 = SimulateBeginFrameArgs(current_id_1);
+
+ viz::BeginFrameId current_id_2(1, 2);
+ viz::BeginFrameArgs args_2 = SimulateBeginFrameArgs(current_id_2);
+
+ viz::BeginFrameId current_id_3(1, 3);
+ viz::BeginFrameArgs args_3 = SimulateBeginFrameArgs(current_id_3);
+
+ viz::BeginFrameId current_id_4(1, 4);
+ viz::BeginFrameArgs args_4 = SimulateBeginFrameArgs(current_id_4);
+
+ reporting_controller_.WillBeginImplFrame(args_1);
+ reporting_controller_.WillBeginMainFrame(args_1);
+ reporting_controller_.OnFinishImplFrame(current_id_1);
+ EXPECT_EQ(0u, dropped_counter.total_compositor_dropped());
+ reporting_controller_.DidNotProduceFrame(args_1.frame_id,
+ FrameSkippedReason::kWaitingOnMain);
+
+ reporting_controller_.WillBeginImplFrame(args_2);
+ reporting_controller_.OnFinishImplFrame(args_2.frame_id);
+ reporting_controller_.DidNotProduceFrame(args_2.frame_id,
+ FrameSkippedReason::kWaitingOnMain);
+
+ reporting_controller_.WillBeginImplFrame(args_3);
+ reporting_controller_.OnFinishImplFrame(args_3.frame_id);
+ reporting_controller_.DidNotProduceFrame(args_3.frame_id,
+ FrameSkippedReason::kWaitingOnMain);
+
+ EXPECT_EQ(1u, reporting_controller_.GetBlockingReportersCount());
+ EXPECT_EQ(3u, reporting_controller_.GetBlockedReportersCount());
+
+ // All frames are waiting for the main frame
+ EXPECT_EQ(0u, dropped_counter.total_main_dropped());
+ EXPECT_EQ(0u, dropped_counter.total_compositor_dropped());
+ EXPECT_EQ(0u, dropped_counter.total_frames());
+
+ reporting_controller_.BeginMainFrameAborted(args_1.frame_id);
+ reporting_controller_.DidNotProduceFrame(args_1.frame_id,
+ FrameSkippedReason::kNoDamage);
+ EXPECT_EQ(0u, dropped_counter.total_compositor_dropped());
+
+ // New reporters replace older reporters
+ reporting_controller_.WillBeginImplFrame(args_4);
+ reporting_controller_.WillBeginMainFrame(args_4);
+
+ EXPECT_EQ(4u, dropped_counter.total_frames());
+ EXPECT_EQ(0u, dropped_counter.total_main_dropped());
+ EXPECT_EQ(0u, dropped_counter.total_compositor_dropped());
+}
+
+TEST_F(CompositorFrameReportingControllerTest,
+ SkippedFramesFromDisplayCompositorHaveSmoothThread) {
+ auto thread_type_compositor = FrameSequenceMetrics::ThreadType::kCompositor;
+ reporting_controller_.SetThreadAffectsSmoothness(thread_type_compositor,
+ true);
+ dropped_counter.OnFcpReceived();
+
+ // Submit and present two compositor frames.
+ SimulatePresentCompositorFrame();
+ EXPECT_EQ(1u, dropped_counter.total_frames());
+ EXPECT_EQ(0u, dropped_counter.total_main_dropped());
+ EXPECT_EQ(0u, dropped_counter.total_compositor_dropped());
+
+ SimulatePresentCompositorFrame();
+ EXPECT_EQ(2u, dropped_counter.total_frames());
+ EXPECT_EQ(0u, dropped_counter.total_main_dropped());
+ EXPECT_EQ(0u, dropped_counter.total_compositor_dropped());
+
+ // Now skip over a few frames, and submit + present another frame.
+ const uint32_t kSkipFrames_1 = 5;
+ for (uint32_t i = 0; i < kSkipFrames_1; ++i)
+ IncrementCurrentId();
+ SimulatePresentCompositorFrame();
+ EXPECT_EQ(3u + kSkipFrames_1, dropped_counter.total_frames());
+ EXPECT_EQ(0u, dropped_counter.total_main_dropped());
+ EXPECT_EQ(kSkipFrames_1, dropped_counter.total_compositor_dropped());
+ EXPECT_EQ(kSkipFrames_1, dropped_counter.total_smoothness_dropped());
+
+ // Now skip over a few frames which are not affecting smoothness.
+ reporting_controller_.SetThreadAffectsSmoothness(thread_type_compositor,
+ false);
+ const uint32_t kSkipFrames_2 = 7;
+ for (uint32_t i = 0; i < kSkipFrames_2; ++i)
+ IncrementCurrentId();
+ SimulatePresentCompositorFrame(); // Present another frame.
+ EXPECT_EQ(4u + kSkipFrames_1 + kSkipFrames_2, dropped_counter.total_frames());
+ EXPECT_EQ(0u, dropped_counter.total_main_dropped());
+ EXPECT_EQ(kSkipFrames_1 + kSkipFrames_2,
+ dropped_counter.total_compositor_dropped());
+ EXPECT_EQ(kSkipFrames_1, dropped_counter.total_smoothness_dropped());
+
+ // Now skip over a few frames more frames which are affecting smoothness.
+ reporting_controller_.SetThreadAffectsSmoothness(thread_type_compositor,
+ true);
+ const uint32_t kSkipFrames_3 = 10;
+ for (uint32_t i = 0; i < kSkipFrames_3; ++i)
+ IncrementCurrentId();
+ SimulatePresentCompositorFrame(); // Present another frame.
+ EXPECT_EQ(5u + kSkipFrames_1 + kSkipFrames_2 + kSkipFrames_3,
+ dropped_counter.total_frames());
+ EXPECT_EQ(0u, dropped_counter.total_main_dropped());
+ EXPECT_EQ(kSkipFrames_1 + kSkipFrames_2 + kSkipFrames_3,
+ dropped_counter.total_compositor_dropped());
+ EXPECT_EQ(kSkipFrames_1 + kSkipFrames_3,
+ dropped_counter.total_smoothness_dropped());
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/metrics/compositor_timing_history.cc b/chromium/cc/metrics/compositor_timing_history.cc
index 9a427c71a1e..9dd8e1aa0a4 100644
--- a/chromium/cc/metrics/compositor_timing_history.cc
+++ b/chromium/cc/metrics/compositor_timing_history.cc
@@ -34,9 +34,7 @@ class CompositorTimingHistory::UMAReporter {
virtual void AddInvalidationToReadyToActivateDuration(
base::TimeDelta duration,
TreePriority priority) = 0;
- virtual void AddPrepareTilesDuration(base::TimeDelta duration) = 0;
virtual void AddDrawDuration(base::TimeDelta duration) = 0;
- virtual void AddSubmitToAckLatency(base::TimeDelta duration) = 0;
// crbug.com/758439: the following functions are used to report timing in
// certain conditions targeting blink / compositor animations.
@@ -323,20 +321,10 @@ class RendererUMAReporter : public CompositorTimingHistory::UMAReporter {
priority);
}
- void AddPrepareTilesDuration(base::TimeDelta duration) override {
- UMA_HISTOGRAM_CUSTOM_TIMES_DURATION(
- "Scheduling.Renderer.PrepareTilesDuration", duration);
- }
-
void AddDrawDuration(base::TimeDelta duration) override {
UMA_HISTOGRAM_CUSTOM_TIMES_DURATION("Scheduling.Renderer.DrawDuration",
duration);
}
-
- void AddSubmitToAckLatency(base::TimeDelta duration) override {
- UMA_HISTOGRAM_CUSTOM_TIMES_DURATION("Scheduling.Renderer.SwapToAckLatency",
- duration);
- }
};
class BrowserUMAReporter : public CompositorTimingHistory::UMAReporter {
@@ -370,20 +358,10 @@ class BrowserUMAReporter : public CompositorTimingHistory::UMAReporter {
priority);
}
- void AddPrepareTilesDuration(base::TimeDelta duration) override {
- UMA_HISTOGRAM_CUSTOM_TIMES_DURATION(
- "Scheduling.Browser.PrepareTilesDuration", duration);
- }
-
void AddDrawDuration(base::TimeDelta duration) override {
UMA_HISTOGRAM_CUSTOM_TIMES_DURATION("Scheduling.Browser.DrawDuration",
duration);
}
-
- void AddSubmitToAckLatency(base::TimeDelta duration) override {
- UMA_HISTOGRAM_CUSTOM_TIMES_DURATION("Scheduling.Browser.SwapToAckLatency",
- duration);
- }
};
class NullUMAReporter : public CompositorTimingHistory::UMAReporter {
@@ -398,9 +376,7 @@ class NullUMAReporter : public CompositorTimingHistory::UMAReporter {
void AddInvalidationToReadyToActivateDuration(
base::TimeDelta duration,
TreePriority priority) override {}
- void AddPrepareTilesDuration(base::TimeDelta duration) override {}
void AddDrawDuration(base::TimeDelta duration) override {}
- void AddSubmitToAckLatency(base::TimeDelta duration) override {}
};
} // namespace
@@ -535,12 +511,6 @@ base::TimeDelta CompositorTimingHistory::DrawDurationEstimate() const {
return draw_duration_history_.Percentile(kDrawEstimationPercentile);
}
-void CompositorTimingHistory::DidCreateAndInitializeLayerTreeFrameSink() {
- // After we get a new output surface, we won't get a spurious
- // CompositorFrameAck from the old output surface.
- submit_start_time_ = base::TimeTicks();
-}
-
void CompositorTimingHistory::WillBeginImplFrame(
const viz::BeginFrameArgs& args,
base::TimeTicks now) {
@@ -690,7 +660,6 @@ void CompositorTimingHistory::DidPrepareTiles() {
DCHECK_NE(base::TimeTicks(), prepare_tiles_start_time_);
base::TimeDelta prepare_tiles_duration = Now() - prepare_tiles_start_time_;
- uma_reporter_->AddPrepareTilesDuration(prepare_tiles_duration);
if (enabled_)
prepare_tiles_duration_history_.InsertSample(prepare_tiles_duration);
@@ -808,11 +777,9 @@ void CompositorTimingHistory::DidSubmitCompositorFrame(
const viz::BeginFrameId& current_frame_id,
const viz::BeginFrameId& last_activated_frame_id,
EventMetricsSet events_metrics) {
- DCHECK_EQ(base::TimeTicks(), submit_start_time_);
compositor_frame_reporting_controller_->DidSubmitCompositorFrame(
frame_token, current_frame_id, last_activated_frame_id,
std::move(events_metrics));
- submit_start_time_ = Now();
}
void CompositorTimingHistory::DidNotProduceFrame(
@@ -821,13 +788,6 @@ void CompositorTimingHistory::DidNotProduceFrame(
compositor_frame_reporting_controller_->DidNotProduceFrame(id, skip_reason);
}
-void CompositorTimingHistory::DidReceiveCompositorFrameAck() {
- DCHECK_NE(base::TimeTicks(), submit_start_time_);
- base::TimeDelta submit_to_ack_duration = Now() - submit_start_time_;
- uma_reporter_->AddSubmitToAckLatency(submit_to_ack_duration);
- submit_start_time_ = base::TimeTicks();
-}
-
void CompositorTimingHistory::DidPresentCompositorFrame(
uint32_t frame_token,
const viz::FrameTimingDetails& details) {
diff --git a/chromium/cc/metrics/compositor_timing_history.h b/chromium/cc/metrics/compositor_timing_history.h
index 93a06913241..15b1ff0050f 100644
--- a/chromium/cc/metrics/compositor_timing_history.h
+++ b/chromium/cc/metrics/compositor_timing_history.h
@@ -70,7 +70,6 @@ class CC_EXPORT CompositorTimingHistory {
// State that affects when events should be expected/recorded/reported.
void SetRecordingEnabled(bool enabled);
- void DidCreateAndInitializeLayerTreeFrameSink();
// Events to be timed.
void WillBeginImplFrame(const viz::BeginFrameArgs& args,
@@ -99,7 +98,6 @@ class CC_EXPORT CompositorTimingHistory {
EventMetricsSet events_metrics);
void DidNotProduceFrame(const viz::BeginFrameId& id,
FrameSkippedReason skip_reason);
- void DidReceiveCompositorFrameAck();
void DidPresentCompositorFrame(uint32_t frame_token,
const viz::FrameTimingDetails& details);
void WillInvalidateOnImplSide();
@@ -157,7 +155,6 @@ class CC_EXPORT CompositorTimingHistory {
base::TimeTicks prepare_tiles_start_time_;
base::TimeTicks activate_start_time_;
base::TimeTicks draw_start_time_;
- base::TimeTicks submit_start_time_;
bool pending_tree_is_impl_side_;
diff --git a/chromium/cc/metrics/dropped_frame_counter.cc b/chromium/cc/metrics/dropped_frame_counter.cc
index bc9e116bcf8..357acc6e903 100644
--- a/chromium/cc/metrics/dropped_frame_counter.cc
+++ b/chromium/cc/metrics/dropped_frame_counter.cc
@@ -4,7 +4,13 @@
#include "cc/metrics/dropped_frame_counter.h"
+#include <algorithm>
+#include <cmath>
+
#include "base/bind.h"
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
#include "base/trace_event/trace_event.h"
#include "cc/metrics/frame_sorter.h"
#include "cc/metrics/total_frame_counter.h"
@@ -12,6 +18,53 @@
namespace cc {
+using SlidingWindowHistogram = DroppedFrameCounter::SlidingWindowHistogram;
+
+void SlidingWindowHistogram::AddPercentDroppedFrame(
+ double percent_dropped_frame,
+ size_t count) {
+ DCHECK_GE(percent_dropped_frame, 0.0);
+ DCHECK_GE(100.0, percent_dropped_frame);
+ histogram_bins_[static_cast<int>(std::round(percent_dropped_frame))] += count;
+ total_count_ += count;
+}
+
+uint32_t SlidingWindowHistogram::GetPercentDroppedFramePercentile(
+ double percentile) const {
+ if (total_count_ == 0)
+ return 0;
+ DCHECK_GE(percentile, 0.0);
+ DCHECK_GE(1.0, percentile);
+ int current_index = 100; // Last bin in historgam
+ uint32_t skipped_counter = histogram_bins_[current_index]; // Last bin values
+ double samples_to_skip = ((1 - percentile) * total_count_);
+ // We expect this method to calculate higher end percentiles such 95 and as a
+ // result we count from the last bin to find the correct bin.
+ while (skipped_counter < samples_to_skip && current_index > 0) {
+ current_index--;
+ skipped_counter += histogram_bins_[current_index];
+ }
+ return current_index;
+}
+
+void SlidingWindowHistogram::Clear() {
+ std::fill(std::begin(histogram_bins_), std::end(histogram_bins_), 0);
+ total_count_ = 0;
+}
+
+std::ostream& SlidingWindowHistogram::Dump(std::ostream& stream) const {
+ for (size_t i = 0; i < base::size(histogram_bins_); ++i) {
+ stream << i << ": " << histogram_bins_[i] << std::endl;
+ }
+ return stream << "Total: " << total_count_;
+}
+
+std::ostream& operator<<(
+ std::ostream& stream,
+ const DroppedFrameCounter::SlidingWindowHistogram& histogram) {
+ return histogram.Dump(stream);
+}
+
DroppedFrameCounter::DroppedFrameCounter()
: frame_sorter_(base::BindRepeating(&DroppedFrameCounter::NotifyFrameResult,
base::Unretained(this))) {}
@@ -44,22 +97,100 @@ void DroppedFrameCounter::AddDroppedFrame() {
++total_dropped_;
}
-void DroppedFrameCounter::ResetFrameSorter() {
+void DroppedFrameCounter::ResetPendingFrames(base::TimeTicks timestamp) {
+ // Before resetting the pending frames, update the measurements for the
+ // sliding windows.
+ if (!latest_sliding_window_start_.is_null()) {
+ const auto report_until = timestamp - kSlidingWindowInterval;
+ // Report the sliding window metrics for frames that have already been
+ // completed (and some of which may have been dropped).
+ while (!sliding_window_.empty()) {
+ const auto& args = sliding_window_.front().first;
+ latest_sliding_window_start_ = args.frame_time;
+ latest_sliding_window_interval_ = args.interval;
+ bool was_dropped = sliding_window_.front().second;
+ if (was_dropped) {
+ DCHECK_GT(dropped_frame_count_in_window_, 0u);
+ --dropped_frame_count_in_window_;
+ }
+ sliding_window_.pop();
+ if (latest_sliding_window_start_ > report_until)
+ break;
+ double percent_dropped_frame = std::min(
+ (dropped_frame_count_in_window_ * 100.0) / total_frames_in_window_,
+ 100.0);
+ sliding_window_histogram_.AddPercentDroppedFrame(percent_dropped_frame,
+ /*count=*/1);
+ }
+ if (sliding_window_.empty()) {
+ DCHECK_EQ(dropped_frame_count_in_window_, 0u);
+ }
+
+ // Report no dropped frames for the sliding windows spanning the rest of the
+ // time.
+ if (latest_sliding_window_start_ < report_until) {
+ const auto difference = report_until - latest_sliding_window_start_;
+ const size_t count =
+ std::ceil(difference / latest_sliding_window_interval_);
+ if (count > 0)
+ sliding_window_histogram_.AddPercentDroppedFrame(0., count);
+ }
+ }
+
+ dropped_frame_count_in_window_ = 0;
+ sliding_window_ = {};
+ latest_sliding_window_start_ = {};
+ latest_sliding_window_interval_ = {};
frame_sorter_.Reset();
}
-void DroppedFrameCounter::OnBeginFrame(const viz::BeginFrameArgs& args) {
- if (fcp_received_)
+void DroppedFrameCounter::OnBeginFrame(const viz::BeginFrameArgs& args,
+ bool is_scroll_active) {
+ // Remember when scrolling starts/ends. Do this even if fcp has not happened
+ // yet.
+ if (!is_scroll_active) {
+ scroll_start_.reset();
+ } else if (!scroll_start_.has_value()) {
+ ScrollStartInfo info = {args.frame_time, args.frame_id};
+ scroll_start_ = info;
+ }
+
+ if (fcp_received_) {
frame_sorter_.AddNewFrame(args);
+ if (is_scroll_active) {
+ DCHECK(scroll_start_.has_value());
+ scroll_start_per_frame_[args.frame_id] = *scroll_start_;
+ }
+ }
}
void DroppedFrameCounter::OnEndFrame(const viz::BeginFrameArgs& args,
bool is_dropped) {
+ if (!args.interval.is_zero())
+ total_frames_in_window_ = kSlidingWindowInterval / args.interval;
+
if (is_dropped) {
if (fcp_received_)
++total_smoothness_dropped_;
ReportFrames();
}
+ auto iter = scroll_start_per_frame_.find(args.frame_id);
+ if (iter != scroll_start_per_frame_.end()) {
+ ScrollStartInfo& scroll_start = iter->second;
+ if (args.frame_id.source_id == scroll_start.frame_id.source_id) {
+ UMA_HISTOGRAM_CUSTOM_TIMES(
+ "Graphics.Smoothness.Diagnostic.DroppedFrameAfterScrollStart.Time",
+ (args.frame_time - scroll_start.timestamp),
+ base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromSeconds(4),
+ 50);
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ "Graphics.Smoothness.Diagnostic.DroppedFrameAfterScrollStart.Frames",
+ (args.frame_id.sequence_number -
+ scroll_start.frame_id.sequence_number),
+ 1, 250, 50);
+ }
+ scroll_start_per_frame_.erase(iter);
+ }
if (fcp_received_)
frame_sorter_.AddFrameResult(args, is_dropped);
@@ -70,20 +201,52 @@ void DroppedFrameCounter::ReportFrames() {
total_counter_->ComputeTotalVisibleFrames(base::TimeTicks::Now());
TRACE_EVENT2("cc,benchmark", "SmoothnessDroppedFrame", "total", total_frames,
"smoothness", total_smoothness_dropped_);
+ UMA_HISTOGRAM_PERCENTAGE(
+ "Graphics.Smoothness.MaxPercentDroppedFrames_1sWindow",
+ sliding_window_max_percent_dropped_);
+
+ uint32_t sliding_window_95pct_percent_dropped =
+ SlidingWindow95PercentilePercentDropped();
+ UMA_HISTOGRAM_PERCENTAGE(
+ "Graphics.Smoothness.95pctPercentDroppedFrames_1sWindow",
+ sliding_window_95pct_percent_dropped);
+
+ DCHECK_LE(
+ sliding_window_95pct_percent_dropped,
+ static_cast<uint32_t>(std::round(sliding_window_max_percent_dropped_)));
+
+ // Emit trace event with most recent smoothness calculation. This matches
+ // the smoothness metrics displayed on HeadsUpDisplay.
+ TRACE_EVENT2("cc,benchmark", "SmoothnessDroppedFrame::MostRecentCalculation",
+ "worst_smoothness", sliding_window_max_percent_dropped_,
+ "95_percentile_smoothness",
+ sliding_window_95pct_percent_dropped);
if (ukm_smoothness_data_ && total_frames > 0) {
UkmSmoothnessData smoothness_data;
smoothness_data.avg_smoothness =
static_cast<double>(total_smoothness_dropped_) * 100 / total_frames;
-
- ukm_smoothness_data_->seq_lock.WriteBegin();
- device::OneWriterSeqLock::AtomicWriterMemcpy(&ukm_smoothness_data_->data,
- &smoothness_data,
- sizeof(UkmSmoothnessData));
- ukm_smoothness_data_->seq_lock.WriteEnd();
+ smoothness_data.worst_smoothness = sliding_window_max_percent_dropped_;
+ smoothness_data.percentile_95 = sliding_window_95pct_percent_dropped;
+ smoothness_data.time_max_delta = time_max_delta_;
+ ukm_smoothness_data_->Write(smoothness_data);
}
}
+double DroppedFrameCounter::GetMostRecentAverageSmoothness() const {
+ if (ukm_smoothness_data_)
+ return ukm_smoothness_data_->data.avg_smoothness;
+
+ return -1.f;
+}
+
+double DroppedFrameCounter::GetMostRecent95PercentileSmoothness() const {
+ if (ukm_smoothness_data_)
+ return ukm_smoothness_data_->data.percentile_95;
+
+ return -1.f;
+}
+
void DroppedFrameCounter::SetUkmSmoothnessDestination(
UkmSmoothnessDataShared* smoothness_data) {
ukm_smoothness_data_ = smoothness_data;
@@ -94,18 +257,93 @@ void DroppedFrameCounter::Reset() {
total_partial_ = 0;
total_dropped_ = 0;
total_smoothness_dropped_ = 0;
+ sliding_window_max_percent_dropped_ = 0;
+ dropped_frame_count_in_window_ = 0;
fcp_received_ = false;
+ sliding_window_ = {};
+ latest_sliding_window_start_ = {};
+ sliding_window_histogram_.Clear();
ring_buffer_.Clear();
frame_sorter_.Reset();
+ time_max_delta_ = {};
+}
+
+base::TimeDelta DroppedFrameCounter::ComputeCurrentWindowSize() const {
+ if (sliding_window_.empty())
+ return {};
+ return sliding_window_.back().first.frame_time +
+ sliding_window_.back().first.interval -
+ sliding_window_.front().first.frame_time;
}
void DroppedFrameCounter::NotifyFrameResult(const viz::BeginFrameArgs& args,
bool is_dropped) {
- // TODO(crbug.com/1115141) The implementation of smoothness metrics.
+ // Entirely disregard the frames with interval larger than the window --
+ // these are violating the assumptions in the below code and should
+ // only occur with external frame control, where dropped frame stats
+ // are not relevant.
+ if (args.interval >= kSlidingWindowInterval)
+ return;
+
+ sliding_window_.push({args, is_dropped});
+
+ if (ComputeCurrentWindowSize() < kSlidingWindowInterval) {
+ if (is_dropped)
+ ++dropped_frame_count_in_window_;
+ return;
+ }
+
+ DCHECK_GE(dropped_frame_count_in_window_, 0u);
+ DCHECK_GE(sliding_window_.size(), dropped_frame_count_in_window_);
+
+ const auto max_sliding_window_start =
+ args.frame_time - kSlidingWindowInterval;
+ const auto max_difference = args.interval * 1.5;
+ while (ComputeCurrentWindowSize() > kSlidingWindowInterval) {
+ const auto removed_args = sliding_window_.front().first;
+ const auto removed_was_dropped = sliding_window_.front().second;
+ if (removed_was_dropped) {
+ DCHECK_GT(dropped_frame_count_in_window_, 0u);
+ --dropped_frame_count_in_window_;
+ }
+ sliding_window_.pop();
+ DCHECK(!sliding_window_.empty());
+
+ auto dropped = dropped_frame_count_in_window_;
+ if (ComputeCurrentWindowSize() <= kSlidingWindowInterval && is_dropped)
+ ++dropped;
+
+ // If two consecutive 'completed' frames are far apart from each other (in
+ // time), then report the 'dropped frame count' for the sliding window(s) in
+ // between. Note that the window-size still needs to be at least
+ // kSlidingWindowInterval.
+ const auto& remaining_oldest_args = sliding_window_.front().first;
+ const auto last_timestamp =
+ std::min(remaining_oldest_args.frame_time, max_sliding_window_start);
+ const auto difference = last_timestamp - removed_args.frame_time;
+ const size_t count =
+ difference > max_difference ? std::ceil(difference / args.interval) : 1;
+ double percent_dropped_frame =
+ std::min((dropped * 100.0) / total_frames_in_window_, 100.0);
+ sliding_window_histogram_.AddPercentDroppedFrame(percent_dropped_frame,
+ count);
+
+ if (percent_dropped_frame > sliding_window_max_percent_dropped_) {
+ time_max_delta_ = args.frame_time - time_fcp_received_;
+ sliding_window_max_percent_dropped_ = percent_dropped_frame;
+ }
+
+ latest_sliding_window_start_ = last_timestamp;
+ latest_sliding_window_interval_ = remaining_oldest_args.interval;
+ }
+
+ if (is_dropped)
+ ++dropped_frame_count_in_window_;
}
void DroppedFrameCounter::OnFcpReceived() {
fcp_received_ = true;
+ time_fcp_received_ = base::TimeTicks::Now();
}
} // namespace cc
diff --git a/chromium/cc/metrics/dropped_frame_counter.h b/chromium/cc/metrics/dropped_frame_counter.h
index 17e9386a508..7126c32c46d 100644
--- a/chromium/cc/metrics/dropped_frame_counter.h
+++ b/chromium/cc/metrics/dropped_frame_counter.h
@@ -6,14 +6,16 @@
#define CC_METRICS_DROPPED_FRAME_COUNTER_H_
#include <stddef.h>
+#include <queue>
+#include <utility>
#include "base/containers/ring_buffer.h"
#include "cc/cc_export.h"
#include "cc/metrics/frame_sorter.h"
+#include "cc/metrics/ukm_smoothness_data.h"
namespace cc {
class TotalFrameCounter;
-struct UkmSmoothnessDataShared;
// This class maintains a counter for produced/dropped frames, and can be used
// to estimate the recent throughput.
@@ -25,6 +27,20 @@ class CC_EXPORT DroppedFrameCounter {
kFrameStateComplete
};
+ class CC_EXPORT SlidingWindowHistogram {
+ public:
+ void AddPercentDroppedFrame(double percent_dropped_frame, size_t count = 1);
+ uint32_t GetPercentDroppedFramePercentile(double percentile) const;
+ void Clear();
+ std::ostream& Dump(std::ostream& stream) const;
+
+ uint32_t total_count() const { return total_count_; }
+
+ private:
+ uint32_t histogram_bins_[101] = {0};
+ uint32_t total_count_ = 0;
+ };
+
DroppedFrameCounter();
~DroppedFrameCounter();
@@ -39,6 +55,9 @@ class CC_EXPORT DroppedFrameCounter {
uint32_t GetAverageThroughput() const;
+ double GetMostRecentAverageSmoothness() const;
+ double GetMostRecent95PercentileSmoothness() const;
+
typedef base::RingBuffer<FrameState, 180> RingBufferType;
RingBufferType::Iterator begin() const { return ring_buffer_.Begin(); }
RingBufferType::Iterator end() const { return ring_buffer_.End(); }
@@ -48,7 +67,7 @@ class CC_EXPORT DroppedFrameCounter {
void AddDroppedFrame();
void ReportFrames();
- void OnBeginFrame(const viz::BeginFrameArgs& args);
+ void OnBeginFrame(const viz::BeginFrameArgs& args, bool is_scroll_active);
void OnEndFrame(const viz::BeginFrameArgs& args, bool is_dropped);
void SetUkmSmoothnessDestination(UkmSmoothnessDataShared* smoothness_data);
void OnFcpReceived();
@@ -56,16 +75,42 @@ class CC_EXPORT DroppedFrameCounter {
// Reset is used on navigation, which resets frame statistics as well as
// frame sorter.
void Reset();
- // ResetFrameSorter is used when we need to keep track of frame statistics
- // but not to track the frames prior to reset in frame sorter.
- void ResetFrameSorter();
+
+ // ResetPendingFrames is used when we need to keep track of frame statistics,
+ // but should no longer wait for the pending frames (e.g. connection to
+ // gpu-process was reset, or the page became invisible, etc.). The pending
+ // frames are not considered to be dropped.
+ void ResetPendingFrames(base::TimeTicks timestamp);
void set_total_counter(TotalFrameCounter* total_counter) {
total_counter_ = total_counter;
}
+ double sliding_window_max_percent_dropped() const {
+ return sliding_window_max_percent_dropped_;
+ }
+
+ uint32_t SlidingWindow95PercentilePercentDropped() const {
+ return sliding_window_histogram_.GetPercentDroppedFramePercentile(0.95);
+ }
+
+ const SlidingWindowHistogram* GetSlidingWindowHistogram() const {
+ return &sliding_window_histogram_;
+ }
+
private:
void NotifyFrameResult(const viz::BeginFrameArgs& args, bool is_dropped);
+ base::TimeDelta ComputeCurrentWindowSize() const;
+
+ const base::TimeDelta kSlidingWindowInterval =
+ base::TimeDelta::FromSeconds(1);
+ std::queue<std::pair<const viz::BeginFrameArgs, bool>> sliding_window_;
+ uint32_t dropped_frame_count_in_window_ = 0;
+ double total_frames_in_window_ = 60.0;
+ SlidingWindowHistogram sliding_window_histogram_;
+
+ base::TimeTicks latest_sliding_window_start_;
+ base::TimeDelta latest_sliding_window_interval_;
RingBufferType ring_buffer_;
size_t total_frames_ = 0;
@@ -73,12 +118,28 @@ class CC_EXPORT DroppedFrameCounter {
size_t total_dropped_ = 0;
size_t total_smoothness_dropped_ = 0;
bool fcp_received_ = false;
-
+ double sliding_window_max_percent_dropped_ = 0;
+ base::TimeTicks time_fcp_received_;
+ base::TimeDelta time_max_delta_;
UkmSmoothnessDataShared* ukm_smoothness_data_ = nullptr;
FrameSorter frame_sorter_;
TotalFrameCounter* total_counter_ = nullptr;
+
+ struct ScrollStartInfo {
+ // The timestamp of when the scroll started.
+ base::TimeTicks timestamp;
+
+ // The vsync corresponding to the scroll-start.
+ viz::BeginFrameId frame_id;
+ };
+ base::Optional<ScrollStartInfo> scroll_start_;
+ std::map<viz::BeginFrameId, ScrollStartInfo> scroll_start_per_frame_;
};
+CC_EXPORT std::ostream& operator<<(
+ std::ostream&,
+ const DroppedFrameCounter::SlidingWindowHistogram&);
+
} // namespace cc
#endif // CC_METRICS_DROPPED_FRAME_COUNTER_H_
diff --git a/chromium/cc/metrics/dropped_frame_counter_unittest.cc b/chromium/cc/metrics/dropped_frame_counter_unittest.cc
index 99d5c35a35a..881eff48090 100644
--- a/chromium/cc/metrics/dropped_frame_counter_unittest.cc
+++ b/chromium/cc/metrics/dropped_frame_counter_unittest.cc
@@ -4,8 +4,11 @@
#include "cc/metrics/dropped_frame_counter.h"
+#include <vector>
+
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
+#include "base/time/time.h"
#include "cc/animation/animation_host.h"
#include "cc/test/fake_content_layer_client.h"
#include "cc/test/fake_picture_layer.h"
@@ -247,5 +250,251 @@ class DroppedFrameCounterMainDropsSmoothnessTest
// TODO(crbug.com/1115376) Disabled for flakiness.
// MULTI_THREAD_TEST_F(DroppedFrameCounterMainDropsSmoothnessTest);
+class DroppedFrameCounterTest : public testing::Test {
+ public:
+ DroppedFrameCounterTest() {
+ dropped_frame_counter_.set_total_counter(&total_frame_counter_);
+ dropped_frame_counter_.OnFcpReceived();
+ }
+ ~DroppedFrameCounterTest() override = default;
+
+ // For each boolean in frame_states produces a frame
+ void SimulateFrameSequence(std::vector<bool> frame_states, int repeat) {
+ for (int i = 0; i < repeat; i++) {
+ for (auto is_dropped : frame_states) {
+ viz::BeginFrameArgs args_ = SimulateBeginFrameArgs();
+ dropped_frame_counter_.OnBeginFrame(args_, /*is_scroll_active=*/false);
+ dropped_frame_counter_.OnEndFrame(args_, is_dropped);
+ sequence_number_++;
+ frame_time_ += interval_;
+ }
+ }
+ }
+
+ void AdvancetimeByIntervals(int interval_count) {
+ frame_time_ += interval_ * interval_count;
+ }
+
+ double MaxPercentDroppedFrame() {
+ return dropped_frame_counter_.sliding_window_max_percent_dropped();
+ }
+
+ double PercentDroppedFrame95Percentile() {
+ return dropped_frame_counter_.SlidingWindow95PercentilePercentDropped();
+ }
+
+ double GetTotalFramesInWindow() {
+ return base::TimeDelta::FromSeconds(1) / interval_;
+ }
+
+ void SetInterval(base::TimeDelta interval) { interval_ = interval; }
+
+ base::TimeTicks GetNextFrameTime() const { return frame_time_ + interval_; }
+
+ public:
+ DroppedFrameCounter dropped_frame_counter_;
+
+ private:
+ TotalFrameCounter total_frame_counter_;
+ uint64_t sequence_number_ = 1;
+ uint64_t source_id_ = 1;
+ const base::TickClock* tick_clock_ = base::DefaultTickClock::GetInstance();
+ base::TimeTicks frame_time_ = tick_clock_->NowTicks();
+ base::TimeDelta interval_ =
+ base::TimeDelta::FromMicroseconds(16667); // 16.667 ms
+
+ viz::BeginFrameArgs SimulateBeginFrameArgs() {
+ viz::BeginFrameId current_id_(source_id_, sequence_number_);
+ viz::BeginFrameArgs args = viz::BeginFrameArgs();
+ args.frame_id = current_id_;
+ args.frame_time = frame_time_;
+ args.interval = interval_;
+ return args;
+ }
+};
+
+TEST_F(DroppedFrameCounterTest, SimplePattern1) {
+ // 2 out of every 3 frames are dropped (In total 80 frames out of 120).
+ SimulateFrameSequence({true, true, true, false, true, false}, 20);
+
+ // The max is the following window:
+ // 16 * <sequence> + {true, true, true, false
+ // Which means a max of 67 dropped frames.
+ EXPECT_EQ(std::round(MaxPercentDroppedFrame()), 67);
+ EXPECT_EQ(PercentDroppedFrame95Percentile(), 67); // all values are in the
+ // 67th bucket, and as a result 95th percentile is also 67.
+}
+
+TEST_F(DroppedFrameCounterTest, SimplePattern2) {
+ // 1 out of every 5 frames are dropped (In total 24 frames out of 120).
+ SimulateFrameSequence({false, false, false, false, true}, 24);
+
+ double expected_percent_dropped_frame = (12 / GetTotalFramesInWindow()) * 100;
+ EXPECT_FLOAT_EQ(MaxPercentDroppedFrame(), expected_percent_dropped_frame);
+ EXPECT_EQ(PercentDroppedFrame95Percentile(), 20); // all values are in the
+ // 20th bucket, and as a result 95th percentile is also 20.
+}
+
+TEST_F(DroppedFrameCounterTest, IncompleteWindow) {
+ // There are only 5 frames submitted and both Max and 95pct should report
+ // zero.
+ SimulateFrameSequence({false, false, false, false, true}, 1);
+ EXPECT_EQ(MaxPercentDroppedFrame(), 0.0);
+ EXPECT_EQ(PercentDroppedFrame95Percentile(), 0);
+}
+
+TEST_F(DroppedFrameCounterTest, MaxPercentDroppedChanges) {
+ // First 60 frames have 20% dropped.
+ SimulateFrameSequence({false, false, false, false, true}, 12);
+
+ double expected_percent_dropped_frame1 =
+ (12 / GetTotalFramesInWindow()) * 100;
+ EXPECT_EQ(MaxPercentDroppedFrame(), expected_percent_dropped_frame1);
+ EXPECT_FLOAT_EQ(PercentDroppedFrame95Percentile(), 20); // There is only one
+ // element in the histogram and that is 20.
+
+ // 30 new frames are added that have 18 dropped frames.
+ // and the 30 frame before that had 6 dropped frames.
+ // So in total in the window has 24 frames dropped out of 60 frames.
+ SimulateFrameSequence({false, false, true, true, true}, 6);
+ double expected_percent_dropped_frame2 =
+ (24 / GetTotalFramesInWindow()) * 100;
+ EXPECT_FLOAT_EQ(MaxPercentDroppedFrame(), expected_percent_dropped_frame2);
+
+ // 30 new frames are added that have 24 dropped frames.
+ // and the 30 frame before that had 18 dropped frames.
+ // So in total in the window has 42 frames dropped out of 60 frames.
+ SimulateFrameSequence({false, true, true, true, true}, 6);
+ double expected_percent_dropped_frame3 =
+ (42 / GetTotalFramesInWindow()) * 100;
+ EXPECT_FLOAT_EQ(MaxPercentDroppedFrame(), expected_percent_dropped_frame3);
+
+ // Percent dropped frame of window increases gradually to 70%.
+ // 1 value exist when we reach 60 frames and 1 value thereafter for each
+ // frame added. So there 61 values in histogram. Last value is 70 (2 sampels)
+ // and then 67 with 1 sample, which would be the 95th percentile.
+ EXPECT_EQ(PercentDroppedFrame95Percentile(), 67);
+}
+
+TEST_F(DroppedFrameCounterTest, MaxPercentDroppedWithIdleFrames) {
+ // First 20 frames have 4 frames dropped (20%).
+ SimulateFrameSequence({false, false, false, false, true}, 4);
+
+ // Then no frames are added for 20 intervals.
+ AdvancetimeByIntervals(20);
+
+ // Then 20 frames have 16 frames dropped (60%).
+ SimulateFrameSequence({false, false, true, true, true}, 4);
+
+ // So in total, there are 40 frames in the 1 second window with 16 dropped
+ // frames (40% in total).
+ double expected_percent_dropped_frame = (16 / GetTotalFramesInWindow()) * 100;
+ EXPECT_FLOAT_EQ(MaxPercentDroppedFrame(), expected_percent_dropped_frame);
+}
+
+TEST_F(DroppedFrameCounterTest, NoCrashForIntervalLargerThanWindow) {
+ SetInterval(base::TimeDelta::FromMilliseconds(1000));
+ SimulateFrameSequence({false, false}, 1);
+}
+
+TEST_F(DroppedFrameCounterTest, Percentile95WithIdleFrames) {
+ // Test scenario:
+ // . 4s of 20% dropped frames.
+ // . 96s of idle time.
+ // The 96%ile dropped-frame metric should be 0.
+
+ // Set an interval that rounds up nicely with 1 second.
+ constexpr auto kInterval = base::TimeDelta::FromMilliseconds(10);
+ constexpr size_t kFps = base::TimeDelta::FromSeconds(1) / kInterval;
+ static_assert(
+ kFps % 5 == 0,
+ "kFps must be a multiple of 5 because this test depends on it.");
+ SetInterval(kInterval);
+
+ const auto* histogram = dropped_frame_counter_.GetSlidingWindowHistogram();
+
+ // First 4 seconds with 20% dropped frames.
+ SimulateFrameSequence({false, false, false, false, true}, (kFps / 5) * 4);
+ EXPECT_EQ(histogram->GetPercentDroppedFramePercentile(0.95), 20u);
+
+ // Then no frames are added for 97s. Note that this 1s more than 96 seconds,
+ // because the last second remains in the sliding window.
+ AdvancetimeByIntervals(kFps * 97);
+
+ // A single frame to flush the pipeline.
+ SimulateFrameSequence({false}, 1);
+
+ EXPECT_EQ(histogram->total_count(), 100u * kFps);
+ EXPECT_EQ(histogram->GetPercentDroppedFramePercentile(0.96), 0u);
+ EXPECT_GT(histogram->GetPercentDroppedFramePercentile(0.97), 0u);
+}
+
+TEST_F(DroppedFrameCounterTest, Percentile95WithIdleFramesWhileHidden) {
+ // The test scenario is the same as |Percentile95WithIdleFrames| test:
+ // . 4s of 20% dropped frames.
+ // . 96s of idle time.
+ // However, the 96s of idle time happens *after* the page becomes invisible
+ // (e.g. after a tab-switch). In this case, the idle time *should not*
+ // contribute to the sliding window.
+
+ // Set an interval that rounds up nicely with 1 second.
+ constexpr auto kInterval = base::TimeDelta::FromMilliseconds(10);
+ constexpr size_t kFps = base::TimeDelta::FromSeconds(1) / kInterval;
+ static_assert(
+ kFps % 5 == 0,
+ "kFps must be a multiple of 5 because this test depends on it.");
+ SetInterval(kInterval);
+
+ const auto* histogram = dropped_frame_counter_.GetSlidingWindowHistogram();
+
+ // First 4 seconds with 20% dropped frames.
+ SimulateFrameSequence({false, false, false, false, true}, (kFps / 5) * 4);
+ EXPECT_EQ(histogram->GetPercentDroppedFramePercentile(0.95), 20u);
+
+ // Hide the page (thus resetting the pending frames), then idle for 96s before
+ // producing a single frame.
+ dropped_frame_counter_.ResetPendingFrames(GetNextFrameTime());
+ AdvancetimeByIntervals(kFps * 97);
+
+ // A single frame to flush the pipeline.
+ SimulateFrameSequence({false}, 1);
+
+ EXPECT_EQ(histogram->GetPercentDroppedFramePercentile(0.95), 20u);
+}
+
+TEST_F(DroppedFrameCounterTest, Percentile95WithIdleFramesThenHide) {
+ // The test scenario is the same as |Percentile95WithIdleFramesWhileHidden|:
+ // . 4s of 20% dropped frames.
+ // . 96s of idle time.
+ // However, the 96s of idle time happens *before* the page becomes invisible
+ // (e.g. after a tab-switch). In this case, the idle time *should*
+ // contribute to the sliding window.
+
+ // Set an interval that rounds up nicely with 1 second.
+ constexpr auto kInterval = base::TimeDelta::FromMilliseconds(10);
+ constexpr size_t kFps = base::TimeDelta::FromSeconds(1) / kInterval;
+ static_assert(
+ kFps % 5 == 0,
+ "kFps must be a multiple of 5 because this test depends on it.");
+ SetInterval(kInterval);
+
+ const auto* histogram = dropped_frame_counter_.GetSlidingWindowHistogram();
+
+ // First 4 seconds with 20% dropped frames.
+ SimulateFrameSequence({false, false, false, false, true}, (kFps / 5) * 4);
+ EXPECT_EQ(histogram->GetPercentDroppedFramePercentile(0.95), 20u);
+
+ // Idle for 96s before hiding the page.
+ AdvancetimeByIntervals(kFps * 97);
+ dropped_frame_counter_.ResetPendingFrames(GetNextFrameTime());
+ AdvancetimeByIntervals(kFps * 97);
+
+ // A single frame to flush the pipeline.
+ SimulateFrameSequence({false}, 1);
+
+ EXPECT_EQ(histogram->GetPercentDroppedFramePercentile(0.96), 0u);
+ EXPECT_GT(histogram->GetPercentDroppedFramePercentile(0.97), 0u);
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/metrics/event_metrics.cc b/chromium/cc/metrics/event_metrics.cc
index b4cac6065cc..b331dc0a0f5 100644
--- a/chromium/cc/metrics/event_metrics.cc
+++ b/chromium/cc/metrics/event_metrics.cc
@@ -4,12 +4,14 @@
#include "cc/metrics/event_metrics.h"
+#include <algorithm>
#include <utility>
#include "base/check.h"
#include "base/memory/ptr_util.h"
#include "base/notreached.h"
#include "base/stl_util.h"
+#include "base/time/default_tick_clock.h"
namespace cc {
namespace {
@@ -48,6 +50,10 @@ constexpr struct {
EVENT_TYPE(FirstGestureScrollUpdate,
ui::ET_GESTURE_SCROLL_UPDATE,
EventMetrics::ScrollUpdateType::kStarted),
+ EVENT_TYPE(MouseDragged, ui::ET_MOUSE_DRAGGED),
+ EVENT_TYPE(GesturePinchBegin, ui::ET_GESTURE_PINCH_BEGIN),
+ EVENT_TYPE(GesturePinchEnd, ui::ET_GESTURE_PINCH_END),
+ EVENT_TYPE(GesturePinchUpdate, ui::ET_GESTURE_PINCH_UPDATE),
#undef EVENT_TYPE
};
static_assert(base::size(kInterestingEvents) ==
@@ -106,11 +112,85 @@ base::Optional<EventMetrics::ScrollType> ToScrollType(
} // namespace
+// static
std::unique_ptr<EventMetrics> EventMetrics::Create(
ui::EventType type,
base::Optional<ScrollUpdateType> scroll_update_type,
- base::TimeTicks time_stamp,
- base::Optional<ui::ScrollInputType> scroll_input_type) {
+ base::Optional<ui::ScrollInputType> scroll_input_type,
+ base::TimeTicks timestamp) {
+ // TODO(crbug.com/1157090): We expect that `timestamp` is not null, but there
+ // seems to be some tests that are emitting events with null timestamp. We
+ // should investigate and try to fix those cases and add a `DCHECK` here to
+ // assert `timestamp` is not null.
+
+ std::unique_ptr<EventMetrics> metrics =
+ CreateInternal(type, scroll_update_type, scroll_input_type, timestamp,
+ base::DefaultTickClock::GetInstance());
+ if (!metrics)
+ return nullptr;
+
+ metrics->SetDispatchStageTimestamp(
+ DispatchStage::kArrivedInRendererCompositor);
+ return metrics;
+}
+
+// static
+std::unique_ptr<EventMetrics> EventMetrics::CreateForTesting(
+ ui::EventType type,
+ base::Optional<ScrollUpdateType> scroll_update_type,
+ base::Optional<ui::ScrollInputType> scroll_input_type,
+ base::TimeTicks timestamp,
+ const base::TickClock* tick_clock) {
+ DCHECK(!timestamp.is_null());
+
+ std::unique_ptr<EventMetrics> metrics = CreateInternal(
+ type, scroll_update_type, scroll_input_type, timestamp, tick_clock);
+ if (!metrics)
+ return nullptr;
+
+ metrics->SetDispatchStageTimestamp(
+ DispatchStage::kArrivedInRendererCompositor);
+ return metrics;
+}
+
+// static
+std::unique_ptr<EventMetrics> EventMetrics::CreateFromExisting(
+ ui::EventType type,
+ base::Optional<ScrollUpdateType> scroll_update_type,
+ base::Optional<ui::ScrollInputType> scroll_input_type,
+ DispatchStage last_dispatch_stage,
+ const EventMetrics* existing) {
+ std::unique_ptr<EventMetrics> metrics = CreateInternal(
+ type, scroll_update_type, scroll_input_type, base::TimeTicks(),
+ existing ? existing->tick_clock_ : base::DefaultTickClock::GetInstance());
+ if (!metrics)
+ return nullptr;
+
+ // Since the new event is of an interesting type, we expect the existing event
+ // to be of an interesting type, too; which means `existing` should not be
+ // nullptr. However, some tests that are not interested in reporting metrics,
+ // don't create metrics objects even for events of interesting types. Return
+ // nullptr if that's the case.
+ if (!existing)
+ return nullptr;
+
+ // Use timestamps of all stages (including "Generated" stage) up to
+ // `last_dispatch_stage` from `existing`.
+ for (size_t stage_index = static_cast<size_t>(DispatchStage::kGenerated);
+ stage_index <= static_cast<size_t>(last_dispatch_stage); stage_index++) {
+ metrics->dispatch_stage_timestamps_[stage_index] =
+ existing->dispatch_stage_timestamps_[stage_index];
+ }
+ return metrics;
+}
+
+// static
+std::unique_ptr<EventMetrics> EventMetrics::CreateInternal(
+ ui::EventType type,
+ base::Optional<ScrollUpdateType> scroll_update_type,
+ base::Optional<ui::ScrollInputType> scroll_input_type,
+ base::TimeTicks timestamp,
+ const base::TickClock* tick_clock) {
// `scroll_update_type` should be set for and only for
// `ui::ET_GESTURE_SCROLL_UPDATE`.
DCHECK(type == ui::ET_GESTURE_SCROLL_UPDATE && scroll_update_type ||
@@ -119,14 +199,21 @@ std::unique_ptr<EventMetrics> EventMetrics::Create(
ToInterestingEventType(type, scroll_update_type);
if (!interesting_type)
return nullptr;
- return base::WrapUnique(new EventMetrics(*interesting_type, time_stamp,
- ToScrollType(scroll_input_type)));
+ return base::WrapUnique(new EventMetrics(*interesting_type,
+ ToScrollType(scroll_input_type),
+ timestamp, tick_clock));
}
EventMetrics::EventMetrics(EventType type,
- base::TimeTicks time_stamp,
- base::Optional<ScrollType> scroll_type)
- : type_(type), time_stamp_(time_stamp), scroll_type_(scroll_type) {}
+ base::Optional<ScrollType> scroll_type,
+ base::TimeTicks timestamp,
+ const base::TickClock* tick_clock)
+ : type_(type), scroll_type_(scroll_type), tick_clock_(tick_clock) {
+ dispatch_stage_timestamps_[static_cast<int>(DispatchStage::kGenerated)] =
+ timestamp;
+}
+
+EventMetrics::~EventMetrics() = default;
const char* EventMetrics::GetTypeName() const {
return kInterestingEvents[static_cast<int>(type_)].name;
@@ -138,9 +225,47 @@ const char* EventMetrics::GetScrollTypeName() const {
return kScrollTypes[static_cast<int>(*scroll_type_)].name;
}
+void EventMetrics::SetDispatchStageTimestamp(DispatchStage stage) {
+ DCHECK(dispatch_stage_timestamps_[static_cast<size_t>(stage)].is_null());
+
+ dispatch_stage_timestamps_[static_cast<size_t>(stage)] =
+ tick_clock_->NowTicks();
+}
+
+base::TimeTicks EventMetrics::GetDispatchStageTimestamp(
+ DispatchStage stage) const {
+ return dispatch_stage_timestamps_[static_cast<size_t>(stage)];
+}
+
+void EventMetrics::ResetToDispatchStage(DispatchStage stage) {
+ for (size_t stage_index = static_cast<size_t>(stage) + 1;
+ stage_index <= static_cast<size_t>(DispatchStage::kMaxValue);
+ stage_index++) {
+ dispatch_stage_timestamps_[stage_index] = base::TimeTicks();
+ }
+}
+
+bool EventMetrics::ShouldReportScrollingTotalLatency() const {
+ return type_ == EventType::kGestureScrollBegin ||
+ type_ == EventType::kGestureScrollEnd ||
+ type_ == EventType::kFirstGestureScrollUpdate ||
+ type_ == EventType::kGestureScrollUpdate;
+}
+
+std::unique_ptr<EventMetrics> EventMetrics::Clone() const {
+ auto clone = base::WrapUnique(
+ new EventMetrics(type_, scroll_type_, base::TimeTicks(), tick_clock_));
+ std::copy(std::begin(dispatch_stage_timestamps_),
+ std::end(dispatch_stage_timestamps_),
+ std::begin(clone->dispatch_stage_timestamps_));
+ return clone;
+}
+
bool EventMetrics::operator==(const EventMetrics& other) const {
- return std::tie(type_, time_stamp_, scroll_type_) ==
- std::tie(other.type_, other.time_stamp_, other.scroll_type_);
+ return type_ == other.type_ && scroll_type_ == other.scroll_type_ &&
+ std::equal(std::begin(dispatch_stage_timestamps_),
+ std::end(dispatch_stage_timestamps_),
+ std::begin(other.dispatch_stage_timestamps_));
}
// EventMetricsSet
diff --git a/chromium/cc/metrics/event_metrics.h b/chromium/cc/metrics/event_metrics.h
index 6350452616f..d9306946733 100644
--- a/chromium/cc/metrics/event_metrics.h
+++ b/chromium/cc/metrics/event_metrics.h
@@ -9,6 +9,7 @@
#include <vector>
#include "base/optional.h"
+#include "base/time/tick_clock.h"
#include "base/time/time.h"
#include "cc/cc_export.h"
#include "ui/events/types/event_type.h"
@@ -49,7 +50,11 @@ class CC_EXPORT EventMetrics {
kGestureTapUnconfirmed,
kGestureTwoFingerTap,
kFirstGestureScrollUpdate,
- kMaxValue = kFirstGestureScrollUpdate,
+ kMouseDragged,
+ kGesturePinchBegin,
+ kGesturePinchEnd,
+ kGesturePinchUpdate,
+ kMaxValue = kGesturePinchUpdate,
};
// Type of scroll events. This list should be in the same order as values of
@@ -70,44 +75,105 @@ class CC_EXPORT EventMetrics {
kMaxValue = kContinued,
};
- // Returns a new instance if |type| is an event type we are interested in.
+ // Stages of event dispatch in different processes/threads.
+ enum class DispatchStage {
+ kGenerated,
+ kArrivedInRendererCompositor,
+ kRendererCompositorStarted,
+ kRendererCompositorFinished,
+ kRendererMainStarted,
+ kRendererMainFinished,
+ kMaxValue = kRendererMainFinished,
+ };
+
+ // Returns a new instance if the event is of a type we are interested in.
// Otherwise, returns nullptr.
static std::unique_ptr<EventMetrics> Create(
ui::EventType type,
base::Optional<ScrollUpdateType> scroll_update_type,
- base::TimeTicks time_stamp,
- base::Optional<ui::ScrollInputType> scroll_input_type);
+ base::Optional<ui::ScrollInputType> scroll_input_type,
+ base::TimeTicks timestamp);
+
+ // Similar to `Create()` with an extra `base::TickClock` to use in tests.
+ static std::unique_ptr<EventMetrics> CreateForTesting(
+ ui::EventType type,
+ base::Optional<ScrollUpdateType> scroll_update_type,
+ base::Optional<ui::ScrollInputType> scroll_input_type,
+ base::TimeTicks timestamp,
+ const base::TickClock* tick_clock);
+
+ // Used to create an instance for an event generated based on an existing
+ // event. If the new event is of an interesting type, we expect that the
+ // existing event is also of an interesting type in which case `existing` is
+ // not nullptr and timestamps (up to and including `last_dispatch_stage`) and
+ // tick clock from `existing` will be used for the new metrics object. If the
+ // new event is not an interesting one, return value would be nullptr.
+ static std::unique_ptr<EventMetrics> CreateFromExisting(
+ ui::EventType type,
+ base::Optional<ScrollUpdateType> scroll_update_type,
+ base::Optional<ui::ScrollInputType> scroll_input_type,
+ DispatchStage last_dispatch_stage,
+ const EventMetrics* existing);
EventMetrics(const EventMetrics&) = delete;
EventMetrics& operator=(const EventMetrics&) = delete;
+ ~EventMetrics();
+
EventType type() const { return type_; }
// Returns a string representing event type.
const char* GetTypeName() const;
- base::TimeTicks time_stamp() const { return time_stamp_; }
-
const base::Optional<ScrollType>& scroll_type() const { return scroll_type_; }
// Returns a string representing input type for a scroll event. Should only be
// called for scroll events.
const char* GetScrollTypeName() const;
+ void SetDispatchStageTimestamp(DispatchStage stage);
+ base::TimeTicks GetDispatchStageTimestamp(DispatchStage stage) const;
+
+ // Resets the metrics object to dispatch stage `stage` by setting timestamps
+ // of dispatch stages after `stage` to null timestamp,
+ void ResetToDispatchStage(DispatchStage stage);
+
+ // Determines whether TotalLatencyToSwapBegin metric should be reported for
+ // this event or not. This metric is only desired for gesture-scroll events.
+ bool ShouldReportScrollingTotalLatency() const;
+
+ std::unique_ptr<EventMetrics> Clone() const;
+
// Used in tests to check expectations on EventMetrics objects.
bool operator==(const EventMetrics& other) const;
private:
+ static std::unique_ptr<EventMetrics> CreateInternal(
+ ui::EventType type,
+ base::Optional<ScrollUpdateType> scroll_update_type,
+ base::Optional<ui::ScrollInputType> scroll_input_type,
+ base::TimeTicks timestamp,
+ const base::TickClock* tick_clock);
+
EventMetrics(EventType type,
- base::TimeTicks time_stamp,
- base::Optional<ScrollType> scroll_type);
+ base::Optional<ScrollType> scroll_type,
+ base::TimeTicks timestamp,
+ const base::TickClock* tick_clock);
EventType type_;
- base::TimeTicks time_stamp_;
// Only available for scroll events and represents the type of input device
// for the event.
base::Optional<ScrollType> scroll_type_;
+
+ const base::TickClock* const tick_clock_;
+
+ // Timestamps of different stages of event dispatch. Timestamps are set as the
+ // event moves forward in the pipeline. In the end, some stages might not have
+ // a timestamp which means the event did not pass those stages.
+ base::TimeTicks
+ dispatch_stage_timestamps_[static_cast<int>(DispatchStage::kMaxValue) +
+ 1];
};
// Struct storing event metrics from both main and impl threads.
diff --git a/chromium/cc/metrics/events_metrics_manager_unittest.cc b/chromium/cc/metrics/events_metrics_manager_unittest.cc
index 5e3f72b8b68..8c7c450cf52 100644
--- a/chromium/cc/metrics/events_metrics_manager_unittest.cc
+++ b/chromium/cc/metrics/events_metrics_manager_unittest.cc
@@ -9,6 +9,7 @@
#include "base/bind.h"
#include "base/stl_util.h"
+#include "base/test/simple_test_tick_clock.h"
#include "cc/metrics/event_metrics.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -51,15 +52,16 @@ class EventsMetricsManagerTest : public testing::Test {
~EventsMetricsManagerTest() override = default;
protected:
- base::TimeTicks now() const { return now_; }
-
- base::TimeTicks AdvanceNowByMs(int ms) {
- now_ += base::TimeDelta::FromMilliseconds(ms);
- return now_;
+ std::unique_ptr<EventMetrics> CreateEventMetrics(ui::EventType type) {
+ test_tick_clock_.Advance(base::TimeDelta::FromMicroseconds(10));
+ base::TimeTicks event_time = test_tick_clock_.NowTicks();
+ test_tick_clock_.Advance(base::TimeDelta::FromMicroseconds(10));
+ return EventMetrics::CreateForTesting(type, base::nullopt, base::nullopt,
+ event_time, &test_tick_clock_);
}
EventsMetricsManager manager_;
- base::TimeTicks now_ = base::TimeTicks::Now();
+ base::SimpleTestTickClock test_tick_clock_;
};
// Tests that EventMetrics are saved only if they have an event type we are
@@ -75,27 +77,19 @@ TEST_F(EventsMetricsManagerTest, EventsMetricsSaved) {
std::pair<std::unique_ptr<EventMetrics>, Behavior> events[] = {
// An interesting event type for which SaveActiveEventMetrics() is not
// called.
- {EventMetrics::Create(ui::ET_MOUSE_PRESSED, base::nullopt,
- AdvanceNowByMs(1), base::nullopt),
- Behavior::kDoNotSave},
+ {CreateEventMetrics(ui::ET_MOUSE_PRESSED), Behavior::kDoNotSave},
// An interesting event type for which SaveActiveEventMetrics() is called
// inside its monitor scope.
- {EventMetrics::Create(ui::ET_MOUSE_PRESSED, base::nullopt,
- AdvanceNowByMs(1), base::nullopt),
- Behavior::kSaveInsideScope},
+ {CreateEventMetrics(ui::ET_MOUSE_PRESSED), Behavior::kSaveInsideScope},
// An interesting event type for which SaveActiveEventMetrics() is called
// after its monitor scope is finished.
- {EventMetrics::Create(ui::ET_MOUSE_PRESSED, base::nullopt,
- AdvanceNowByMs(1), base::nullopt),
- Behavior::kSaveOutsideScope},
+ {CreateEventMetrics(ui::ET_MOUSE_PRESSED), Behavior::kSaveOutsideScope},
// A non-interesting event type for which SaveActiveEventMetrics() is
// called inside its monitor scope.
- {EventMetrics::Create(ui::ET_MOUSE_MOVED, base::nullopt,
- AdvanceNowByMs(1), base::nullopt),
- Behavior::kSaveInsideScope},
+ {CreateEventMetrics(ui::ET_MOUSE_MOVED), Behavior::kSaveInsideScope},
};
EXPECT_NE(events[0].first, nullptr);
EXPECT_NE(events[1].first, nullptr);
@@ -134,22 +128,16 @@ TEST_F(EventsMetricsManagerTest, EventsMetricsSaved) {
// different configurations.
TEST_F(EventsMetricsManagerTest, NestedEventsMetrics) {
struct {
- ui::EventType type;
- base::TimeTicks timestamp;
- } events[] = {
- {ui::ET_MOUSE_PRESSED, AdvanceNowByMs(1)},
- {ui::ET_MOUSE_RELEASED, AdvanceNowByMs(1)},
- };
-
- struct {
- // Index of event to use for the outer scope. -1 if no event should be used.
- int outer_event;
+ // Type of event to use for the outer scope. `ui::EventType::ET_UNKNOWN` if
+ // no event should be used.
+ ui::EventType outer_event_type;
// Whether to save the outer scope metrics before starting the inner scope.
bool save_outer_metrics_before_inner;
- // Index of event to use for the inner scope. -1 if no event should be used.
- int inner_event;
+ // Type of event to use for the inner scope. `ui::EventType::ET_UNKNOWN` if
+ // no event should be used.
+ ui::EventType inner_event_type;
// Whether to save the inner scope metrics.
bool save_inner_metrics;
@@ -159,45 +147,45 @@ TEST_F(EventsMetricsManagerTest, NestedEventsMetrics) {
} configs[] = {
// Config #0.
{
- /*outer_metrics=*/0,
+ /*outer_event_type=*/ui::EventType::ET_MOUSE_PRESSED,
/*save_outer_metrics_before_inner=*/true,
- /*inner_metrics=*/1,
+ /*inner_event_type=*/ui::EventType::ET_MOUSE_RELEASED,
/*save_inner_metrics=*/true,
/*save_outer_metrics_after_inner=*/false,
},
// Config #1.
{
- /*outer_metrics=*/0,
+ /*outer_event_type=*/ui::EventType::ET_MOUSE_PRESSED,
/*save_outer_metrics_before_inner=*/false,
- /*inner_metrics=*/1,
+ /*inner_event_type=*/ui::EventType::ET_MOUSE_RELEASED,
/*save_inner_metrics=*/true,
/*save_outer_metrics_after_inner=*/true,
},
// Config #2.
{
- /*outer_metrics=*/0,
+ /*outer_event_type=*/ui::EventType::ET_MOUSE_PRESSED,
/*save_outer_metrics_before_inner=*/true,
- /*inner_metrics=*/1,
+ /*inner_event_type=*/ui::EventType::ET_MOUSE_RELEASED,
/*save_inner_metrics=*/true,
/*save_outer_metrics_after_inner=*/true,
},
// Config #3.
{
- /*outer_metrics=*/0,
+ /*outer_event_type=*/ui::EventType::ET_MOUSE_PRESSED,
/*save_outer_metrics_before_inner=*/false,
- /*inner_metrics=*/-1,
+ /*inner_event_type=*/ui::EventType::ET_UNKNOWN,
/*save_inner_metrics=*/false,
/*save_outer_metrics_after_inner=*/true,
},
// Config #4.
{
- /*outer_metrics=*/-1,
+ /*outer_event_type=*/ui::EventType::ET_UNKNOWN,
/*save_outer_metrics_before_inner=*/false,
- /*inner_metrics=*/0,
+ /*inner_event_type=*/ui::EventType::ET_MOUSE_PRESSED,
/*save_inner_metrics=*/true,
/*save_outer_metrics_after_inner=*/false,
},
@@ -209,10 +197,8 @@ TEST_F(EventsMetricsManagerTest, NestedEventsMetrics) {
{ // Start outer scope.
std::unique_ptr<EventMetrics> outer_metrics;
- if (config.outer_event != -1) {
- auto& event = events[config.outer_event];
- outer_metrics = EventMetrics::Create(event.type, base::nullopt,
- event.timestamp, base::nullopt);
+ if (config.outer_event_type != ui::EventType::ET_UNKNOWN) {
+ outer_metrics = CreateEventMetrics(config.outer_event_type);
DCHECK_NE(outer_metrics, nullptr);
expected_saved_metrics.push_back(outer_metrics.get());
}
@@ -223,10 +209,8 @@ TEST_F(EventsMetricsManagerTest, NestedEventsMetrics) {
{ // Start inner scope.
std::unique_ptr<EventMetrics> inner_metrics;
- if (config.inner_event != -1) {
- auto& event = events[config.inner_event];
- inner_metrics = EventMetrics::Create(event.type, base::nullopt,
- event.timestamp, base::nullopt);
+ if (config.inner_event_type != ui::EventType::ET_UNKNOWN) {
+ inner_metrics = CreateEventMetrics(config.inner_event_type);
DCHECK_NE(inner_metrics, nullptr);
expected_saved_metrics.push_back(inner_metrics.get());
}
diff --git a/chromium/cc/metrics/frame_sequence_metrics.cc b/chromium/cc/metrics/frame_sequence_metrics.cc
index e79edb0a3c0..1d4e00a04df 100644
--- a/chromium/cc/metrics/frame_sequence_metrics.cc
+++ b/chromium/cc/metrics/frame_sequence_metrics.cc
@@ -119,7 +119,7 @@ FrameSequenceMetrics::FrameSequenceMetrics(FrameSequenceTrackerType type,
FrameSequenceMetrics::~FrameSequenceMetrics() = default;
void FrameSequenceMetrics::ReportLeftoverData() {
- if (HasDataLeftForReporting())
+ if (HasDataLeftForReporting() || type_ == FrameSequenceTrackerType::kCustom)
ReportMetrics();
}
@@ -228,6 +228,7 @@ void FrameSequenceMetrics::ReportMetrics() {
main_throughput_ = {};
impl_throughput_ = {};
+ jank_reporter_->Reset();
frames_checkerboarded_ = 0;
return;
}
diff --git a/chromium/cc/metrics/frame_sequence_tracker.cc b/chromium/cc/metrics/frame_sequence_tracker.cc
index 4b603a222dc..9576ad3b63d 100644
--- a/chromium/cc/metrics/frame_sequence_tracker.cc
+++ b/chromium/cc/metrics/frame_sequence_tracker.cc
@@ -78,6 +78,11 @@ FrameSequenceTracker::FrameSequenceTracker(
throughput_ukm_reporter)) {
DCHECK_LT(type, FrameSequenceTrackerType::kMaxType);
DCHECK(type != FrameSequenceTrackerType::kCustom);
+ // TODO(crbug.com/1158439): remove the trace event once the validation is
+ // completed.
+ TRACE_EVENT_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP1(
+ "cc,benchmark", "TrackerValidation", TRACE_ID_LOCAL(this),
+ base::TimeTicks::Now(), "name", GetFrameSequenceTrackerTypeName(type));
}
FrameSequenceTracker::FrameSequenceTracker(
@@ -92,6 +97,9 @@ FrameSequenceTracker::FrameSequenceTracker(
}
FrameSequenceTracker::~FrameSequenceTracker() {
+ TRACE_EVENT_NESTABLE_ASYNC_END_WITH_TIMESTAMP0(
+ "cc,benchmark", "TrackerValidation", TRACE_ID_LOCAL(this),
+ base::TimeTicks::Now());
CleanUp();
}
@@ -441,13 +449,12 @@ void FrameSequenceTracker::ReportFramePresented(
uint32_t impl_frames_ontime = 0;
uint32_t main_frames_ontime = 0;
- const auto& vsync_interval =
+ const auto vsync_interval =
(feedback.interval.is_zero() ? viz::BeginFrameArgs::DefaultInterval()
- : feedback.interval) *
- 1.5;
+ : feedback.interval);
DCHECK(!vsync_interval.is_zero()) << TRACKER_DCHECK_MSG;
base::TimeTicks safe_deadline_for_frame =
- last_frame_presentation_timestamp_ + vsync_interval;
+ last_frame_presentation_timestamp_ + vsync_interval * 1.5;
const bool was_presented = !feedback.failed();
if (was_presented && submitted_frame_since_last_presentation) {
@@ -470,7 +477,7 @@ void FrameSequenceTracker::ReportFramePresented(
}
metrics()->ComputeJank(FrameSequenceMetrics::ThreadType::kCompositor,
- frame_token, feedback.timestamp, feedback.interval);
+ frame_token, feedback.timestamp, vsync_interval);
}
if (was_presented) {
@@ -492,8 +499,7 @@ void FrameSequenceTracker::ReportFramePresented(
}
metrics()->ComputeJank(FrameSequenceMetrics::ThreadType::kMain,
- frame_token, feedback.timestamp,
- feedback.interval);
+ frame_token, feedback.timestamp, vsync_interval);
}
if (main_frames_.size() < size_before_erase) {
if (!last_frame_presentation_timestamp_.is_null() &&
diff --git a/chromium/cc/metrics/frame_sequence_tracker.h b/chromium/cc/metrics/frame_sequence_tracker.h
index 2c4fb649bb9..387a50b71f3 100644
--- a/chromium/cc/metrics/frame_sequence_tracker.h
+++ b/chromium/cc/metrics/frame_sequence_tracker.h
@@ -250,7 +250,6 @@ class CC_EXPORT FrameSequenceTracker {
// only when the last impl-frame is ended (ReportFrameEnd).
bool is_inside_frame_ = false;
-
#if DCHECK_IS_ON()
// This stringstream represents a sequence of frame reporting activities on
// the current tracker. Each letter can be one of the following:
diff --git a/chromium/cc/metrics/frame_sequence_tracker_collection.cc b/chromium/cc/metrics/frame_sequence_tracker_collection.cc
index 7d982152838..22c7941a8ac 100644
--- a/chromium/cc/metrics/frame_sequence_tracker_collection.cc
+++ b/chromium/cc/metrics/frame_sequence_tracker_collection.cc
@@ -363,7 +363,7 @@ void FrameSequenceTrackerCollection::RecreateTrackers(
}
ActiveFrameSequenceTrackers
-FrameSequenceTrackerCollection::FrameSequenceTrackerActiveTypes() {
+FrameSequenceTrackerCollection::FrameSequenceTrackerActiveTypes() const {
ActiveFrameSequenceTrackers encoded_types = 0;
for (const auto& key : frame_trackers_) {
auto thread_type = key.first.first;
diff --git a/chromium/cc/metrics/frame_sequence_tracker_collection.h b/chromium/cc/metrics/frame_sequence_tracker_collection.h
index d1b5fa53dd2..9761e937f47 100644
--- a/chromium/cc/metrics/frame_sequence_tracker_collection.h
+++ b/chromium/cc/metrics/frame_sequence_tracker_collection.h
@@ -105,7 +105,7 @@ class CC_EXPORT FrameSequenceTrackerCollection {
// Return the type of each active frame tracker, encoded into a 16 bit
// integer with the bit at each position corresponding to the enum value of
// each type.
- ActiveFrameSequenceTrackers FrameSequenceTrackerActiveTypes();
+ ActiveFrameSequenceTrackers FrameSequenceTrackerActiveTypes() const;
FrameSequenceTracker* GetRemovalTrackerForTesting(
FrameSequenceTrackerType type);
diff --git a/chromium/cc/metrics/frame_sequence_tracker_unittest.cc b/chromium/cc/metrics/frame_sequence_tracker_unittest.cc
index ba8f2b1f7e2..908b0edd950 100644
--- a/chromium/cc/metrics/frame_sequence_tracker_unittest.cc
+++ b/chromium/cc/metrics/frame_sequence_tracker_unittest.cc
@@ -353,6 +353,82 @@ TEST_F(FrameSequenceTrackerTest, TestNotifyFramePresented) {
EXPECT_EQ(NumberOfRemovalTrackers(), 0u);
}
+TEST_F(FrameSequenceTrackerTest, TestJankWithZeroIntervalInFeedback) {
+ // Test if jank can be correctly counted if presentation feedback reports
+ // zero frame interval.
+ const uint64_t source = 1;
+ uint64_t sequence = 1;
+ uint64_t frame_token = sequence;
+ const char* histogram_name =
+ "Graphics.Smoothness.Jank.Compositor.TouchScroll";
+ const base::TimeDelta zero_interval = base::TimeDelta::FromMilliseconds(0);
+ base::HistogramTester histogram_tester;
+
+ CreateNewTracker();
+ base::TimeTicks args_timestamp = base::TimeTicks::Now();
+ auto args = CreateBeginFrameArgs(source, sequence, args_timestamp);
+
+ // Frame 1
+ collection_.NotifyBeginImplFrame(args);
+ collection_.NotifySubmitFrame(sequence, false, viz::BeginFrameAck(args, true),
+ args);
+ collection_.NotifyFrameEnd(args, args);
+
+ collection_.NotifyFramePresented(
+ frame_token,
+ /*feedback=*/{args_timestamp, zero_interval, 0});
+
+ // Frame 2
+ ++sequence;
+ ++frame_token;
+ args_timestamp += base::TimeDelta::FromMillisecondsD(16.67);
+ args = CreateBeginFrameArgs(source, sequence, args_timestamp);
+ collection_.NotifyBeginImplFrame(args);
+ collection_.NotifySubmitFrame(sequence, false, viz::BeginFrameAck(args, true),
+ args);
+ collection_.NotifyFrameEnd(args, args);
+ collection_.NotifyFramePresented(
+ frame_token,
+ /*feedback=*/{args_timestamp, zero_interval, 0});
+
+ // Frame 3: There is one jank (frame interval incremented from 16.67ms
+ // to 30.0ms)
+ ++sequence;
+ ++frame_token;
+ args_timestamp += base::TimeDelta::FromMillisecondsD(30.0);
+ args = CreateBeginFrameArgs(source, sequence, args_timestamp);
+ collection_.NotifyBeginImplFrame(args);
+ collection_.NotifySubmitFrame(sequence, false, viz::BeginFrameAck(args, true),
+ args);
+ collection_.NotifyFrameEnd(args, args);
+ collection_.NotifyFramePresented(
+ frame_token,
+ /*feedback=*/{args_timestamp, zero_interval, 0});
+
+ // Frame 4: There is no jank since the increment from 30ms to 31ms is too
+ // small. This tests if |NotifyFramePresented| can correctly handle the
+ // situation when the frame interval reported in presentation feedback is 0.
+ ++sequence;
+ ++frame_token;
+ args_timestamp += base::TimeDelta::FromMillisecondsD(31.0);
+ args = CreateBeginFrameArgs(source, sequence, args_timestamp);
+ collection_.NotifyBeginImplFrame(args);
+ collection_.NotifySubmitFrame(sequence, false, viz::BeginFrameAck(args, true),
+ args);
+ collection_.NotifyFrameEnd(args, args);
+ collection_.NotifyFramePresented(
+ frame_token,
+ /*feedback=*/{args_timestamp, zero_interval, 0});
+ ImplThroughput().frames_expected = 100u;
+ ReportMetrics();
+ histogram_tester.ExpectTotalCount(
+ "Graphics.Smoothness.Jank.Compositor.TouchScroll", 1u);
+
+ // There should be only one jank for frame 3.
+ EXPECT_THAT(histogram_tester.GetAllSamples(histogram_name),
+ testing::ElementsAre(base::Bucket(1, 1)));
+}
+
// Base case for checkerboarding: present a single frame with checkerboarding,
// followed by a non-checkerboard frame.
TEST_F(FrameSequenceTrackerTest, CheckerboardingSimple) {
@@ -1641,9 +1717,10 @@ TEST_F(FrameSequenceTrackerTest, CustomTrackers) {
collection_.StopCustomSequence(2);
EXPECT_EQ(2u, NumberOfCustomTrackers());
- // Tracker 2 has no data to report.
+ // Tracker 2 has zero expected frames.
collection_.NotifyFramePresented(frame_token, {});
- EXPECT_EQ(0u, results.size());
+ EXPECT_EQ(1u, results.size());
+ EXPECT_EQ(0u, results[2].frames_expected);
// Simple sequence of one frame.
const char sequence[] = "b(1)B(0,1)s(1)S(1)e(1,0)P(1)";
@@ -1656,9 +1733,11 @@ TEST_F(FrameSequenceTrackerTest, CustomTrackers) {
// Tracker 1 and 3 and should report.
collection_.NotifyFramePresented(frame_token, {});
- EXPECT_EQ(2u, results.size());
+ EXPECT_EQ(3u, results.size());
EXPECT_EQ(1u, results[1].frames_produced);
EXPECT_EQ(1u, results[1].frames_expected);
+ EXPECT_EQ(0u, results[2].frames_produced);
+ EXPECT_EQ(0u, results[2].frames_expected);
EXPECT_EQ(1u, results[3].frames_produced);
EXPECT_EQ(1u, results[3].frames_expected);
}
diff --git a/chromium/cc/metrics/frame_sorter.cc b/chromium/cc/metrics/frame_sorter.cc
index 4b7990c75f2..c8c494f65f4 100644
--- a/chromium/cc/metrics/frame_sorter.cc
+++ b/chromium/cc/metrics/frame_sorter.cc
@@ -124,7 +124,7 @@ void FrameSorter::FlushFrames() {
DCHECK(!pending_frames_.empty());
size_t flushed_count = 0;
while (!pending_frames_.empty()) {
- const auto first = pending_frames_.front();
+ const auto& first = pending_frames_.front();
auto& frame_state = frame_states_[first.frame_id];
if (!frame_state.IsComplete())
break;
diff --git a/chromium/cc/metrics/jank_injector.cc b/chromium/cc/metrics/jank_injector.cc
new file mode 100644
index 00000000000..12c13e41cc5
--- /dev/null
+++ b/chromium/cc/metrics/jank_injector.cc
@@ -0,0 +1,176 @@
+// Copyright 2021 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/metrics/jank_injector.h"
+
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/debug/alias.h"
+#include "base/feature_list.h"
+#include "base/no_destructor.h"
+#include "base/strings/string_split.h"
+#include "base/trace_event/trace_event.h"
+#include "cc/base/features.h"
+#include "url/gurl.h"
+
+namespace cc {
+
+namespace {
+
+const char kJankInjectionAllowedURLs[] = "allowed_urls";
+const char kJankInjectionClusterSize[] = "cluster";
+const char kJankInjectionTargetPercent[] = "percent";
+
+struct JankInjectionParams {
+ JankInjectionParams() = default;
+ ~JankInjectionParams() = default;
+
+ JankInjectionParams(JankInjectionParams&&) = default;
+ JankInjectionParams& operator=(JankInjectionParams&&) = default;
+
+ JankInjectionParams(const JankInjectionParams&) = delete;
+ JankInjectionParams& operator=(const JankInjectionParams&) = delete;
+
+ // The jank injection code blocks the main thread for |jank_duration| amount
+ // of time.
+ base::TimeDelta jank_duration;
+
+ // When |busy_loop| is set, blocks the main thread in a busy loop for
+ // |jank_duration|. Otherwise, sleeps for |jank_duration|.
+ bool busy_loop = true;
+};
+
+bool IsJankInjectionEnabled() {
+ static bool enabled =
+ base::FeatureList::IsEnabled(features::kJankInjectionAblationFeature);
+ return enabled;
+}
+
+using AllowedURLsMap = std::map<std::string, std::vector<std::string>>;
+// Returns a map of <host, <list of paths>> pairs.
+AllowedURLsMap GetAllowedURLs() {
+ DCHECK(IsJankInjectionEnabled());
+ AllowedURLsMap urls;
+ std::string url_list = base::GetFieldTrialParamValueByFeature(
+ features::kJankInjectionAblationFeature, kJankInjectionAllowedURLs);
+ for (auto& it : base::SplitString(url_list, ",", base::TRIM_WHITESPACE,
+ base::SPLIT_WANT_ALL)) {
+ GURL url = GURL(it);
+ urls[url.host()].emplace_back(url.path());
+ }
+ return urls;
+}
+
+bool IsJankInjectionEnabledForURL(const GURL& url) {
+ DCHECK(IsJankInjectionEnabled());
+ static base::NoDestructor<AllowedURLsMap> allowed_urls(GetAllowedURLs());
+ if (allowed_urls->empty())
+ return false;
+
+ const auto iter = allowed_urls->find(url.host());
+ if (iter == allowed_urls->end())
+ return false;
+
+ const auto& paths = iter->second;
+ const auto& path = url.path_piece();
+ return paths.end() !=
+ std::find_if(paths.begin(), paths.end(), [path](const std::string& p) {
+ return base::StartsWith(path, p);
+ });
+}
+
+void RunJank(JankInjectionParams params) {
+ TRACE_EVENT0("cc,benchmark", "Injected Jank");
+ if (params.busy_loop) {
+ // Do some useless work, and prevent any weird compiler optimization from
+ // doing anything here.
+ base::TimeTicks start = base::TimeTicks::Now();
+ std::vector<base::TimeTicks> dummy;
+ while (base::TimeTicks::Now() - start < params.jank_duration) {
+ dummy.push_back(base::TimeTicks::Now());
+ if (dummy.size() > 100) {
+ dummy.erase(dummy.begin());
+ }
+ }
+ base::debug::Alias(&dummy);
+ } else {
+ base::PlatformThread::Sleep(params.jank_duration);
+ }
+}
+
+} // namespace
+
+JankInjector::JankInjector() {
+ if (IsJankInjectionEnabled()) {
+ config_.target_dropped_frames_percent =
+ base::GetFieldTrialParamByFeatureAsInt(
+ features::kJankInjectionAblationFeature,
+ kJankInjectionTargetPercent, config_.target_dropped_frames_percent);
+ config_.dropped_frame_cluster_size = base::GetFieldTrialParamByFeatureAsInt(
+ features::kJankInjectionAblationFeature, kJankInjectionClusterSize,
+ config_.dropped_frame_cluster_size);
+ }
+}
+
+JankInjector::~JankInjector() = default;
+
+bool JankInjector::IsEnabled(const GURL& url) {
+ return IsJankInjectionEnabled() && IsJankInjectionEnabledForURL(url);
+}
+
+void JankInjector::ScheduleJankIfNeeded(
+ const viz::BeginFrameArgs& args,
+ base::SingleThreadTaskRunner* task_runner) {
+ if (ShouldJankCurrentFrame(args)) {
+ ScheduleJank(args, task_runner);
+ did_jank_last_time_ = true;
+ } else {
+ ++total_frames_;
+ did_jank_last_time_ = false;
+ }
+}
+
+bool JankInjector::ShouldJankCurrentFrame(
+ const viz::BeginFrameArgs& args) const {
+ // If jank was injected during the previous frame, then do not inject jank
+ // again now.
+ if (did_jank_last_time_)
+ return false;
+
+ // Do not jank during the first frame.
+ if (!total_frames_)
+ return false;
+
+ auto current_jank = janked_frames_ * 100 / total_frames_;
+ // Do not drop any more frames if the injected jank is already above or at the
+ // target.
+ if (current_jank >= config_.target_dropped_frames_percent)
+ return false;
+
+ // If janking now makes the dropped the frames goes beyond the target, then do
+ // not inject the jank yet.
+ auto next_jank = (janked_frames_ + config_.dropped_frame_cluster_size) * 100 /
+ (total_frames_ + config_.dropped_frame_cluster_size);
+ if (next_jank > config_.target_dropped_frames_percent)
+ return false;
+
+ return true;
+}
+
+void JankInjector::ScheduleJank(const viz::BeginFrameArgs& args,
+ base::SingleThreadTaskRunner* task_runner) {
+ JankInjectionParams params;
+ params.jank_duration = config_.dropped_frame_cluster_size * args.interval;
+ params.busy_loop = true;
+ task_runner->PostTask(FROM_HERE, base::BindOnce(&RunJank, std::move(params)));
+
+ janked_frames_ += config_.dropped_frame_cluster_size;
+ total_frames_ += config_.dropped_frame_cluster_size;
+}
+
+} // namespace cc
diff --git a/chromium/cc/metrics/jank_injector.h b/chromium/cc/metrics/jank_injector.h
new file mode 100644
index 00000000000..b27bf2143c9
--- /dev/null
+++ b/chromium/cc/metrics/jank_injector.h
@@ -0,0 +1,56 @@
+// Copyright 2021 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_METRICS_JANK_INJECTOR_H_
+#define CC_METRICS_JANK_INJECTOR_H_
+
+#include <memory>
+
+#include "base/single_thread_task_runner.h"
+#include "cc/cc_export.h"
+#include "components/viz/common/frame_sinks/begin_frame_args.h"
+
+class GURL;
+
+namespace cc {
+
+class CC_EXPORT JankInjector {
+ public:
+ struct CC_EXPORT JankConfig {
+ uint32_t target_dropped_frames_percent = 10;
+
+ // How many consecutive frames to drop (when a frame is dropped).
+ uint32_t dropped_frame_cluster_size = 1;
+ };
+
+ // Jank injection.
+ JankInjector();
+ ~JankInjector();
+
+ JankInjector(const JankInjector&) = delete;
+ JankInjector& operator=(const JankInjector&) = delete;
+
+ static bool IsEnabled(const GURL& url);
+
+ void ScheduleJankIfNeeded(const viz::BeginFrameArgs& args,
+ base::SingleThreadTaskRunner* task_runner);
+
+ const JankConfig& config() const { return config_; }
+
+ private:
+ bool ShouldJankCurrentFrame(const viz::BeginFrameArgs& args) const;
+ void ScheduleJank(const viz::BeginFrameArgs& args,
+ base::SingleThreadTaskRunner* task_runner);
+ void SignalJank();
+
+ JankConfig config_;
+
+ uint64_t total_frames_ = 0;
+ uint64_t janked_frames_ = 0;
+ bool did_jank_last_time_ = false;
+};
+
+} // namespace cc
+
+#endif // CC_METRICS_JANK_INJECTOR_H_
diff --git a/chromium/cc/metrics/jank_injector_unittest.cc b/chromium/cc/metrics/jank_injector_unittest.cc
new file mode 100644
index 00000000000..cbc50ccf272
--- /dev/null
+++ b/chromium/cc/metrics/jank_injector_unittest.cc
@@ -0,0 +1,61 @@
+// Copyright 2021 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/metrics/jank_injector.h"
+
+#include <string>
+
+#include "base/test/scoped_feature_list.h"
+#include "base/test/test_simple_task_runner.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+class JankInjectorTest : public testing::Test {
+ public:
+ JankInjectorTest() = default;
+ ~JankInjectorTest() override = default;
+};
+
+TEST_F(JankInjectorTest, Basic) {
+ base::test::ScopedFeatureList features;
+ features.InitFromCommandLine("JankInjectionAblation:cluster/4/percent/10",
+ std::string());
+
+ scoped_refptr<base::TestSimpleTaskRunner> task_runner(
+ new base::TestSimpleTaskRunner());
+
+ JankInjector injector;
+ const auto& config = injector.config();
+ EXPECT_EQ(config.target_dropped_frames_percent, 10u);
+ EXPECT_EQ(config.dropped_frame_cluster_size, 4u);
+
+ const uint32_t kSourceId = 1;
+ uint32_t sequence_number = 1;
+ constexpr base::TimeDelta kInterval = base::TimeDelta::FromMilliseconds(16);
+ base::TimeTicks frame_time = base::TimeTicks::Now();
+ base::TimeTicks deadline = frame_time + kInterval;
+
+ auto args = viz::BeginFrameArgs::Create(
+ BEGINFRAME_FROM_HERE, kSourceId, ++sequence_number, frame_time, deadline,
+ kInterval, viz::BeginFrameArgs::NORMAL);
+ // For the first frame, no janks scheduled.
+ injector.ScheduleJankIfNeeded(args, task_runner.get());
+ EXPECT_FALSE(task_runner->HasPendingTask());
+
+ // Generate over 100 frames. This should cause jank to be injected 3 times.
+ for (uint32_t count = 0; count < 100; ++count) {
+ args.frame_time += kInterval;
+ args.deadline += kInterval;
+ ++args.frame_id.sequence_number;
+ injector.ScheduleJankIfNeeded(args, task_runner.get());
+ }
+
+ // Jank should be injected 3 times for the 100 frames.
+ EXPECT_EQ(task_runner->NumPendingTasks(), 3u);
+}
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/metrics/jank_metrics.cc b/chromium/cc/metrics/jank_metrics.cc
index b6237766c7e..8922e14f484 100644
--- a/chromium/cc/metrics/jank_metrics.cc
+++ b/chromium/cc/metrics/jank_metrics.cc
@@ -246,6 +246,14 @@ void JankMetrics::ReportJankMetrics(int frames_expected) {
GetMaxStaleHistogramName(tracker_type_), kStaleHistogramMin,
kStaleHistogramMax, kStaleHistogramBucketCount,
base::HistogramBase::kUmaTargetedHistogramFlag));
+
+ // Reset counts to avoid duplicated reporting.
+ Reset();
+}
+
+void JankMetrics::Reset() {
+ jank_count_ = 0;
+ max_staleness_ = {};
}
void JankMetrics::Merge(std::unique_ptr<JankMetrics> jank_metrics) {
diff --git a/chromium/cc/metrics/jank_metrics.h b/chromium/cc/metrics/jank_metrics.h
index 6fea8f00d5c..91ca7fa3d5c 100644
--- a/chromium/cc/metrics/jank_metrics.h
+++ b/chromium/cc/metrics/jank_metrics.h
@@ -31,6 +31,9 @@ class CC_EXPORT JankMetrics {
JankMetrics(const JankMetrics&) = delete;
JankMetrics& operator=(const JankMetrics&) = delete;
+ void AddFrameWithNoUpdate(uint32_t sequence_number,
+ base::TimeDelta frame_interval);
+
// Check if a jank occurs based on the timestamps of recent presentations.
// If there is a jank, increment |jank_count_| and log a trace event.
// Graphics.Smoothness.Stale.* metrics are reported in this function.
@@ -38,22 +41,24 @@ class CC_EXPORT JankMetrics {
base::TimeTicks current_presentation_timestamp,
base::TimeDelta frame_interval);
- // Report Graphics.Smoothness.(Jank|MaxStale).* metrics.
- void ReportJankMetrics(int frames_expected);
+ void AddSubmitFrame(uint32_t frame_token, uint32_t sequence_number);
// Merge the current jank count with a previously unreported jank metrics.
void Merge(std::unique_ptr<JankMetrics> jank_metrics);
- void AddSubmitFrame(uint32_t frame_token, uint32_t sequence_number);
+ // Report Graphics.Smoothness.(Jank|MaxStale).* metrics.
+ void ReportJankMetrics(int frames_expected);
- void AddFrameWithNoUpdate(uint32_t sequence_number,
- base::TimeDelta frame_interval);
+ // Reset the internal jank count
+ void Reset();
+
+ int jank_count() const { return jank_count_; }
+
+ base::TimeDelta max_staleness() const { return max_staleness_; }
FrameSequenceMetrics::ThreadType thread_type() const {
return effective_thread_;
}
- int jank_count() const { return jank_count_; }
-
private:
// The type of the tracker this JankMetrics object is attached to.
const FrameSequenceTrackerType tracker_type_;
diff --git a/chromium/cc/metrics/jank_metrics_unittest.cc b/chromium/cc/metrics/jank_metrics_unittest.cc
index b4c43bed2f1..dbc624e1ac5 100644
--- a/chromium/cc/metrics/jank_metrics_unittest.cc
+++ b/chromium/cc/metrics/jank_metrics_unittest.cc
@@ -415,8 +415,17 @@ TEST_F(JankMetricsTest, RAFMergeJanks) {
SimulateFrameSequence(other_reporter.get(), seqs);
jank_reporter.Merge(std::move(other_reporter));
+ EXPECT_EQ(jank_reporter.jank_count(), 6);
+ EXPECT_TRUE(
+ jank_reporter.max_staleness() > base::TimeDelta::FromMilliseconds(33) &&
+ jank_reporter.max_staleness() < base::TimeDelta::FromMilliseconds(34));
jank_reporter.ReportJankMetrics(100u);
+ // Jank / staleness values should be reset after reporting
+ EXPECT_EQ(jank_reporter.jank_count(), 0);
+ EXPECT_EQ(jank_reporter.max_staleness(),
+ base::TimeDelta::FromMilliseconds(0));
+
// Expect 6 janks for "Main" (3 from each reporter)
const char* metric = "Graphics.Smoothness.Jank.Main.RAF";
const char* invalid_metric = "Graphics.Smoothness.Jank.Compositor.RAF";
diff --git a/chromium/cc/metrics/latency_ukm_reporter.cc b/chromium/cc/metrics/latency_ukm_reporter.cc
index 02c884e0e03..da8144ec98e 100644
--- a/chromium/cc/metrics/latency_ukm_reporter.cc
+++ b/chromium/cc/metrics/latency_ukm_reporter.cc
@@ -89,22 +89,30 @@ void LatencyUkmReporter::ReportCompositorLatencyUkm(
CompositorFrameReporter::FrameReportType report_type,
const std::vector<CompositorFrameReporter::StageData>& stage_history,
const CompositorFrameReporter::ActiveTrackers& active_trackers,
- const viz::FrameTimingDetails& viz_breakdown) {
+ const CompositorFrameReporter::ProcessedBlinkBreakdown&
+ processed_blink_breakdown,
+ const CompositorFrameReporter::ProcessedVizBreakdown&
+ processed_viz_breakdown) {
if (ukm_manager_ &&
compositor_latency_sampling_controller_->ShouldRecordNextEvent()) {
- ukm_manager_->RecordCompositorLatencyUKM(report_type, stage_history,
- active_trackers, viz_breakdown);
+ ukm_manager_->RecordCompositorLatencyUKM(
+ report_type, stage_history, active_trackers, processed_blink_breakdown,
+ processed_viz_breakdown);
}
}
void LatencyUkmReporter::ReportEventLatencyUkm(
const EventMetrics::List& events_metrics,
const std::vector<CompositorFrameReporter::StageData>& stage_history,
- const viz::FrameTimingDetails& viz_breakdown) {
+ const CompositorFrameReporter::ProcessedBlinkBreakdown&
+ processed_blink_breakdown,
+ const CompositorFrameReporter::ProcessedVizBreakdown&
+ processed_viz_breakdown) {
if (ukm_manager_ &&
event_latency_sampling_controller_->ShouldRecordNextEvent()) {
ukm_manager_->RecordEventLatencyUKM(events_metrics, stage_history,
- viz_breakdown);
+ processed_blink_breakdown,
+ processed_viz_breakdown);
}
}
diff --git a/chromium/cc/metrics/latency_ukm_reporter.h b/chromium/cc/metrics/latency_ukm_reporter.h
index 3d2f96f6f9e..827890a845e 100644
--- a/chromium/cc/metrics/latency_ukm_reporter.h
+++ b/chromium/cc/metrics/latency_ukm_reporter.h
@@ -11,7 +11,6 @@
#include "cc/cc_export.h"
#include "cc/metrics/compositor_frame_reporter.h"
#include "cc/metrics/event_metrics.h"
-#include "components/viz/common/frame_timing_details.h"
namespace cc {
class UkmManager;
@@ -30,12 +29,18 @@ class CC_EXPORT LatencyUkmReporter {
CompositorFrameReporter::FrameReportType report_type,
const std::vector<CompositorFrameReporter::StageData>& stage_history,
const CompositorFrameReporter::ActiveTrackers& active_trackers,
- const viz::FrameTimingDetails& viz_breakdown);
+ const CompositorFrameReporter::ProcessedBlinkBreakdown&
+ processed_blink_breakdown,
+ const CompositorFrameReporter::ProcessedVizBreakdown&
+ processed_viz_breakdown);
void ReportEventLatencyUkm(
const EventMetrics::List& events_metrics,
const std::vector<CompositorFrameReporter::StageData>& stage_history,
- const viz::FrameTimingDetails& viz_breakdown);
+ const CompositorFrameReporter::ProcessedBlinkBreakdown&
+ processed_blink_breakdown,
+ const CompositorFrameReporter::ProcessedVizBreakdown&
+ processed_viz_breakdown);
void set_ukm_manager(UkmManager* manager) { ukm_manager_ = manager; }
diff --git a/chromium/cc/metrics/shared_metrics_buffer.h b/chromium/cc/metrics/shared_metrics_buffer.h
new file mode 100644
index 00000000000..5167a7715a6
--- /dev/null
+++ b/chromium/cc/metrics/shared_metrics_buffer.h
@@ -0,0 +1,46 @@
+// Copyright 2021 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_METRICS_SHARED_METRICS_BUFFER_H_
+#define CC_METRICS_SHARED_METRICS_BUFFER_H_
+
+#include "device/base/synchronization/one_writer_seqlock.h"
+
+namespace cc {
+// The struct written in shared memory to transport metrics across
+// processes. |data| is protected by the sequence-lock |seq_lock|.
+// Note: This template copies data between processes. Any class that uses this
+// template would need security review.
+template <class T>
+struct SharedMetricsBuffer {
+ device::OneWriterSeqLock seq_lock;
+ T data;
+ static_assert(std::is_trivially_copyable<T>::value,
+ "Metrics shared across processes need to be trivially "
+ "copyable, otherwise it is dangerous to copy it.");
+
+ bool Read(T& out) const {
+ const uint32_t kMaxRetries = 5;
+ uint32_t retries = 0;
+ base::subtle::Atomic32 version;
+ do {
+ const uint32_t kMaxReadAttempts = 32;
+ version = seq_lock.ReadBegin(kMaxReadAttempts);
+ device::OneWriterSeqLock::AtomicReaderMemcpy(&out, &data, sizeof(T));
+ } while (seq_lock.ReadRetry(version) && ++retries < kMaxRetries);
+
+ // Consider the number of retries less than kMaxRetries as success.
+ return retries < kMaxRetries;
+ }
+
+ void Write(const T& in) {
+ seq_lock.WriteBegin();
+ device::OneWriterSeqLock::AtomicWriterMemcpy(&data, &in, sizeof(T));
+ seq_lock.WriteEnd();
+ }
+};
+
+} // namespace cc
+
+#endif // CC_METRICS_SHARED_METRICS_BUFFER_H_
diff --git a/chromium/cc/metrics/ukm_smoothness_data.h b/chromium/cc/metrics/ukm_smoothness_data.h
index 2bb5118cd1b..eb74020c249 100644
--- a/chromium/cc/metrics/ukm_smoothness_data.h
+++ b/chromium/cc/metrics/ukm_smoothness_data.h
@@ -5,7 +5,7 @@
#ifndef CC_METRICS_UKM_SMOOTHNESS_DATA_H_
#define CC_METRICS_UKM_SMOOTHNESS_DATA_H_
-#include "device/base/synchronization/one_writer_seqlock.h"
+#include "cc/metrics/shared_metrics_buffer.h"
namespace cc {
@@ -17,14 +17,10 @@ struct UkmSmoothnessData {
double worst_smoothness = 0.0;
double above_threshold = 0.0;
double percentile_95 = 0.0;
+ base::TimeDelta time_max_delta = base::TimeDelta::FromMilliseconds(1);
};
-// The struct written in shared memory to transport UkmSmoothnessData across
-// processes. |data| is protected by the sequence-lock |seq_lock|.
-struct UkmSmoothnessDataShared {
- device::OneWriterSeqLock seq_lock;
- struct UkmSmoothnessData data;
-};
+using UkmSmoothnessDataShared = SharedMetricsBuffer<UkmSmoothnessData>;
} // namespace cc
diff --git a/chromium/cc/metrics/video_playback_roughness_reporter.cc b/chromium/cc/metrics/video_playback_roughness_reporter.cc
index 69474ed3080..33ef9c517be 100644
--- a/chromium/cc/metrics/video_playback_roughness_reporter.cc
+++ b/chromium/cc/metrics/video_playback_roughness_reporter.cc
@@ -59,11 +59,11 @@ void VideoPlaybackRoughnessReporter::FrameSubmitted(
FrameInfo info;
info.token = token;
- info.decode_time = frame.metadata()->decode_end_time;
+ info.decode_time = frame.metadata().decode_end_time;
info.refresh_rate_hz = int{std::round(1.0 / render_interval.InSecondsF())};
info.size = frame.natural_size();
- info.intended_duration = frame.metadata()->wallclock_frame_duration;
+ info.intended_duration = frame.metadata().wallclock_frame_duration;
if (info.intended_duration) {
if (render_interval > info.intended_duration.value()) {
// In videos with FPS higher than display refresh rate we acknowledge
diff --git a/chromium/cc/metrics/video_playback_roughness_reporter_unittest.cc b/chromium/cc/metrics/video_playback_roughness_reporter_unittest.cc
index f028506c2be..ffe36027105 100644
--- a/chromium/cc/metrics/video_playback_roughness_reporter_unittest.cc
+++ b/chromium/cc/metrics/video_playback_roughness_reporter_unittest.cc
@@ -39,7 +39,7 @@ class VideoPlaybackRoughnessReporterTest : public ::testing::Test {
int frame_size = 100) {
scoped_refptr<VideoFrame> result = media::VideoFrame::CreateColorFrame(
gfx::Size(frame_size, frame_size), 0x80, 0x80, 0x80, base::TimeDelta());
- result->metadata()->wallclock_frame_duration = duration;
+ result->metadata().wallclock_frame_duration = duration;
return result;
}
diff --git a/chromium/cc/metrics/web_vital_metrics.cc b/chromium/cc/metrics/web_vital_metrics.cc
new file mode 100644
index 00000000000..1bb822de2dc
--- /dev/null
+++ b/chromium/cc/metrics/web_vital_metrics.cc
@@ -0,0 +1,13 @@
+// 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.
+
+#include "cc/metrics/web_vital_metrics.h"
+
+namespace cc {
+
+constexpr WebVitalMetrics::MetricsInfo WebVitalMetrics::lcp_info;
+constexpr WebVitalMetrics::MetricsInfo WebVitalMetrics::fid_info;
+constexpr WebVitalMetrics::MetricsInfo WebVitalMetrics::cls_info;
+
+} // namespace cc
diff --git a/chromium/cc/metrics/web_vital_metrics.h b/chromium/cc/metrics/web_vital_metrics.h
new file mode 100644
index 00000000000..35b46b41268
--- /dev/null
+++ b/chromium/cc/metrics/web_vital_metrics.h
@@ -0,0 +1,56 @@
+// 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_METRICS_WEB_VITAL_METRICS_H_
+#define CC_METRICS_WEB_VITAL_METRICS_H_
+
+#include <string>
+
+#include "base/time/time.h"
+#include "cc/cc_export.h"
+
+namespace cc {
+
+// Web Vital metrics reported from blink to be displayed with cc's HUD display.
+struct CC_EXPORT WebVitalMetrics {
+ bool has_lcp = false;
+ base::TimeDelta largest_contentful_paint;
+ bool has_fid = false;
+ base::TimeDelta first_input_delay;
+ bool has_cls = false;
+ double layout_shift = 0.f;
+
+ WebVitalMetrics() = default;
+ WebVitalMetrics(const WebVitalMetrics& other) = default;
+
+ bool HasValue() const { return has_lcp || has_fid || has_cls; }
+
+ struct MetricsInfo {
+ double green_threshold;
+ double yellow_threshold;
+ enum Unit { kSecond, kMillisecond, kScore };
+ Unit unit;
+ std::string UnitToString() const {
+ switch (unit) {
+ case Unit::kSecond:
+ return " s";
+ case Unit::kMillisecond:
+ return " ms";
+ case Unit::kScore:
+ default:
+ return "";
+ }
+ }
+ };
+ static constexpr MetricsInfo lcp_info = {
+ 2.5f, 4.f, WebVitalMetrics::MetricsInfo::Unit::kSecond};
+ static constexpr MetricsInfo fid_info = {
+ 100, 300, WebVitalMetrics::MetricsInfo::Unit::kMillisecond};
+ static constexpr MetricsInfo cls_info = {
+ 0.1f, 0.25f, WebVitalMetrics::MetricsInfo::Unit::kScore};
+};
+
+} // namespace cc
+
+#endif // CC_METRICS_WEB_VITAL_METRICS_H_
diff --git a/chromium/cc/mojo_embedder/BUILD.gn b/chromium/cc/mojo_embedder/BUILD.gn
index 63e0725c502..99b982c602f 100644
--- a/chromium/cc/mojo_embedder/BUILD.gn
+++ b/chromium/cc/mojo_embedder/BUILD.gn
@@ -16,6 +16,7 @@ cc_component("mojo_embedder") {
deps = [
"//base",
"//cc",
+ "//components/power_scheduler",
"//components/viz/client",
"//components/viz/common",
"//mojo/public/cpp/bindings",
diff --git a/chromium/cc/mojo_embedder/DEPS b/chromium/cc/mojo_embedder/DEPS
index 325a68db50a..3006227caf0 100644
--- a/chromium/cc/mojo_embedder/DEPS
+++ b/chromium/cc/mojo_embedder/DEPS
@@ -1,4 +1,5 @@
include_rules = [
+ "+components/power_scheduler",
"+mojo/public/cpp/bindings",
"+services/viz/public/mojom/compositing",
]
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 452bb7371a9..467fac7f00f 100644
--- a/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.cc
+++ b/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.cc
@@ -13,6 +13,9 @@
#include "base/trace_event/trace_event.h"
#include "cc/base/histograms.h"
#include "cc/trees/layer_tree_frame_sink_client.h"
+#include "components/power_scheduler/power_mode.h"
+#include "components/power_scheduler/power_mode_arbiter.h"
+#include "components/power_scheduler/power_mode_voter.h"
#include "components/viz/common/features.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
#include "components/viz/common/hit_test/hit_test_region_list.h"
@@ -47,8 +50,10 @@ AsyncLayerTreeFrameSink::AsyncLayerTreeFrameSink(
synthetic_begin_frame_source_(
std::move(params->synthetic_begin_frame_source)),
pipes_(std::move(params->pipes)),
- wants_animate_only_begin_frames_(
- params->wants_animate_only_begin_frames) {
+ wants_animate_only_begin_frames_(params->wants_animate_only_begin_frames),
+ animation_power_mode_voter_(
+ power_scheduler::PowerModeArbiter::GetInstance()->NewVoter(
+ "PowerModeVoter.Animation")) {
DETACH_FROM_THREAD(thread_checker_);
}
@@ -123,11 +128,12 @@ void AsyncLayerTreeFrameSink::SubmitCompositorFrame(
DCHECK(frame.metadata.begin_frame_ack.has_damage);
DCHECK(frame.metadata.begin_frame_ack.frame_id.IsSequenceValid());
- TRACE_EVENT_WITH_FLOW1(
+ TRACE_EVENT_WITH_FLOW2(
"viz,benchmark", "Graphics.Pipeline",
TRACE_ID_GLOBAL(frame.metadata.begin_frame_ack.trace_id),
TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "step",
- "SubmitCompositorFrame");
+ "SubmitCompositorFrame", "local_surface_id",
+ local_surface_id_.ToString());
if (local_surface_id_ == last_submitted_local_surface_id_) {
DCHECK_EQ(last_submitted_device_scale_factor_, frame.device_scale_factor());
@@ -274,10 +280,15 @@ void AsyncLayerTreeFrameSink::ReclaimResources(
void AsyncLayerTreeFrameSink::OnNeedsBeginFrames(bool needs_begin_frames) {
DCHECK(compositor_frame_sink_ptr_);
if (needs_begin_frames_ != needs_begin_frames) {
- if (needs_begin_frames_) {
- TRACE_EVENT_ASYNC_END0("cc,benchmark", "NeedsBeginFrames", this);
+ if (needs_begin_frames) {
+ TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("cc,benchmark", "NeedsBeginFrames",
+ this);
+ animation_power_mode_voter_->VoteFor(
+ power_scheduler::PowerMode::kAnimation);
} else {
- TRACE_EVENT_ASYNC_BEGIN0("cc,benchmark", "NeedsBeginFrames", this);
+ TRACE_EVENT_NESTABLE_ASYNC_END0("cc,benchmark", "NeedsBeginFrames", this);
+ animation_power_mode_voter_->ResetVoteAfterTimeout(
+ power_scheduler::PowerModeVoter::kAnimationTimeout);
}
}
needs_begin_frames_ = needs_begin_frames;
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 7bfcf4680e6..c7efb10500a 100644
--- a/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.h
+++ b/chromium/cc/mojo_embedder/async_layer_tree_frame_sink.h
@@ -14,6 +14,7 @@
#include "base/single_thread_task_runner.h"
#include "cc/mojo_embedder/mojo_embedder_export.h"
#include "cc/trees/layer_tree_frame_sink.h"
+#include "components/power_scheduler/power_mode_voter.h"
#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "components/viz/common/frame_timing_details_map.h"
#include "components/viz/common/gpu/context_provider.h"
@@ -140,6 +141,8 @@ class CC_MOJO_EMBEDDER_EXPORT AsyncLayerTreeFrameSink
float last_submitted_device_scale_factor_ = 1.f;
gfx::Size last_submitted_size_in_pixels_;
+ std::unique_ptr<power_scheduler::PowerModeVoter> animation_power_mode_voter_;
+
base::WeakPtrFactory<AsyncLayerTreeFrameSink> weak_factory_{this};
};
diff --git a/chromium/cc/mojom/BUILD.gn b/chromium/cc/mojom/BUILD.gn
index 1cf5167d715..fc4ab95cb54 100644
--- a/chromium/cc/mojom/BUILD.gn
+++ b/chromium/cc/mojom/BUILD.gn
@@ -23,6 +23,7 @@ mojom("mojom") {
generate_java = true
sources = [
"browser_controls_params.mojom",
+ "browser_controls_state.mojom",
"overscroll_behavior.mojom",
"render_frame_metadata.mojom",
"touch_action.mojom",
@@ -42,6 +43,16 @@ mojom("mojom") {
{
types = [
{
+ mojom = "cc.mojom.BrowserControlsState"
+ cpp = "::cc::BrowserControlsState"
+ },
+ ]
+ traits_headers = [ "//cc/ipc/cc_param_traits_macros.h" ]
+ traits_public_deps = [ "//cc/ipc" ]
+ },
+ {
+ types = [
+ {
mojom = "cc.mojom.TouchAction"
cpp = "::cc::TouchAction"
},
diff --git a/chromium/cc/mojom/browser_controls_state.mojom b/chromium/cc/mojom/browser_controls_state.mojom
new file mode 100644
index 00000000000..d4f396cd67f
--- /dev/null
+++ b/chromium/cc/mojom/browser_controls_state.mojom
@@ -0,0 +1,8 @@
+// Copyright 2019 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.
+
+module cc.mojom;
+
+[Native]
+enum BrowserControlsState;
diff --git a/chromium/cc/mojom/render_frame_metadata.mojom b/chromium/cc/mojom/render_frame_metadata.mojom
index 2db01c54bb6..3a087f778cd 100644
--- a/chromium/cc/mojom/render_frame_metadata.mojom
+++ b/chromium/cc/mojom/render_frame_metadata.mojom
@@ -10,6 +10,18 @@ import "services/viz/public/mojom/compositing/selection.mojom";
import "services/viz/public/mojom/compositing/vertical_scroll_direction.mojom";
import "ui/gfx/geometry/mojom/geometry.mojom";
+// Contains information to assist in making a decision about forwarding
+// pointerevents to viz for use in a delegated ink trail.
+struct DelegatedInkBrowserMetadata {
+ // Flag used to indicate the state of the hovering on the pointerevent that
+ // the delegated ink metadata was created from. If this state does not match
+ // the point under consideration to send to viz, it won't be sent. As soon
+ // as it matches again the point will be sent, regardless of if the renderer
+ // has processed the point that didn't match yet or not. It is true when
+ // hovering, false otherwise.
+ bool delegated_ink_is_hovering;
+};
+
// See components/viz/service/quads/render_frame_metadata.h
struct RenderFrameMetadata {
// The background color of a CompositorFrame. It can be used for filling the
@@ -36,10 +48,12 @@ struct RenderFrameMetadata {
// are the same).
bool is_mobile_optimized;
- // Flag used to notify the browser process to start or stop forwarding points
- // to viz for use in a delegated ink trail. True the entire time points should
- // be forwarded, and forwarding stops as soon as it is false again.
- bool has_delegated_ink_metadata;
+ // Existence of this flag informs the browser process to start forwarding
+ // points to viz for use in a delegated ink trail. It contains more
+ // information to be used in making the forwarding decision. It exists the
+ // entire time points could be forwarded, and forwarding must stop as soon as
+ // it is null.
+ DelegatedInkBrowserMetadata? delegated_ink_metadata;
// The device scale factor used to generate CompositorFrame.
float device_scale_factor;
diff --git a/chromium/cc/mojom/render_frame_metadata_mojom_traits.cc b/chromium/cc/mojom/render_frame_metadata_mojom_traits.cc
index dd89563e802..b9eecfbf56d 100644
--- a/chromium/cc/mojom/render_frame_metadata_mojom_traits.cc
+++ b/chromium/cc/mojom/render_frame_metadata_mojom_traits.cc
@@ -14,6 +14,15 @@
namespace mojo {
// static
+bool StructTraits<cc::mojom::DelegatedInkBrowserMetadataDataView,
+ cc::DelegatedInkBrowserMetadata>::
+ Read(cc::mojom::DelegatedInkBrowserMetadataDataView data,
+ cc::DelegatedInkBrowserMetadata* out) {
+ out->delegated_ink_is_hovering = data.delegated_ink_is_hovering();
+ return true;
+}
+
+// static
bool StructTraits<
cc::mojom::RenderFrameMetadataDataView,
cc::RenderFrameMetadata>::Read(cc::mojom::RenderFrameMetadataDataView data,
@@ -21,7 +30,6 @@ bool StructTraits<
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->has_delegated_ink_metadata = data.has_delegated_ink_metadata();
out->device_scale_factor = data.device_scale_factor();
out->page_scale_factor = data.page_scale_factor();
out->external_page_scale_factor = data.external_page_scale_factor();
@@ -40,6 +48,7 @@ bool StructTraits<
#endif
return data.ReadRootScrollOffset(&out->root_scroll_offset) &&
data.ReadSelection(&out->selection) &&
+ data.ReadDelegatedInkMetadata(&out->delegated_ink_metadata) &&
#if defined(OS_ANDROID)
data.ReadScrollableViewportSize(&out->scrollable_viewport_size) &&
data.ReadRootLayerSize(&out->root_layer_size) &&
diff --git a/chromium/cc/mojom/render_frame_metadata_mojom_traits.h b/chromium/cc/mojom/render_frame_metadata_mojom_traits.h
index ed13705d80c..66a3e7e5e19 100644
--- a/chromium/cc/mojom/render_frame_metadata_mojom_traits.h
+++ b/chromium/cc/mojom/render_frame_metadata_mojom_traits.h
@@ -17,6 +17,19 @@ namespace mojo {
template <>
struct COMPONENT_EXPORT(CC_SHARED_MOJOM_TRAITS)
+ StructTraits<cc::mojom::DelegatedInkBrowserMetadataDataView,
+ cc::DelegatedInkBrowserMetadata> {
+ static bool delegated_ink_is_hovering(
+ const cc::DelegatedInkBrowserMetadata& metadata) {
+ return metadata.delegated_ink_is_hovering;
+ }
+
+ static bool Read(cc::mojom::DelegatedInkBrowserMetadataDataView data,
+ cc::DelegatedInkBrowserMetadata* out);
+};
+
+template <>
+struct COMPONENT_EXPORT(CC_SHARED_MOJOM_TRAITS)
StructTraits<cc::mojom::RenderFrameMetadataDataView,
cc::RenderFrameMetadata> {
static SkColor root_background_color(
@@ -42,9 +55,9 @@ struct COMPONENT_EXPORT(CC_SHARED_MOJOM_TRAITS)
return metadata.is_mobile_optimized;
}
- static bool has_delegated_ink_metadata(
+ static base::Optional<cc::DelegatedInkBrowserMetadata> delegated_ink_metadata(
const cc::RenderFrameMetadata& metadata) {
- return metadata.has_delegated_ink_metadata;
+ return metadata.delegated_ink_metadata;
}
static float device_scale_factor(const cc::RenderFrameMetadata& metadata) {
diff --git a/chromium/cc/paint/decoded_draw_image.cc b/chromium/cc/paint/decoded_draw_image.cc
index 9111136214f..8cc94f1de24 100644
--- a/chromium/cc/paint/decoded_draw_image.cc
+++ b/chromium/cc/paint/decoded_draw_image.cc
@@ -2,29 +2,32 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <utility>
-
#include "cc/paint/decoded_draw_image.h"
+#include <utility>
+
namespace cc {
DecodedDrawImage::DecodedDrawImage(sk_sp<const SkImage> image,
sk_sp<SkColorFilter> dark_mode_color_filter,
const SkSize& src_rect_offset,
const SkSize& scale_adjustment,
- SkFilterQuality filter_quality)
+ SkFilterQuality filter_quality,
+ bool is_budgeted)
: image_(std::move(image)),
dark_mode_color_filter_(std::move(dark_mode_color_filter)),
src_rect_offset_(src_rect_offset),
scale_adjustment_(scale_adjustment),
- filter_quality_(filter_quality) {}
+ filter_quality_(filter_quality),
+ is_budgeted_(is_budgeted) {}
DecodedDrawImage::DecodedDrawImage(const gpu::Mailbox& mailbox,
SkFilterQuality filter_quality)
: mailbox_(mailbox),
src_rect_offset_(SkSize::MakeEmpty()),
scale_adjustment_(SkSize::Make(1.f, 1.f)),
- filter_quality_(filter_quality) {}
+ filter_quality_(filter_quality),
+ is_budgeted_(true) {}
DecodedDrawImage::DecodedDrawImage(
base::Optional<uint32_t> transfer_cache_entry_id,
@@ -32,20 +35,23 @@ DecodedDrawImage::DecodedDrawImage(
const SkSize& src_rect_offset,
const SkSize& scale_adjustment,
SkFilterQuality filter_quality,
- bool needs_mips)
+ bool needs_mips,
+ bool is_budgeted)
: transfer_cache_entry_id_(transfer_cache_entry_id),
dark_mode_color_filter_(std::move(dark_mode_color_filter)),
src_rect_offset_(src_rect_offset),
scale_adjustment_(scale_adjustment),
filter_quality_(filter_quality),
- transfer_cache_entry_needs_mips_(needs_mips) {}
+ transfer_cache_entry_needs_mips_(needs_mips),
+ is_budgeted_(is_budgeted) {}
DecodedDrawImage::DecodedDrawImage()
: DecodedDrawImage(nullptr,
nullptr,
SkSize::MakeEmpty(),
SkSize::Make(1.f, 1.f),
- kNone_SkFilterQuality) {}
+ kNone_SkFilterQuality,
+ true) {}
DecodedDrawImage::DecodedDrawImage(const DecodedDrawImage&) = default;
DecodedDrawImage::DecodedDrawImage(DecodedDrawImage&&) = default;
diff --git a/chromium/cc/paint/decoded_draw_image.h b/chromium/cc/paint/decoded_draw_image.h
index bde0f431033..e00bfeebcb4 100644
--- a/chromium/cc/paint/decoded_draw_image.h
+++ b/chromium/cc/paint/decoded_draw_image.h
@@ -30,14 +30,16 @@ class CC_PAINT_EXPORT DecodedDrawImage {
sk_sp<SkColorFilter> dark_mode_color_filter,
const SkSize& src_rect_offset,
const SkSize& scale_adjustment,
- SkFilterQuality filter_quality);
+ SkFilterQuality filter_quality,
+ bool is_budgeted);
DecodedDrawImage(const gpu::Mailbox& mailbox, SkFilterQuality filter_quality);
DecodedDrawImage(base::Optional<uint32_t> transfer_cache_entry_id,
sk_sp<SkColorFilter> dark_mode_color_filter,
const SkSize& src_rect_offset,
const SkSize& scale_adjustment,
SkFilterQuality filter_quality,
- bool needs_mips);
+ bool needs_mips,
+ bool is_budgeted);
DecodedDrawImage(const DecodedDrawImage& other);
DecodedDrawImage(DecodedDrawImage&& other);
DecodedDrawImage& operator=(const DecodedDrawImage&);
@@ -63,6 +65,7 @@ class CC_PAINT_EXPORT DecodedDrawImage {
bool transfer_cache_entry_needs_mips() const {
return transfer_cache_entry_needs_mips_;
}
+ bool is_budgeted() const { return is_budgeted_; }
const gpu::Mailbox& mailbox() const { return mailbox_; }
explicit operator bool() const {
return image_ || transfer_cache_entry_id_ || !mailbox_.IsZero();
@@ -77,6 +80,7 @@ class CC_PAINT_EXPORT DecodedDrawImage {
SkSize scale_adjustment_;
SkFilterQuality filter_quality_;
bool transfer_cache_entry_needs_mips_ = false;
+ bool is_budgeted_;
};
} // namespace cc
diff --git a/chromium/cc/paint/discardable_image_map.cc b/chromium/cc/paint/discardable_image_map.cc
index c0ed8173d38..c5418313e8a 100644
--- a/chromium/cc/paint/discardable_image_map.cc
+++ b/chromium/cc/paint/discardable_image_map.cc
@@ -96,7 +96,7 @@ class DiscardableImageGenerator {
// Prevent PaintOpBuffers from having side effects back into the canvas.
SkAutoCanvasRestore save_restore(canvas, true);
- PlaybackParams params(nullptr, canvas->getTotalMatrix());
+ PlaybackParams params(nullptr, canvas->getLocalToDevice());
// TODO(khushalsagar): Optimize out save/restore blocks if there are no
// images in the draw ops between them.
for (auto* op : PaintOpBuffer::Iterator(buffer)) {
@@ -139,10 +139,8 @@ class DiscardableImageGenerator {
op_rect, ctm, image_op->flags.getFilterQuality());
} else if (op_type == PaintOpType::DrawImageRect) {
auto* image_rect_op = static_cast<DrawImageRectOp*>(op);
- SkMatrix matrix = ctm;
- matrix.postConcat(SkMatrix::MakeRectToRect(image_rect_op->src,
- image_rect_op->dst,
- SkMatrix::kFill_ScaleToFit));
+ SkMatrix matrix =
+ SkMatrix::RectToRect(image_rect_op->src, image_rect_op->dst) * ctm;
AddImage(image_rect_op->image,
image_rect_op->flags.useDarkModeForImage(), image_rect_op->src,
op_rect, matrix, image_rect_op->flags.getFilterQuality());
@@ -196,8 +194,7 @@ class DiscardableImageGenerator {
SkNoDrawCanvas canvas(scaled_tile_rect.width(),
scaled_tile_rect.height());
- canvas.setMatrix(SkMatrix::MakeRectToRect(
- shader->tile(), scaled_tile_rect, SkMatrix::kFill_ScaleToFit));
+ canvas.setMatrix(SkMatrix::RectToRect(shader->tile(), scaled_tile_rect));
base::AutoReset<bool> auto_reset(&only_gather_animated_images_, true);
size_t prev_image_set_size = image_set_.size();
GatherDiscardableImages(shader->paint_record().get(), &op_rect, &canvas);
diff --git a/chromium/cc/paint/discardable_image_map_unittest.cc b/chromium/cc/paint/discardable_image_map_unittest.cc
index 4675f2989bc..1b217d8e9c3 100644
--- a/chromium/cc/paint/discardable_image_map_unittest.cc
+++ b/chromium/cc/paint/discardable_image_map_unittest.cc
@@ -47,7 +47,7 @@ struct PositionScaleDrawImage {
sk_sp<PaintOpBuffer> CreateRecording(const PaintImage& discardable_image,
const gfx::Rect& visible_rect) {
auto buffer = sk_make_sp<PaintOpBuffer>();
- buffer->push<DrawImageOp>(discardable_image, 0.f, 0.f, nullptr);
+ buffer->push<DrawImageOp>(discardable_image, 0.f, 0.f);
return buffer;
}
@@ -122,10 +122,8 @@ TEST_F(DiscardableImageMapTest, GetDiscardableImagesInRectTest) {
if ((x + y) & 1) {
discardable_image[y][x] =
CreateDiscardablePaintImage(gfx::Size(500, 500));
- PaintFlags flags;
content_layer_client.add_draw_image(
- discardable_image[y][x], gfx::Point(x * 512 + 6, y * 512 + 6),
- flags);
+ discardable_image[y][x], gfx::Point(x * 512 + 6, y * 512 + 6));
}
}
}
@@ -194,10 +192,9 @@ TEST_F(DiscardableImageMapTest, GetDiscardableImagesInRectNonZeroLayer) {
if ((x + y) & 1) {
discardable_image[y][x] =
CreateDiscardablePaintImage(gfx::Size(500, 500));
- PaintFlags flags;
content_layer_client.add_draw_image(
discardable_image[y][x],
- gfx::Point(1024 + x * 512 + 6, y * 512 + 6), flags);
+ gfx::Point(1024 + x * 512 + 6, y * 512 + 6));
}
}
}
@@ -295,10 +292,8 @@ TEST_F(DiscardableImageMapTest, GetDiscardableImagesInRectOnePixelQuery) {
if ((x + y) & 1) {
discardable_image[y][x] =
CreateDiscardablePaintImage(gfx::Size(500, 500));
- PaintFlags flags;
content_layer_client.add_draw_image(
- discardable_image[y][x], gfx::Point(x * 512 + 6, y * 512 + 6),
- flags);
+ discardable_image[y][x], gfx::Point(x * 512 + 6, y * 512 + 6));
}
}
}
@@ -334,9 +329,7 @@ TEST_F(DiscardableImageMapTest, GetDiscardableImagesInRectMassiveImage) {
PaintImage discardable_image =
CreateDiscardablePaintImage(gfx::Size(1 << 25, 1 << 25), nullptr,
false /* allocate_encoded_memory */);
- PaintFlags flags;
- content_layer_client.add_draw_image(discardable_image, gfx::Point(0, 0),
- flags);
+ content_layer_client.add_draw_image(discardable_image, gfx::Point(0, 0));
scoped_refptr<DisplayItemList> display_list =
content_layer_client.PaintContentsToDisplayList();
@@ -416,13 +409,13 @@ TEST_F(DiscardableImageMapTest, RestoreSavedTransformedLayers) {
PaintImage discardable_image3 =
CreateDiscardablePaintImage(gfx::Size(25, 25));
display_list->push<TranslateOp>(25, 25);
- display_list->push<DrawImageOp>(discardable_image1, 0.f, 0.f, nullptr);
+ display_list->push<DrawImageOp>(discardable_image1, 0.f, 0.f);
display_list->push<SaveLayerOp>(nullptr, &paint);
display_list->push<TranslateOp>(100, 100);
- display_list->push<DrawImageOp>(discardable_image2, 0.f, 0.f, nullptr);
+ display_list->push<DrawImageOp>(discardable_image2, 0.f, 0.f);
display_list->push<RestoreOp>();
display_list->push<TranslateOp>(0, 100);
- display_list->push<DrawImageOp>(discardable_image3, 0.f, 0.f, nullptr);
+ display_list->push<DrawImageOp>(discardable_image3, 0.f, 0.f);
display_list->EndPaintOfUnpaired(visible_rect);
display_list->Finalize();
@@ -471,9 +464,7 @@ TEST_F(DiscardableImageMapTest, GetDiscardableImagesInRectMaxImage) {
PaintImage discardable_image = CreateDiscardablePaintImage(
gfx::Size(dimension, dimension), no_color_space,
false /* allocate_encoded_memory */);
- PaintFlags flags;
- content_layer_client.add_draw_image(discardable_image, gfx::Point(42, 42),
- flags);
+ content_layer_client.add_draw_image(discardable_image, gfx::Point(42, 42));
scoped_refptr<DisplayItemList> display_list =
content_layer_client.PaintContentsToDisplayList();
@@ -511,13 +502,10 @@ TEST_F(DiscardableImageMapTest, GetDiscardableImagesInRectMaxImageMaxLayer) {
gfx::Size(dimension, dimension), no_color_space,
false /* allocate_encoded_memory */);
- PaintFlags flags;
- content_layer_client.add_draw_image(discardable_image1, gfx::Point(0, 0),
- flags);
- content_layer_client.add_draw_image(discardable_image2, gfx::Point(10000, 0),
- flags);
+ content_layer_client.add_draw_image(discardable_image1, gfx::Point(0, 0));
+ content_layer_client.add_draw_image(discardable_image2, gfx::Point(10000, 0));
content_layer_client.add_draw_image(discardable_image3,
- gfx::Point(-10000, 500), flags);
+ gfx::Point(-10000, 500));
scoped_refptr<DisplayItemList> display_list =
content_layer_client.PaintContentsToDisplayList();
@@ -560,13 +548,10 @@ TEST_F(DiscardableImageMapTest, GetDiscardableImagesRectInBounds) {
PaintImage long_discardable_image =
CreateDiscardablePaintImage(gfx::Size(10000, 100));
- PaintFlags flags;
- content_layer_client.add_draw_image(discardable_image1, gfx::Point(-10, -11),
- flags);
- content_layer_client.add_draw_image(discardable_image2, gfx::Point(950, 951),
- flags);
+ content_layer_client.add_draw_image(discardable_image1, gfx::Point(-10, -11));
+ content_layer_client.add_draw_image(discardable_image2, gfx::Point(950, 951));
content_layer_client.add_draw_image(long_discardable_image,
- gfx::Point(-100, 500), flags);
+ gfx::Point(-100, 500));
scoped_refptr<DisplayItemList> display_list =
content_layer_client.PaintContentsToDisplayList();
@@ -701,7 +686,7 @@ TEST_F(DiscardableImageMapTest, GathersDiscardableImagesFromNestedOps) {
auto internal_record = sk_make_sp<PaintOpBuffer>();
PaintImage discardable_image =
CreateDiscardablePaintImage(gfx::Size(100, 100));
- internal_record->push<DrawImageOp>(discardable_image, 0.f, 0.f, nullptr);
+ internal_record->push<DrawImageOp>(discardable_image, 0.f, 0.f);
// This |discardable_image2| is in a DisplayItemList that gets added
// to the root buffer.
@@ -711,7 +696,7 @@ TEST_F(DiscardableImageMapTest, GathersDiscardableImagesFromNestedOps) {
scoped_refptr<DisplayItemList> display_list =
new DisplayItemList(DisplayItemList::kToBeReleasedAsPaintOpBuffer);
display_list->StartPaint();
- display_list->push<DrawImageOp>(discardable_image2, 100.f, 100.f, nullptr);
+ display_list->push<DrawImageOp>(discardable_image2, 100.f, 100.f);
display_list->EndPaintOfUnpaired(gfx::Rect(100, 100, 100, 100));
display_list->Finalize();
@@ -750,12 +735,10 @@ TEST_F(DiscardableImageMapTest, GathersAnimatedImages) {
PaintImage animation_loop_infinite =
CreateAnimatedImage(image_size, frames, 1u);
- PaintFlags flags;
- content_layer_client.add_draw_image(static_image, gfx::Point(0, 0), flags);
- content_layer_client.add_draw_image(animated_loop_none, gfx::Point(100, 100),
- flags);
+ content_layer_client.add_draw_image(static_image, gfx::Point(0, 0));
+ content_layer_client.add_draw_image(animated_loop_none, gfx::Point(100, 100));
content_layer_client.add_draw_image(animation_loop_infinite,
- gfx::Point(200, 200), flags);
+ gfx::Point(200, 200));
scoped_refptr<DisplayItemList> display_list =
content_layer_client.PaintContentsToDisplayList();
@@ -796,10 +779,9 @@ TEST_F(DiscardableImageMapTest, GathersPaintWorklets) {
base::MakeRefCounted<TestPaintWorkletInput>(gfx::SizeF(image_size));
PaintImage paint_worklet_image = CreatePaintWorkletPaintImage(input);
- PaintFlags flags;
- content_layer_client.add_draw_image(static_image, gfx::Point(0, 0), flags);
- content_layer_client.add_draw_image(paint_worklet_image, gfx::Point(100, 100),
- flags);
+ content_layer_client.add_draw_image(static_image, gfx::Point(0, 0));
+ content_layer_client.add_draw_image(paint_worklet_image,
+ gfx::Point(100, 100));
scoped_refptr<DisplayItemList> display_list =
content_layer_client.PaintContentsToDisplayList();
@@ -823,13 +805,13 @@ TEST_F(DiscardableImageMapTest, CapturesImagesInPaintRecordShaders) {
shader_record->push<ScaleOp>(2.0f, 2.0f);
PaintImage static_image = CreateDiscardablePaintImage(gfx::Size(100, 100));
- shader_record->push<DrawImageOp>(static_image, 0.f, 0.f, nullptr);
+ shader_record->push<DrawImageOp>(static_image, 0.f, 0.f);
std::vector<FrameMetadata> frames = {
FrameMetadata(true, base::TimeDelta::FromMilliseconds(1)),
FrameMetadata(true, base::TimeDelta::FromMilliseconds(1))};
PaintImage animated_image = CreateAnimatedImage(gfx::Size(100, 100), frames);
- shader_record->push<DrawImageOp>(animated_image, 0.f, 0.f, nullptr);
+ shader_record->push<DrawImageOp>(animated_image, 0.f, 0.f);
gfx::Rect visible_rect(500, 500);
scoped_refptr<DisplayItemList> display_list = new DisplayItemList();
@@ -870,13 +852,13 @@ TEST_F(DiscardableImageMapTest, CapturesImagesInPaintFilters) {
auto filter_record = sk_make_sp<PaintOpBuffer>();
PaintImage static_image = CreateDiscardablePaintImage(gfx::Size(100, 100));
- filter_record->push<DrawImageOp>(static_image, 0.f, 0.f, nullptr);
+ filter_record->push<DrawImageOp>(static_image, 0.f, 0.f);
std::vector<FrameMetadata> frames = {
FrameMetadata(true, base::TimeDelta::FromMilliseconds(1)),
FrameMetadata(true, base::TimeDelta::FromMilliseconds(1))};
PaintImage animated_image = CreateAnimatedImage(gfx::Size(100, 100), frames);
- filter_record->push<DrawImageOp>(animated_image, 0.f, 0.f, nullptr);
+ filter_record->push<DrawImageOp>(animated_image, 0.f, 0.f);
gfx::Rect visible_rect(500, 500);
scoped_refptr<DisplayItemList> display_list = new DisplayItemList();
@@ -943,7 +925,7 @@ TEST_F(DiscardableImageMapTest, EmbeddedShaderWithAnimatedImages) {
FrameMetadata(true, base::TimeDelta::FromMilliseconds(1)),
FrameMetadata(true, base::TimeDelta::FromMilliseconds(1))};
PaintImage animated_image = CreateAnimatedImage(gfx::Size(100, 100), frames);
- shader_record->push<DrawImageOp>(animated_image, 0.f, 0.f, nullptr);
+ shader_record->push<DrawImageOp>(animated_image, 0.f, 0.f);
auto shader_with_image = PaintShader::MakePaintRecord(
shader_record, tile, SkTileMode::kClamp, SkTileMode::kClamp, nullptr);
@@ -993,12 +975,9 @@ TEST_F(DiscardableImageMapTest, DecodingModeHintsBasic) {
FakeContentLayerClient content_layer_client;
content_layer_client.set_bounds(visible_rect.size());
- content_layer_client.add_draw_image(unspecified_image, gfx::Point(0, 0),
- PaintFlags());
- content_layer_client.add_draw_image(async_image, gfx::Point(10, 10),
- PaintFlags());
- content_layer_client.add_draw_image(sync_image, gfx::Point(20, 20),
- PaintFlags());
+ content_layer_client.add_draw_image(unspecified_image, gfx::Point(0, 0));
+ content_layer_client.add_draw_image(async_image, gfx::Point(10, 10));
+ content_layer_client.add_draw_image(sync_image, gfx::Point(20, 20));
scoped_refptr<DisplayItemList> display_list =
content_layer_client.PaintContentsToDisplayList();
display_list->GenerateDiscardableImagesMetadata();
@@ -1058,18 +1037,12 @@ TEST_F(DiscardableImageMapTest, DecodingModeHintsDuplicates) {
FakeContentLayerClient content_layer_client;
content_layer_client.set_bounds(visible_rect.size());
- content_layer_client.add_draw_image(unspecified_image1, gfx::Point(0, 0),
- PaintFlags());
- content_layer_client.add_draw_image(async_image1, gfx::Point(10, 10),
- PaintFlags());
- content_layer_client.add_draw_image(unspecified_image2, gfx::Point(20, 20),
- PaintFlags());
- content_layer_client.add_draw_image(sync_image2, gfx::Point(30, 30),
- PaintFlags());
- content_layer_client.add_draw_image(async_image3, gfx::Point(40, 40),
- PaintFlags());
- content_layer_client.add_draw_image(sync_image3, gfx::Point(50, 50),
- PaintFlags());
+ content_layer_client.add_draw_image(unspecified_image1, gfx::Point(0, 0));
+ content_layer_client.add_draw_image(async_image1, gfx::Point(10, 10));
+ content_layer_client.add_draw_image(unspecified_image2, gfx::Point(20, 20));
+ content_layer_client.add_draw_image(sync_image2, gfx::Point(30, 30));
+ content_layer_client.add_draw_image(async_image3, gfx::Point(40, 40));
+ content_layer_client.add_draw_image(sync_image3, gfx::Point(50, 50));
scoped_refptr<DisplayItemList> display_list =
content_layer_client.PaintContentsToDisplayList();
display_list->GenerateDiscardableImagesMetadata();
@@ -1100,9 +1073,8 @@ TEST_F(DiscardableImageMapTest, TracksImageRegions) {
FrameMetadata(true, base::TimeDelta::FromMilliseconds(1)),
};
auto image = CreateAnimatedImage(gfx::Size(100, 100), frames);
- PaintFlags flags;
- content_layer_client.add_draw_image(image, gfx::Point(0, 0), flags);
- content_layer_client.add_draw_image(image, gfx::Point(400, 400), flags);
+ content_layer_client.add_draw_image(image, gfx::Point(0, 0));
+ content_layer_client.add_draw_image(image, gfx::Point(400, 400));
scoped_refptr<DisplayItemList> display_list =
content_layer_client.PaintContentsToDisplayList();
@@ -1146,8 +1118,7 @@ TEST_F(DiscardableImageMapTest, HighBitDepth) {
const DiscardableImageMap& image_map = display_list->discardable_image_map();
EXPECT_FALSE(image_map.contains_hbd_images());
- content_layer_client.add_draw_image(discardable_image, gfx::Point(0, 0),
- PaintFlags());
+ content_layer_client.add_draw_image(discardable_image, gfx::Point(0, 0));
display_list = content_layer_client.PaintContentsToDisplayList();
display_list->GenerateDiscardableImagesMetadata();
const DiscardableImageMap& image_map2 = display_list->discardable_image_map();
@@ -1169,8 +1140,7 @@ TEST_F(DiscardableImageMapTest, ContentColorUsage) {
// Adding a SRGB image should remain SRGB.
PaintImage discardable_image_srgb = CreateDiscardablePaintImage(
kSize, gfx::ColorSpace::CreateSRGB().ToSkColorSpace());
- content_layer_client.add_draw_image(discardable_image_srgb, gfx::Point(0, 0),
- PaintFlags());
+ content_layer_client.add_draw_image(discardable_image_srgb, gfx::Point(0, 0));
display_list = content_layer_client.PaintContentsToDisplayList();
display_list->GenerateDiscardableImagesMetadata();
EXPECT_EQ(display_list->discardable_image_map().content_color_usage(),
@@ -1179,8 +1149,7 @@ TEST_F(DiscardableImageMapTest, ContentColorUsage) {
// Adding a WCG image should switch to WCG.
PaintImage discardable_image_wcg = CreateDiscardablePaintImage(
kSize, gfx::ColorSpace::CreateDisplayP3D65().ToSkColorSpace());
- content_layer_client.add_draw_image(discardable_image_wcg, gfx::Point(0, 0),
- PaintFlags());
+ content_layer_client.add_draw_image(discardable_image_wcg, gfx::Point(0, 0));
display_list = content_layer_client.PaintContentsToDisplayList();
display_list->GenerateDiscardableImagesMetadata();
EXPECT_EQ(display_list->discardable_image_map().content_color_usage(),
@@ -1189,8 +1158,7 @@ TEST_F(DiscardableImageMapTest, ContentColorUsage) {
// Adding a HDR image should switch to HDR.
PaintImage discardable_image_hdr = CreateDiscardablePaintImage(
kSize, gfx::ColorSpace::CreateHDR10().ToSkColorSpace());
- content_layer_client.add_draw_image(discardable_image_hdr, gfx::Point(0, 0),
- PaintFlags());
+ content_layer_client.add_draw_image(discardable_image_hdr, gfx::Point(0, 0));
display_list = content_layer_client.PaintContentsToDisplayList();
display_list->GenerateDiscardableImagesMetadata();
EXPECT_EQ(display_list->discardable_image_map().content_color_usage(),
@@ -1218,8 +1186,7 @@ TEST_P(DiscardableImageMapColorSpaceTest, ColorSpace) {
EXPECT_EQ(image_map.content_color_usage(), gfx::ContentColorUsage::kSRGB);
EXPECT_FALSE(image_map.contains_hbd_images());
- content_layer_client.add_draw_image(discardable_image, gfx::Point(0, 0),
- PaintFlags());
+ content_layer_client.add_draw_image(discardable_image, gfx::Point(0, 0));
display_list = content_layer_client.PaintContentsToDisplayList();
display_list->GenerateDiscardableImagesMetadata();
const DiscardableImageMap& image_map2 = display_list->discardable_image_map();
diff --git a/chromium/cc/paint/display_item_list.cc b/chromium/cc/paint/display_item_list.cc
index aa047aba8f5..02301698f46 100644
--- a/chromium/cc/paint/display_item_list.cc
+++ b/chromium/cc/paint/display_item_list.cc
@@ -67,14 +67,6 @@ void IterateTextContentByOffsets(const PaintOpBuffer& buffer,
++index;
}
}
-
-bool RotationEquivalentToAxisFlip(const SkMatrix& matrix) {
- float skew_x = matrix.getSkewX();
- float skew_y = matrix.getSkewY();
- return ((skew_x == 1.f || skew_x == -1.f) &&
- (skew_y == 1.f || skew_y == -1.f));
-}
-
} // namespace
DisplayItemList::DisplayItemList(UsageHint usage_hint)
@@ -253,7 +245,7 @@ void DisplayItemList::AddToValue(base::trace_event::TracedValue* state,
if (include_items) {
state->BeginArray("items");
- PlaybackParams params(nullptr, SkMatrix::I());
+ PlaybackParams params(nullptr, SkM44());
std::map<size_t, gfx::Rect> visual_rects = rtree_.GetAllBoundsForTracing();
for (const PaintOp* op : PaintOpBuffer::Iterator(&paint_op_buffer_)) {
state->BeginDictionary();
@@ -386,7 +378,7 @@ DisplayItemList::GetDirectlyCompositedImageResult(
// Images that respect orientation will have 5 paint operations:
// (1) Save
// (2) Translate
- // (3) Concat (rotation matrix)
+ // (3) Concat (with a transformation that preserves axis alignment)
// (4) DrawImageRect
// (5) Restore
// Detect these the paint op buffer and disqualify the layer as a directly
@@ -403,21 +395,21 @@ DisplayItemList::GetDirectlyCompositedImageResult(
break;
}
case PaintOpType::Concat: {
- // We only expect a single rotation. If we see another one, then this
- // image won't be eligible for directly compositing.
+ // We only expect a single transformation. If we see another one, then
+ // this image won't be eligible for directly compositing.
if (transpose_image_size)
return base::nullopt;
const ConcatOp* concat_op = static_cast<const ConcatOp*>(op);
- if (concat_op->matrix.hasPerspective() ||
- !concat_op->matrix.preservesAxisAlignment())
+ if (!MathUtil::SkM44Preserves2DAxisAlignment(concat_op->matrix))
return base::nullopt;
- // If the rotation is not an axis flip, we'll need to transpose the
- // width and height dimensions to account for the same transform
- // applying when the layer bounds were calculated.
- transpose_image_size =
- RotationEquivalentToAxisFlip(concat_op->matrix);
+ // If the image has been rotated +/-90 degrees we'll need to transpose
+ // the width and height dimensions to account for the same transform
+ // applying when the layer bounds were calculated. Since we already
+ // know that the transformation preserves axis alignment, we only
+ // need to confirm that this is not a scaling operation.
+ transpose_image_size = (concat_op->matrix.rc(0, 0) == 0);
break;
}
case PaintOpType::DrawImageRect:
diff --git a/chromium/cc/paint/display_item_list_unittest.cc b/chromium/cc/paint/display_item_list_unittest.cc
index 2a3889b7a64..707ffc441e2 100644
--- a/chromium/cc/paint/display_item_list_unittest.cc
+++ b/chromium/cc/paint/display_item_list_unittest.cc
@@ -297,7 +297,7 @@ TEST_F(DisplayItemListTest, TransformPairedRange) {
{
list->StartPaint();
list->push<SaveOp>();
- list->push<ConcatOp>(static_cast<SkMatrix>(transform.matrix()));
+ list->push<ConcatOp>(transform.GetMatrixAsSkM44());
list->EndPaintOfPairedBegin();
}
@@ -511,7 +511,7 @@ TEST_F(DisplayItemListTest, AsValueWithOps) {
{
list->StartPaint();
list->push<SaveOp>();
- list->push<ConcatOp>(static_cast<SkMatrix>(transform.matrix()));
+ list->push<ConcatOp>(transform.GetMatrixAsSkM44());
list->EndPaintOfPairedBegin();
}
@@ -855,7 +855,7 @@ TEST_F(DisplayItemListTest, AppendVisualRectTwoBlocksTwoDrawings) {
{
list->StartPaint();
list->push<SaveOp>();
- list->push<ConcatOp>(SkMatrix::I());
+ list->push<ConcatOp>(SkM44());
list->EndPaintOfPairedBegin();
}
@@ -918,7 +918,7 @@ TEST_F(DisplayItemListTest,
{
list->StartPaint();
list->push<SaveOp>();
- list->push<ConcatOp>(SkMatrix::I());
+ list->push<ConcatOp>(SkM44());
list->EndPaintOfPairedBegin();
}
@@ -981,7 +981,7 @@ TEST_F(DisplayItemListTest,
{
list->StartPaint();
list->push<SaveOp>();
- list->push<ConcatOp>(SkMatrix::I());
+ list->push<ConcatOp>(SkM44());
list->EndPaintOfPairedBegin();
}
@@ -1044,7 +1044,7 @@ TEST_F(DisplayItemListTest,
{
list->StartPaint();
list->push<SaveOp>();
- list->push<ConcatOp>(SkMatrix::I());
+ list->push<ConcatOp>(SkM44());
list->EndPaintOfPairedBegin();
}
diff --git a/chromium/cc/paint/filter_operation.cc b/chromium/cc/paint/filter_operation.cc
index c92ce18b3af..dae02259d51 100644
--- a/chromium/cc/paint/filter_operation.cc
+++ b/chromium/cc/paint/filter_operation.cc
@@ -59,7 +59,7 @@ FilterOperation::FilterOperation(FilterType type, float amount)
FilterOperation::FilterOperation(FilterType type,
float amount,
- SkBlurImageFilter::TileMode tile_mode)
+ SkTileMode tile_mode)
: type_(type),
amount_(amount),
outer_threshold_(0),
diff --git a/chromium/cc/paint/filter_operation.h b/chromium/cc/paint/filter_operation.h
index 7e3b17b2064..c989741e2dd 100644
--- a/chromium/cc/paint/filter_operation.h
+++ b/chromium/cc/paint/filter_operation.h
@@ -14,7 +14,7 @@
#include "cc/paint/paint_filter.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkScalar.h"
-#include "third_party/skia/include/effects/SkBlurImageFilter.h"
+#include "third_party/skia/include/core/SkTileMode.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h"
@@ -98,7 +98,7 @@ class CC_PAINT_EXPORT FilterOperation {
return shape_;
}
- SkBlurImageFilter::TileMode blur_tile_mode() const {
+ SkTileMode blur_tile_mode() const {
DCHECK_EQ(type_, BLUR);
return blur_tile_mode_;
}
@@ -137,8 +137,7 @@ class CC_PAINT_EXPORT FilterOperation {
static FilterOperation CreateBlurFilter(
float amount,
- SkBlurImageFilter::TileMode tile_mode =
- SkBlurImageFilter::kClampToBlack_TileMode) {
+ SkTileMode tile_mode = SkTileMode::kDecal) {
return FilterOperation(BLUR, amount, tile_mode);
}
@@ -227,7 +226,7 @@ class CC_PAINT_EXPORT FilterOperation {
shape_ = shape;
}
- void set_blur_tile_mode(SkBlurImageFilter::TileMode tile_mode) {
+ void set_blur_tile_mode(SkTileMode tile_mode) {
DCHECK_EQ(type_, BLUR);
blur_tile_mode_ = tile_mode;
}
@@ -255,9 +254,7 @@ class CC_PAINT_EXPORT FilterOperation {
private:
FilterOperation(FilterType type, float amount);
- FilterOperation(FilterType type,
- float amount,
- SkBlurImageFilter::TileMode tile_mode);
+ FilterOperation(FilterType type, float amount, SkTileMode tile_mode);
FilterOperation(FilterType type,
const gfx::Point& offset,
@@ -286,7 +283,7 @@ class CC_PAINT_EXPORT FilterOperation {
// Use a collection of |gfx::Rect| to make serialization simpler.
ShapeRects shape_;
- SkBlurImageFilter::TileMode blur_tile_mode_;
+ SkTileMode blur_tile_mode_;
};
} // namespace cc
diff --git a/chromium/cc/paint/filter_operations_unittest.cc b/chromium/cc/paint/filter_operations_unittest.cc
index b8cc7fa6914..a51ea0f82eb 100644
--- a/chromium/cc/paint/filter_operations_unittest.cc
+++ b/chromium/cc/paint/filter_operations_unittest.cc
@@ -55,7 +55,7 @@ TEST(FilterOperationsTest, MapRectDropShadowReferenceFilter) {
FilterOperation::CreateReferenceFilter(sk_make_sp<DropShadowPaintFilter>(
SkIntToScalar(3), SkIntToScalar(8), SkIntToScalar(4),
SkIntToScalar(9), SK_ColorBLACK,
- SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
+ DropShadowPaintFilter::ShadowMode::kDrawShadowAndForeground,
nullptr)));
EXPECT_EQ(gfx::Rect(-9, -19, 34, 64),
ops.MapRect(gfx::Rect(0, 0, 10, 10), SkMatrix::I()));
@@ -71,7 +71,7 @@ TEST(FilterOperationsTest, MapRectReverseDropShadowReferenceFilter) {
FilterOperation::CreateReferenceFilter(sk_make_sp<DropShadowPaintFilter>(
SkIntToScalar(3), SkIntToScalar(8), SkIntToScalar(4),
SkIntToScalar(9), SK_ColorBLACK,
- SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
+ DropShadowPaintFilter::ShadowMode::kDrawShadowAndForeground,
nullptr)));
EXPECT_EQ(gfx::Rect(-15, -35, 34, 64),
ops.MapRectReverse(gfx::Rect(0, 0, 10, 10), SkMatrix::I()));
@@ -222,8 +222,7 @@ TEST(FilterOperationsTest, MapRectTypeConversionDoesNotOverflow) {
FilterOperation::CreateReferenceFilter(sk_make_sp<XfermodePaintFilter>(
SkBlendMode::kSrcOver,
sk_make_sp<OffsetPaintFilter>(-big_offset, -big_offset, nullptr),
- sk_make_sp<OffsetPaintFilter>(big_offset, big_offset, nullptr),
- nullptr)));
+ sk_make_sp<OffsetPaintFilter>(big_offset, big_offset, nullptr))));
gfx::Rect rect = ops.MapRect(gfx::Rect(-10, -10, 20, 20), SkMatrix::I());
EXPECT_GT(rect.width(), 0);
EXPECT_GT(rect.height(), 0);
@@ -699,10 +698,10 @@ TEST(FilterOperationsTest, BlendSaturatingBrightnessWithNull) {
}
TEST(FilterOperationsTest, BlendReferenceFilters) {
- sk_sp<PaintFilter> from_filter(sk_make_sp<BlurPaintFilter>(
- 1.f, 1.f, BlurPaintFilter::TileMode::kClampToBlack_TileMode, nullptr));
- sk_sp<PaintFilter> to_filter(sk_make_sp<BlurPaintFilter>(
- 2.f, 2.f, BlurPaintFilter::TileMode::kClampToBlack_TileMode, nullptr));
+ sk_sp<PaintFilter> from_filter(
+ sk_make_sp<BlurPaintFilter>(1.f, 1.f, SkTileMode::kDecal, nullptr));
+ sk_sp<PaintFilter> to_filter(
+ sk_make_sp<BlurPaintFilter>(2.f, 2.f, SkTileMode::kDecal, nullptr));
FilterOperation from =
FilterOperation::CreateReferenceFilter(std::move(from_filter));
FilterOperation to =
@@ -722,8 +721,8 @@ TEST(FilterOperationsTest, BlendReferenceFilters) {
}
TEST(FilterOperationsTest, BlendReferenceWithNull) {
- sk_sp<PaintFilter> image_filter(sk_make_sp<BlurPaintFilter>(
- 1.f, 1.f, BlurPaintFilter::TileMode::kClampToBlack_TileMode, nullptr));
+ sk_sp<PaintFilter> image_filter(
+ sk_make_sp<BlurPaintFilter>(1.f, 1.f, SkTileMode::kDecal, nullptr));
FilterOperation filter =
FilterOperation::CreateReferenceFilter(std::move(image_filter));
FilterOperation null_filter = FilterOperation::CreateReferenceFilter(nullptr);
@@ -917,8 +916,8 @@ TEST(FilterOperationsTest, HasFilterOfType) {
filters.Append(FilterOperation::CreateGrayscaleFilter(0.5f));
filters.Append(FilterOperation::CreateBlurFilter(20));
- sk_sp<PaintFilter> filter(sk_make_sp<BlurPaintFilter>(
- 1.f, 1.f, BlurPaintFilter::TileMode::kClampToBlack_TileMode, nullptr));
+ sk_sp<PaintFilter> filter(
+ sk_make_sp<BlurPaintFilter>(1.f, 1.f, SkTileMode::kDecal, nullptr));
filters.Append(FilterOperation::CreateReferenceFilter(std::move(filter)));
EXPECT_TRUE(filters.HasFilterOfType(FilterOperation::GRAYSCALE));
diff --git a/chromium/cc/paint/frame_metadata.h b/chromium/cc/paint/frame_metadata.h
index d63bb0d4363..e152074d599 100644
--- a/chromium/cc/paint/frame_metadata.h
+++ b/chromium/cc/paint/frame_metadata.h
@@ -12,7 +12,7 @@ namespace cc {
// TODO(khushalsagar): Find a better name?
struct CC_PAINT_EXPORT FrameMetadata {
- FrameMetadata() {}
+ FrameMetadata() = default;
FrameMetadata(bool complete, base::TimeDelta duration)
: complete(complete), duration(duration) {}
diff --git a/chromium/cc/paint/image_provider.h b/chromium/cc/paint/image_provider.h
index 973f8f78a9d..ca1f2939c1c 100644
--- a/chromium/cc/paint/image_provider.h
+++ b/chromium/cc/paint/image_provider.h
@@ -5,6 +5,8 @@
#ifndef CC_PAINT_IMAGE_PROVIDER_H_
#define CC_PAINT_IMAGE_PROVIDER_H_
+#include <vector>
+
#include "base/callback.h"
#include "base/optional.h"
#include "cc/paint/decoded_draw_image.h"
@@ -12,8 +14,6 @@
#include "cc/paint/paint_export.h"
#include "cc/paint/paint_op_buffer.h"
-#include <vector>
-
namespace cc {
class PaintImage;
@@ -36,7 +36,7 @@ class CC_PAINT_EXPORT ImageProvider {
ScopedResult& operator=(const ScopedResult&) = delete;
ScopedResult& operator=(ScopedResult&& other);
- operator bool() const { return image_ || record_; }
+ explicit operator bool() const { return image_ || record_; }
const DecodedDrawImage& decoded_image() const { return image_; }
bool needs_unlock() const { return !destruction_callback_.is_null(); }
const PaintRecord* paint_record() {
@@ -52,7 +52,7 @@ class CC_PAINT_EXPORT ImageProvider {
DestructionCallback destruction_callback_;
};
- virtual ~ImageProvider() {}
+ virtual ~ImageProvider() = default;
// Returns either:
// 1. The DecodedDrawImage to use for this PaintImage. If no image is
diff --git a/chromium/cc/paint/image_transfer_cache_entry.cc b/chromium/cc/paint/image_transfer_cache_entry.cc
index 37077c2b1c8..8da6a2cc99d 100644
--- a/chromium/cc/paint/image_transfer_cache_entry.cc
+++ b/chromium/cc/paint/image_transfer_cache_entry.cc
@@ -17,10 +17,10 @@
#include "third_party/skia/include/core/SkColorSpace.h"
#include "third_party/skia/include/core/SkImage.h"
#include "third_party/skia/include/core/SkPixmap.h"
-#include "third_party/skia/include/core/SkYUVAIndex.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/GrTypes.h"
+#include "third_party/skia/include/gpu/GrYUVABackendTextures.h"
namespace cc {
namespace {
@@ -48,17 +48,18 @@ void ReleaseContext(SkImage::ReleaseContext context) {
sk_sp<SkImage> MakeYUVImageFromUploadedPlanes(
GrDirectContext* context,
const std::vector<sk_sp<SkImage>>& plane_images,
- YUVDecodeFormat plane_images_format,
+ SkYUVAInfo::PlaneConfig plane_config,
+ SkYUVAInfo::Subsampling subsampling,
SkYUVColorSpace yuv_color_space,
sk_sp<SkColorSpace> image_color_space) {
// 1) Extract the textures.
- DCHECK_NE(YUVDecodeFormat::kUnknown, plane_images_format);
- DCHECK_EQ(NumberOfPlanesForYUVDecodeFormat(plane_images_format),
+ DCHECK_NE(SkYUVAInfo::PlaneConfig::kUnknown, plane_config);
+ DCHECK_NE(SkYUVAInfo::Subsampling::kUnknown, subsampling);
+ DCHECK_EQ(static_cast<size_t>(SkYUVAInfo::NumPlanes(plane_config)),
plane_images.size());
DCHECK_LE(plane_images.size(),
- base::checked_cast<size_t>(SkYUVASizeInfo::kMaxCount));
- std::array<GrBackendTexture, SkYUVASizeInfo::kMaxCount>
- plane_backend_textures;
+ base::checked_cast<size_t>(SkYUVAInfo::kMaxPlanes));
+ std::array<GrBackendTexture, SkYUVAInfo::kMaxPlanes> plane_backend_textures;
for (size_t plane = 0u; plane < plane_images.size(); plane++) {
plane_backend_textures[plane] = plane_images[plane]->getBackendTexture(
true /* flushPendingGrContextIO */);
@@ -69,31 +70,14 @@ sk_sp<SkImage> MakeYUVImageFromUploadedPlanes(
}
// 2) Create the YUV image.
- SkYUVAIndex plane_indices[SkYUVAIndex::kIndexCount];
- if (plane_images_format == YUVDecodeFormat::kYUV3) {
- plane_indices[SkYUVAIndex::kY_Index] = {0, SkColorChannel::kR};
- plane_indices[SkYUVAIndex::kU_Index] = {1, SkColorChannel::kR};
- plane_indices[SkYUVAIndex::kV_Index] = {2, SkColorChannel::kR};
- } else if (plane_images_format == YUVDecodeFormat::kYVU3) {
- plane_indices[SkYUVAIndex::kY_Index] = {0, SkColorChannel::kR};
- plane_indices[SkYUVAIndex::kU_Index] = {2, SkColorChannel::kR};
- plane_indices[SkYUVAIndex::kV_Index] = {1, SkColorChannel::kR};
- } else if (plane_images_format == YUVDecodeFormat::kYUV2) {
- plane_indices[SkYUVAIndex::kY_Index] = {0, SkColorChannel::kR};
- plane_indices[SkYUVAIndex::kU_Index] = {1, SkColorChannel::kR};
- plane_indices[SkYUVAIndex::kV_Index] = {1, SkColorChannel::kG};
- } else {
- // TODO(crbug.com/910276): handle and test non-opaque images.
- NOTREACHED();
- DLOG(ERROR) << "Unsupported planar format";
- return nullptr;
- }
- plane_indices[SkYUVAIndex::kA_Index] = {-1, SkColorChannel::kR};
+ SkYUVAInfo yuva_info(plane_images[0]->dimensions(), plane_config, subsampling,
+ yuv_color_space);
+ GrYUVABackendTextures yuva_backend_textures(
+ yuva_info, plane_backend_textures.data(), kTopLeft_GrSurfaceOrigin);
Context* ctx = new Context{plane_images};
sk_sp<SkImage> image = SkImage::MakeFromYUVATextures(
- context, yuv_color_space, plane_backend_textures.data(), plane_indices,
- plane_images[0]->dimensions(), kTopLeft_GrSurfaceOrigin,
- std::move(image_color_space), ReleaseContext, ctx);
+ context, yuva_backend_textures, std::move(image_color_space),
+ ReleaseContext, ctx);
if (!image) {
DLOG(ERROR) << "Could not create YUV image";
return nullptr;
@@ -190,20 +174,28 @@ ClientImageTransferCacheEntry::ClientImageTransferCacheEntry(
}
ClientImageTransferCacheEntry::ClientImageTransferCacheEntry(
- const SkPixmap* y_pixmap,
- const SkPixmap* u_pixmap,
- const SkPixmap* v_pixmap,
+ const SkPixmap yuva_pixmaps[],
+ SkYUVAInfo::PlaneConfig plane_config,
+ SkYUVAInfo::Subsampling subsampling,
const SkColorSpace* decoded_color_space,
SkYUVColorSpace yuv_color_space,
bool needs_mips)
: needs_mips_(needs_mips),
- num_planes_(3),
+ plane_config_(plane_config),
id_(GetNextId()),
pixmap_(nullptr),
target_color_space_(nullptr),
- yuv_pixmaps_({y_pixmap, u_pixmap, v_pixmap, nullptr}),
decoded_color_space_(decoded_color_space),
+ subsampling_(subsampling),
yuv_color_space_(yuv_color_space) {
+ yuv_pixmaps_.emplace(std::array<const SkPixmap*, SkYUVAInfo::kMaxPlanes>());
+ size_t num_yuva_pixmaps =
+ static_cast<size_t>(SkYUVAInfo::NumPlanes(plane_config));
+ DCHECK_GT(num_yuva_pixmaps, 0U);
+ DCHECK_LE(num_yuva_pixmaps, yuv_pixmaps_->size());
+ for (size_t i = 0; i < num_yuva_pixmaps; ++i) {
+ yuv_pixmaps_->at(i) = &yuva_pixmaps[i];
+ }
DCHECK(IsYuv());
size_t decoded_color_space_size =
decoded_color_space ? decoded_color_space->writeToMemory(nullptr) : 0u;
@@ -215,23 +207,23 @@ ClientImageTransferCacheEntry::ClientImageTransferCacheEntry(
// Compute and cache the size of the data.
base::CheckedNumeric<uint32_t> safe_size;
safe_size += PaintOpWriter::HeaderBytes();
- safe_size += sizeof(uint32_t); // is_yuv
- safe_size += sizeof(uint32_t); // num_planes
+ safe_size += sizeof(uint32_t); // plane_config
+ safe_size += sizeof(uint32_t); // subsampling
safe_size += sizeof(uint32_t); // has mips
safe_size += sizeof(uint32_t); // yuv_color_space
safe_size += sizeof(uint32_t); // yuv_color_type
safe_size += decoded_color_space_size + align;
- safe_size += num_planes_ * sizeof(uint64_t); // plane widths
- safe_size += num_planes_ * sizeof(uint64_t); // plane heights
- safe_size += num_planes_ * sizeof(uint64_t); // plane strides
+ safe_size += num_yuva_pixmaps * sizeof(uint64_t); // plane widths
+ safe_size += num_yuva_pixmaps * sizeof(uint64_t); // plane heights
+ safe_size += num_yuva_pixmaps * sizeof(uint64_t); // plane strides
safe_size +=
- num_planes_ * (sizeof(uint64_t) + align); // pixels size + alignment
+ num_yuva_pixmaps * (sizeof(uint64_t) + align); // pixels size + alignment
// Include 4 bytes of padding before each plane data chunk so we can always
// align our data pointer to a 4-byte boundary.
- safe_size += 4 * num_planes_;
- safe_size += y_pixmap->computeByteSize();
- safe_size += u_pixmap->computeByteSize();
- safe_size += v_pixmap->computeByteSize();
+ safe_size += 4 * num_yuva_pixmaps;
+ for (size_t i = 0; i < num_yuva_pixmaps; ++i) {
+ safe_size += yuv_pixmaps_->at(i)->computeByteSize();
+ }
size_ = safe_size.ValueOrDie();
}
@@ -250,9 +242,11 @@ uint32_t ClientImageTransferCacheEntry::Id() const {
void ClientImageTransferCacheEntry::ValidateYUVDataBeforeSerializing() const {
DCHECK(!pixmap_);
- DCHECK_LE(yuv_pixmaps_->size(),
- static_cast<uint32_t>(SkYUVASizeInfo::kMaxCount));
- for (uint32_t i = 0; i < num_planes_; ++i) {
+ DCHECK_NE(subsampling_, SkYUVAInfo::Subsampling::kUnknown);
+ DCHECK_LE(yuv_pixmaps_->size(), static_cast<size_t>(SkYUVAInfo::kMaxPlanes));
+ size_t num_planes = static_cast<size_t>(SkYUVAInfo::NumPlanes(plane_config_));
+ DCHECK_LE(num_planes, yuv_pixmaps_->size());
+ for (size_t i = 0; i < num_planes; ++i) {
DCHECK(yuv_pixmaps_->at(i));
const SkPixmap* plane = yuv_pixmaps_->at(i);
DCHECK_GT(plane->width(), 0);
@@ -266,18 +260,19 @@ bool ClientImageTransferCacheEntry::Serialize(base::span<uint8_t> data) const {
// We don't need to populate the SerializeOptions here since the writer is
// only used for serializing primitives.
PaintOp::SerializeOptions options(nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr, false, false, 0, SkMatrix::I());
+ nullptr, false, false, 0, SkM44());
PaintOpWriter writer(data.data(), data.size(), options);
- writer.Write(static_cast<uint32_t>(IsYuv() ? 1 : 0));
+ writer.Write(plane_config_);
- if (IsYuv()) {
+ if (plane_config_ != SkYUVAInfo::PlaneConfig::kUnknown) {
ValidateYUVDataBeforeSerializing();
- writer.Write(num_planes_);
+ writer.Write(subsampling_);
+ int num_planes = SkYUVAInfo::NumPlanes(plane_config_);
writer.Write(static_cast<uint32_t>(needs_mips_ ? 1 : 0));
writer.Write(yuv_color_space_);
writer.Write(decoded_color_space_);
writer.Write(yuv_pixmaps_->at(0)->colorType());
- for (uint32_t i = 0; i < num_planes_; ++i) {
+ for (int i = 0; i < num_planes; ++i) {
DCHECK(yuv_pixmaps_->at(i));
const SkPixmap* plane = yuv_pixmaps_->at(i);
writer.Write(plane->width());
@@ -334,7 +329,8 @@ ServiceImageTransferCacheEntry& ServiceImageTransferCacheEntry::operator=(
bool ServiceImageTransferCacheEntry::BuildFromHardwareDecodedImage(
GrDirectContext* context,
std::vector<sk_sp<SkImage>> plane_images,
- YUVDecodeFormat plane_images_format,
+ SkYUVAInfo::PlaneConfig plane_config,
+ SkYUVAInfo::Subsampling subsampling,
SkYUVColorSpace yuv_color_space,
size_t buffer_byte_size,
bool needs_mips) {
@@ -352,8 +348,7 @@ bool ServiceImageTransferCacheEntry::BuildFromHardwareDecodedImage(
DLOG(ERROR) << "Could not generate mipmap chain for plane " << plane;
return false;
}
- plane_sizes_.push_back(GrDirectContext::ComputeImageSize(
- plane_images[plane], GrMipMapped::kYes));
+ plane_sizes_.push_back(plane_images[plane]->textureSize());
safe_total_size += plane_sizes_.back();
}
if (!safe_total_size.AssignIfValid(&size_)) {
@@ -362,14 +357,15 @@ bool ServiceImageTransferCacheEntry::BuildFromHardwareDecodedImage(
}
}
plane_images_ = std::move(plane_images);
- plane_images_format_ = plane_images_format;
+ plane_config_ = plane_config;
+ subsampling_ = subsampling;
yuv_color_space_ = yuv_color_space;
// 2) Create a SkImage backed by |plane_images|.
// TODO(andrescj): support embedded color profiles for hardware decodes and
// pass the color space to MakeYUVImageFromUploadedPlanes.
- image_ = MakeYUVImageFromUploadedPlanes(context_, plane_images_,
- plane_images_format_, yuv_color_space,
+ image_ = MakeYUVImageFromUploadedPlanes(context_, plane_images_, plane_config,
+ subsampling, yuv_color_space,
SkColorSpace::MakeSRGB());
if (!image_)
return false;
@@ -395,17 +391,14 @@ bool ServiceImageTransferCacheEntry::Deserialize(
PaintOp::DeserializeOptions options(nullptr, nullptr, nullptr,
&scratch_buffer, false, nullptr);
PaintOpReader reader(data.data(), data.size(), options);
- uint32_t image_is_yuv = 0;
- reader.Read(&image_is_yuv);
- if (!!image_is_yuv) {
- uint32_t num_planes = 0;
- reader.Read(&num_planes);
- // TODO(crbug.com/910276): Allow for four planes if YUVA.
- // TODO(crbug.com/986575): consider serializing a YUVDecodeFormat.
- if (num_planes != 3u)
+ plane_config_ = SkYUVAInfo::PlaneConfig::kUnknown;
+ reader.Read(&plane_config_);
+ if (plane_config_ != SkYUVAInfo::PlaneConfig::kUnknown) {
+ SkYUVAInfo::Subsampling subsampling = SkYUVAInfo::Subsampling::kUnknown;
+ reader.Read(&subsampling);
+ if (subsampling == SkYUVAInfo::Subsampling::kUnknown)
return false;
- plane_images_format_ =
- num_planes == 3u ? YUVDecodeFormat::kYUV3 : YUVDecodeFormat::kYUVA4;
+ subsampling_ = subsampling;
uint32_t needs_mips;
reader.Read(&needs_mips);
has_mips_ = needs_mips;
@@ -417,10 +410,9 @@ bool ServiceImageTransferCacheEntry::Deserialize(
SkColorType yuv_plane_color_type = kUnknown_SkColorType;
reader.Read(&yuv_plane_color_type);
- // Match GrTexture::onGpuMemorySize so that memory traces agree.
- auto gr_mips = has_mips_ ? GrMipMapped::kYes : GrMipMapped::kNo;
+ int num_planes = SkYUVAInfo::NumPlanes(plane_config_);
// Read in each plane and reconstruct pixmaps.
- for (uint32_t i = 0; i < num_planes; i++) {
+ for (int i = 0; i < num_planes; i++) {
uint32_t plane_width = 0;
reader.Read(&plane_width);
uint32_t plane_height = 0;
@@ -440,7 +432,7 @@ bool ServiceImageTransferCacheEntry::Deserialize(
plane_stride == 0)
return false;
- size_t plane_bytes;
+ size_t plane_bytes = 0;
reader.ReadSize(&plane_bytes);
SkImageInfo plane_pixmap_info =
SkImageInfo::Make(plane_width, plane_height, yuv_plane_color_type,
@@ -473,10 +465,8 @@ bool ServiceImageTransferCacheEntry::Deserialize(
return false;
DCHECK(plane->isTextureBacked());
- const size_t plane_size =
- GrDirectContext::ComputeImageSize(plane, gr_mips);
- size_ += plane_size;
- plane_sizes_.push_back(plane_size);
+ plane_sizes_.push_back(plane->textureSize());
+ size_ += plane_sizes_.back();
// |plane_images_| must be set for use in EnsureMips(), memory dumps, and
// unit tests.
@@ -484,8 +474,8 @@ bool ServiceImageTransferCacheEntry::Deserialize(
}
DCHECK(yuv_color_space_.has_value());
image_ = MakeYUVImageFromUploadedPlanes(
- context_, plane_images_, plane_images_format_, yuv_color_space_.value(),
- decoded_color_space);
+ context_, plane_images_, plane_config_, subsampling_.value(),
+ yuv_color_space_.value(), decoded_color_space);
return !!image_;
}
@@ -540,11 +530,8 @@ bool ServiceImageTransferCacheEntry::Deserialize(
SkPixmap pixmap(image_info, const_cast<const void*>(pixel_data), row_bytes);
image_ = MakeSkImage(pixmap, width, height, target_color_space);
- if (image_) {
- // Match GrTexture::onGpuMemorySize so that memory traces agree.
- auto gr_mips = has_mips_ ? GrMipMapped::kYes : GrMipMapped::kNo;
- size_ = GrDirectContext::ComputeImageSize(image_, gr_mips);
- }
+ if (image_)
+ size_ = image_->textureSize();
return !!image_;
}
@@ -608,8 +595,8 @@ void ServiceImageTransferCacheEntry::EnsureMips() {
if (is_yuv()) {
DCHECK(image_);
DCHECK(yuv_color_space_.has_value());
- DCHECK_NE(YUVDecodeFormat::kUnknown, plane_images_format_);
- DCHECK_EQ(NumberOfPlanesForYUVDecodeFormat(plane_images_format_),
+ DCHECK_NE(SkYUVAInfo::PlaneConfig::kUnknown, plane_config_);
+ DCHECK_EQ(static_cast<size_t>(SkYUVAInfo::NumPlanes(plane_config_)),
plane_images_.size());
// We first do all the work with local variables. Then, if everything
@@ -624,11 +611,11 @@ void ServiceImageTransferCacheEntry::EnsureMips() {
if (!mipped_plane)
return;
mipped_planes.push_back(std::move(mipped_plane));
- mipped_plane_sizes.push_back(GrDirectContext::ComputeImageSize(
- mipped_planes.back(), GrMipMapped::kYes));
+ mipped_plane_sizes.push_back(mipped_planes.back()->textureSize());
}
sk_sp<SkImage> mipped_image = MakeYUVImageFromUploadedPlanes(
- context_, mipped_planes, plane_images_format_, yuv_color_space_.value(),
+ context_, mipped_planes, plane_config_, subsampling_.value(),
+ yuv_color_space_.value(),
image_->refColorSpace() /* image_color_space */);
if (!mipped_image)
return;
diff --git a/chromium/cc/paint/image_transfer_cache_entry.h b/chromium/cc/paint/image_transfer_cache_entry.h
index ee4ad202d96..4dd8f49d59d 100644
--- a/chromium/cc/paint/image_transfer_cache_entry.h
+++ b/chromium/cc/paint/image_transfer_cache_entry.h
@@ -16,7 +16,7 @@
#include "cc/paint/transfer_cache_entry.h"
#include "third_party/skia/include/core/SkImageInfo.h"
#include "third_party/skia/include/core/SkRefCnt.h"
-#include "third_party/skia/include/core/SkYUVASizeInfo.h"
+#include "third_party/skia/include/core/SkYUVAInfo.h"
class GrDirectContext;
class SkColorSpace;
@@ -49,9 +49,9 @@ class CC_PAINT_EXPORT ClientImageTransferCacheEntry final
const SkColorSpace* target_color_space,
bool needs_mips);
explicit ClientImageTransferCacheEntry(
- const SkPixmap* y_pixmap,
- const SkPixmap* u_pixmap,
- const SkPixmap* v_pixmap,
+ const SkPixmap yuva_pixmaps[],
+ SkYUVAInfo::PlaneConfig plane_config,
+ SkYUVAInfo::Subsampling subsampling,
const SkColorSpace* decoded_color_space,
SkYUVColorSpace yuv_color_space,
bool needs_mips);
@@ -68,7 +68,7 @@ class CC_PAINT_EXPORT ClientImageTransferCacheEntry final
private:
const bool needs_mips_ = false;
- const uint32_t num_planes_ = 1;
+ SkYUVAInfo::PlaneConfig plane_config_ = SkYUVAInfo::PlaneConfig::kUnknown;
uint32_t id_;
uint32_t size_ = 0;
static base::AtomicSequenceNumber s_next_id_;
@@ -80,9 +80,10 @@ class CC_PAINT_EXPORT ClientImageTransferCacheEntry final
// at raster.
// YUVA-only members.
- base::Optional<std::array<const SkPixmap*, SkYUVASizeInfo::kMaxCount>>
+ base::Optional<std::array<const SkPixmap*, SkYUVAInfo::kMaxPlanes>>
yuv_pixmaps_;
const SkColorSpace* const decoded_color_space_;
+ SkYUVAInfo::Subsampling subsampling_ = SkYUVAInfo::Subsampling::kUnknown;
SkYUVColorSpace yuv_color_space_;
// DCHECKs that the appropriate data members are set or not set and have
@@ -115,7 +116,8 @@ class CC_PAINT_EXPORT ServiceImageTransferCacheEntry final
// Returns true if the entry can be built, false otherwise.
bool BuildFromHardwareDecodedImage(GrDirectContext* context,
std::vector<sk_sp<SkImage>> plane_images,
- YUVDecodeFormat plane_images_format,
+ SkYUVAInfo::PlaneConfig plane_config,
+ SkYUVAInfo::Subsampling subsampling,
SkYUVColorSpace yuv_color_space,
size_t buffer_byte_size,
bool needs_mips);
@@ -141,7 +143,9 @@ class CC_PAINT_EXPORT ServiceImageTransferCacheEntry final
return plane_sizes_;
}
bool is_yuv() const { return !plane_images_.empty(); }
- size_t num_planes() const { return is_yuv() ? plane_images_.size() : 1u; }
+ size_t num_planes() const {
+ return is_yuv() ? SkYUVAInfo::NumPlanes(plane_config_) : 1u;
+ }
private:
sk_sp<SkImage> MakeSkImage(const SkPixmap& pixmap,
@@ -151,9 +155,10 @@ class CC_PAINT_EXPORT ServiceImageTransferCacheEntry final
GrDirectContext* context_ = nullptr;
std::vector<sk_sp<SkImage>> plane_images_;
- YUVDecodeFormat plane_images_format_ = YUVDecodeFormat::kUnknown;
+ SkYUVAInfo::PlaneConfig plane_config_ = SkYUVAInfo::PlaneConfig::kUnknown;
std::vector<size_t> plane_sizes_;
sk_sp<SkImage> image_;
+ base::Optional<SkYUVAInfo::Subsampling> subsampling_;
base::Optional<SkYUVColorSpace> yuv_color_space_;
bool has_mips_ = false;
size_t size_ = 0;
diff --git a/chromium/cc/paint/image_transfer_cache_entry_unittest.cc b/chromium/cc/paint/image_transfer_cache_entry_unittest.cc
index 1ff291d3696..e57ab845546 100644
--- a/chromium/cc/paint/image_transfer_cache_entry_unittest.cc
+++ b/chromium/cc/paint/image_transfer_cache_entry_unittest.cc
@@ -21,6 +21,7 @@
#include "third_party/skia/include/core/SkImageInfo.h"
#include "third_party/skia/include/core/SkPixmap.h"
#include "third_party/skia/include/core/SkRefCnt.h"
+#include "third_party/skia/include/core/SkYUVAPixmaps.h"
#include "third_party/skia/include/gpu/GrBackendSurface.h"
#include "third_party/skia/include/gpu/GrDirectContext.h"
#include "third_party/skia/include/gpu/GrTypes.h"
@@ -78,7 +79,7 @@ bool CheckImageIsSolidColor(const sk_sp<SkImage>& image,
}
class ImageTransferCacheEntryTest
- : public testing::TestWithParam<YUVDecodeFormat> {
+ : public testing::TestWithParam<SkYUVAInfo::PlaneConfig> {
public:
void SetUp() override {
// Initialize a GL GrContext for Skia.
@@ -109,8 +110,8 @@ class ImageTransferCacheEntryTest
std::unique_ptr<bool[]>* release_flags) {
std::vector<sk_sp<SkImage>> plane_images;
*release_flags = nullptr;
- if (GetParam() == YUVDecodeFormat::kYUV3 ||
- GetParam() == YUVDecodeFormat::kYVU3) {
+ if (GetParam() == SkYUVAInfo::PlaneConfig::kY_U_V ||
+ GetParam() == SkYUVAInfo::PlaneConfig::kY_V_U) {
*release_flags =
std::unique_ptr<bool[]>(new bool[3]{false, false, false});
plane_images = {
@@ -120,7 +121,7 @@ class ImageTransferCacheEntryTest
release_flags->get() + 1),
CreateSolidPlane(gr_context(), 32, 32, GL_R8_EXT, SkColors::kWhite,
release_flags->get() + 2)};
- } else if (GetParam() == YUVDecodeFormat::kYUV2) {
+ } else if (GetParam() == SkYUVAInfo::PlaneConfig::kY_UV) {
*release_flags = std::unique_ptr<bool[]>(new bool[2]{false, false});
plane_images = {
CreateSolidPlane(gr_context(), 64, 64, GL_R8_EXT, SkColors::kWhite,
@@ -204,40 +205,30 @@ TEST_P(ImageTransferCacheEntryTest, Deserialize) {
// width to test that alignment works correctly.
const int image_width = 12;
const int image_height = 10;
- const size_t y_stride = 16;
- const size_t uv_stride = 8;
-
- const size_t y_bytes = y_stride * image_height;
- const size_t uv_bytes = uv_stride * image_height / 2;
- const size_t planes_size = y_bytes + 2 * uv_bytes;
- std::unique_ptr<char[]> planes_data(new char[planes_size]);
-
- void* planes[3];
- planes[0] = reinterpret_cast<void*>(planes_data.get());
- planes[1] = reinterpret_cast<char*>(planes[0]) + y_bytes;
- planes[2] = reinterpret_cast<char*>(planes[1]) + uv_bytes;
-
- auto info = SkImageInfo::Make(image_width, image_height, kGray_8_SkColorType,
- kUnknown_SkAlphaType);
- SkPixmap y_pixmap(info, planes[0], y_stride);
- SkPixmap u_pixmap(info.makeWH(image_width / 2, image_height / 2), planes[1],
- uv_stride);
- SkPixmap v_pixmap(info.makeWH(image_width / 2, image_height / 2), planes[2],
- uv_stride);
+ const size_t yuv_strides[] = {16, 8, 8};
+
+ SkYUVAInfo yuva_info({image_width, image_height},
+ SkYUVAInfo::PlaneConfig::kY_U_V,
+ SkYUVAInfo::Subsampling::k420, kJpegYUVColorSpace);
+ SkYUVAPixmapInfo yuva_pixmap_info(
+ yuva_info, SkYUVAPixmapInfo::DataType::kUnorm8, yuv_strides);
+ SkYUVAPixmaps yuva_pixmaps = SkYUVAPixmaps::Allocate(yuva_pixmap_info);
// rgb (255, 121, 255) -> yuv (255, 255, 255)
const SkIRect bottom_color_rect =
SkIRect::MakeXYWH(0, image_height / 2, image_width, image_height / 2);
- ASSERT_TRUE(y_pixmap.erase(SkColors::kWhite));
- ASSERT_TRUE(u_pixmap.erase(SkColors::kWhite));
- ASSERT_TRUE(v_pixmap.erase(SkColors::kWhite));
+ ASSERT_TRUE(yuva_pixmaps.plane(0).erase(SkColors::kWhite));
+ ASSERT_TRUE(yuva_pixmaps.plane(1).erase(SkColors::kWhite));
+ ASSERT_TRUE(yuva_pixmaps.plane(2).erase(SkColors::kWhite));
+
// rgb (178, 0, 225) -> yuv (0, 255, 255)
const SkIRect top_color_rect = SkIRect::MakeWH(image_width, image_height / 2);
- ASSERT_TRUE(y_pixmap.erase(SkColors::kBlack, &top_color_rect));
+ ASSERT_TRUE(yuva_pixmaps.plane(0).erase(SkColors::kBlack, &top_color_rect));
auto client_entry(std::make_unique<ClientImageTransferCacheEntry>(
- &y_pixmap, &u_pixmap, &v_pixmap, nullptr, kJpegYUVColorSpace,
- true /* needs_mips */));
+ yuva_pixmaps.planes().data(), yuva_info.planeConfig(),
+ yuva_info.subsampling(), nullptr /* decoded color space*/,
+ yuva_info.yuvColorSpace(), true /* needs_mips */));
uint32_t size = client_entry->SerializedSize();
std::vector<uint8_t> data(size);
ASSERT_TRUE(client_entry->Serialize(
@@ -263,7 +254,8 @@ TEST_P(ImageTransferCacheEntryTest, HardwareDecodedNoMipsAtCreation) {
std::unique_ptr<bool[]> release_flags;
std::vector<sk_sp<SkImage>> plane_images = CreateTestYUVImage(&release_flags);
const size_t plane_images_size = plane_images.size();
- ASSERT_EQ(NumberOfPlanesForYUVDecodeFormat(GetParam()), plane_images_size);
+ ASSERT_EQ(static_cast<size_t>(SkYUVAInfo::NumPlanes(GetParam())),
+ plane_images_size);
// Create a service-side image cache entry backed by these planes and do not
// request generating mipmap chains. The |buffer_byte_size| is only used for
@@ -271,8 +263,8 @@ TEST_P(ImageTransferCacheEntryTest, HardwareDecodedNoMipsAtCreation) {
auto entry(std::make_unique<ServiceImageTransferCacheEntry>());
EXPECT_TRUE(entry->BuildFromHardwareDecodedImage(
gr_context(), std::move(plane_images),
- GetParam() /* plane_images_format */, kJpegYUVColorSpace,
- 0u /* buffer_byte_size */, false /* needs_mips */));
+ GetParam() /* plane_images_format */, SkYUVAInfo::Subsampling::k420,
+ kJpegYUVColorSpace, 0u /* buffer_byte_size */, false /* needs_mips */));
// We didn't request generating mipmap chains, so the textures we created
// above should stay alive until after the cache entry is deleted.
@@ -289,7 +281,8 @@ TEST_P(ImageTransferCacheEntryTest, HardwareDecodedMipsAtCreation) {
std::unique_ptr<bool[]> release_flags;
std::vector<sk_sp<SkImage>> plane_images = CreateTestYUVImage(&release_flags);
const size_t plane_images_size = plane_images.size();
- ASSERT_EQ(NumberOfPlanesForYUVDecodeFormat(GetParam()), plane_images_size);
+ ASSERT_EQ(static_cast<size_t>(SkYUVAInfo::NumPlanes(GetParam())),
+ plane_images_size);
// Create a service-side image cache entry backed by these planes and request
// generating mipmap chains at creation time. The |buffer_byte_size| is only
@@ -297,8 +290,8 @@ TEST_P(ImageTransferCacheEntryTest, HardwareDecodedMipsAtCreation) {
auto entry(std::make_unique<ServiceImageTransferCacheEntry>());
EXPECT_TRUE(entry->BuildFromHardwareDecodedImage(
gr_context(), std::move(plane_images),
- GetParam() /* plane_images_format */, kJpegYUVColorSpace,
- 0u /* buffer_byte_size */, true /* needs_mips */));
+ GetParam() /* plane_images_format */, SkYUVAInfo::Subsampling::k420,
+ kJpegYUVColorSpace, 0u /* buffer_byte_size */, true /* needs_mips */));
// We requested generating mipmap chains at creation time, so the textures we
// created above should be released by now.
@@ -320,7 +313,8 @@ TEST_P(ImageTransferCacheEntryTest, HardwareDecodedMipsAfterCreation) {
std::unique_ptr<bool[]> release_flags;
std::vector<sk_sp<SkImage>> plane_images = CreateTestYUVImage(&release_flags);
const size_t plane_images_size = plane_images.size();
- ASSERT_EQ(NumberOfPlanesForYUVDecodeFormat(GetParam()), plane_images_size);
+ ASSERT_EQ(static_cast<size_t>(SkYUVAInfo::NumPlanes(GetParam())),
+ plane_images_size);
// Create a service-side image cache entry backed by these planes and do not
// request generating mipmap chains at creation time. The |buffer_byte_size|
@@ -328,8 +322,8 @@ TEST_P(ImageTransferCacheEntryTest, HardwareDecodedMipsAfterCreation) {
auto entry(std::make_unique<ServiceImageTransferCacheEntry>());
EXPECT_TRUE(entry->BuildFromHardwareDecodedImage(
gr_context(), std::move(plane_images),
- GetParam() /* plane_images_format */, kJpegYUVColorSpace,
- 0u /* buffer_byte_size */, false /* needs_mips */));
+ GetParam() /* plane_images_format */, SkYUVAInfo::Subsampling::k420,
+ kJpegYUVColorSpace, 0u /* buffer_byte_size */, false /* needs_mips */));
// We didn't request generating mip chains, so the textures we created above
// should stay alive for now.
@@ -356,14 +350,14 @@ TEST_P(ImageTransferCacheEntryTest, HardwareDecodedMipsAfterCreation) {
}
std::string TestParamToString(
- const testing::TestParamInfo<YUVDecodeFormat>& param_info) {
+ const testing::TestParamInfo<SkYUVAInfo::PlaneConfig>& param_info) {
switch (param_info.param) {
- case YUVDecodeFormat::kYUV3:
- return "YUV3";
- case YUVDecodeFormat::kYVU3:
- return "YVU3";
- case YUVDecodeFormat::kYUV2:
- return "YUV2";
+ case SkYUVAInfo::PlaneConfig::kY_U_V:
+ return "Y_U_V";
+ case SkYUVAInfo::PlaneConfig::kY_V_U:
+ return "Y_V_U";
+ case SkYUVAInfo::PlaneConfig::kY_UV:
+ return "Y_UV";
default:
NOTREACHED();
return "";
@@ -372,9 +366,9 @@ std::string TestParamToString(
INSTANTIATE_TEST_SUITE_P(All,
ImageTransferCacheEntryTest,
- ::testing::Values(YUVDecodeFormat::kYUV3,
- YUVDecodeFormat::kYVU3,
- YUVDecodeFormat::kYUV2),
+ ::testing::Values(SkYUVAInfo::PlaneConfig::kY_U_V,
+ SkYUVAInfo::PlaneConfig::kY_V_U,
+ SkYUVAInfo::PlaneConfig::kY_UV),
TestParamToString);
TEST(ImageTransferCacheEntryTestNoYUV, CPUImageWithMips) {
diff --git a/chromium/cc/paint/oop_pixeltest.cc b/chromium/cc/paint/oop_pixeltest.cc
index 0f6029834e1..d5eec1c990b 100644
--- a/chromium/cc/paint/oop_pixeltest.cc
+++ b/chromium/cc/paint/oop_pixeltest.cc
@@ -520,9 +520,9 @@ TEST_P(OopImagePixelTest, DrawImage) {
auto display_item_list = base::MakeRefCounted<DisplayItemList>();
display_item_list->StartPaint();
- PaintFlags flags;
- flags.setFilterQuality(FilterQuality());
- display_item_list->push<DrawImageOp>(paint_image, 0.f, 0.f, &flags);
+ SkSamplingOptions sampling(FilterQuality());
+ display_item_list->push<DrawImageOp>(paint_image, 0.f, 0.f, sampling,
+ nullptr);
display_item_list->EndPaintOfUnpaired(rect);
display_item_list->Finalize();
@@ -559,9 +559,9 @@ TEST_P(OopImagePixelTest, DrawImageScaled) {
auto display_item_list = base::MakeRefCounted<DisplayItemList>();
display_item_list->StartPaint();
display_item_list->push<ScaleOp>(0.5f, 0.5f);
- PaintFlags flags;
- flags.setFilterQuality(FilterQuality());
- display_item_list->push<DrawImageOp>(paint_image, 0.f, 0.f, &flags);
+ SkSamplingOptions sampling(FilterQuality());
+ display_item_list->push<DrawImageOp>(paint_image, 0.f, 0.f, sampling,
+ nullptr);
display_item_list->EndPaintOfUnpaired(rect);
display_item_list->Finalize();
@@ -633,9 +633,8 @@ TEST_P(OopImagePixelTest, DrawRecordShaderWithImageScaled) {
PaintImage::GetNextId());
auto paint_image = builder.TakePaintImage();
auto paint_record = sk_make_sp<PaintOpBuffer>();
- PaintFlags flags;
- flags.setFilterQuality(FilterQuality());
- paint_record->push<DrawImageOp>(paint_image, 0.f, 0.f, &flags);
+ SkSamplingOptions sampling(FilterQuality());
+ paint_record->push<DrawImageOp>(paint_image, 0.f, 0.f, sampling, nullptr);
auto paint_record_shader = PaintShader::MakePaintRecord(
paint_record, gfx::RectToSkRect(rect), SkTileMode::kRepeat,
SkTileMode::kRepeat, nullptr);
@@ -683,6 +682,10 @@ TEST_F(OopImagePixelTest, DrawRecordShaderTranslatedTileRect) {
sk_sp<PaintShader> paint_record_shader = PaintShader::MakePaintRecord(
shader_buffer, tile_rect, SkTileMode::kRepeat, SkTileMode::kRepeat,
nullptr, PaintShader::ScalingBehavior::kRasterAtScale);
+ // Force paint_flags to convert this to kFixedScale, so we can safely compare
+ // pixels between direct and oop-r modes (since oop will convert to
+ // kFixedScale no matter what.
+ paint_record_shader->set_has_animated_images(true);
gfx::Size output_size(10, 10);
@@ -728,9 +731,9 @@ TEST_P(OopImagePixelTest, DrawImageWithTargetColorSpace) {
auto display_item_list = base::MakeRefCounted<DisplayItemList>();
display_item_list->StartPaint();
- PaintFlags flags;
- flags.setFilterQuality(FilterQuality());
- display_item_list->push<DrawImageOp>(paint_image, 0.f, 0.f, &flags);
+ SkSamplingOptions sampling(FilterQuality());
+ display_item_list->push<DrawImageOp>(paint_image, 0.f, 0.f, sampling,
+ nullptr);
display_item_list->EndPaintOfUnpaired(rect);
display_item_list->Finalize();
@@ -774,9 +777,9 @@ TEST_P(OopImagePixelTest, DrawImageWithSourceColorSpace) {
auto display_item_list = base::MakeRefCounted<DisplayItemList>();
display_item_list->StartPaint();
- PaintFlags flags;
- flags.setFilterQuality(FilterQuality());
- display_item_list->push<DrawImageOp>(paint_image, 0.f, 0.f, &flags);
+ SkSamplingOptions sampling(FilterQuality());
+ display_item_list->push<DrawImageOp>(paint_image, 0.f, 0.f, sampling,
+ nullptr);
display_item_list->EndPaintOfUnpaired(rect);
display_item_list->Finalize();
@@ -819,9 +822,9 @@ TEST_P(OopImagePixelTest, DrawImageWithSourceAndTargetColorSpace) {
auto display_item_list = base::MakeRefCounted<DisplayItemList>();
display_item_list->StartPaint();
- PaintFlags flags;
- flags.setFilterQuality(FilterQuality());
- display_item_list->push<DrawImageOp>(paint_image, 0.f, 0.f, &flags);
+ SkSamplingOptions sampling(FilterQuality());
+ display_item_list->push<DrawImageOp>(paint_image, 0.f, 0.f, sampling,
+ nullptr);
display_item_list->EndPaintOfUnpaired(rect);
display_item_list->Finalize();
@@ -859,10 +862,10 @@ TEST_P(OopImagePixelTest, DrawImageWithSetMatrix) {
auto display_item_list = base::MakeRefCounted<DisplayItemList>();
display_item_list->StartPaint();
- PaintFlags flags;
- flags.setFilterQuality(FilterQuality());
- display_item_list->push<SetMatrixOp>(SkMatrix::Scale(0.5f, 0.5f));
- display_item_list->push<DrawImageOp>(paint_image, 0.f, 0.f, &flags);
+ SkSamplingOptions sampling(FilterQuality());
+ display_item_list->push<SetMatrixOp>(SkM44::Scale(0.5f, 0.5f));
+ display_item_list->push<DrawImageOp>(paint_image, 0.f, 0.f, sampling,
+ nullptr);
display_item_list->EndPaintOfUnpaired(rect);
display_item_list->Finalize();
@@ -934,8 +937,7 @@ TEST_F(OopPixelTest, DrawMailboxBackedImage) {
auto display_item_list = base::MakeRefCounted<DisplayItemList>();
display_item_list->StartPaint();
- PaintFlags flags;
- display_item_list->push<DrawImageOp>(src_paint_image, 0.f, 0.f, &flags);
+ display_item_list->push<DrawImageOp>(src_paint_image, 0.f, 0.f);
display_item_list->EndPaintOfUnpaired(gfx::Rect(options.resource_size));
display_item_list->Finalize();
@@ -1712,7 +1714,12 @@ class OopRecordShaderPixelTest : public OopPixelTest,
BuildTextBlob(SkTypeface::MakeDefault(), UseLcdText()), 0u, 0u, flags);
auto paint_record_shader = PaintShader::MakePaintRecord(
paint_record, SkRect::MakeWH(25, 25), SkTileMode::kRepeat,
- SkTileMode::kRepeat, nullptr);
+ SkTileMode::kRepeat, nullptr,
+ PaintShader::ScalingBehavior::kRasterAtScale);
+ // Force paint_flags to convert this to kFixedScale, so we can safely
+ // compare pixels between direct and oop-r modes (since oop will convert to
+ // kFixedScale no matter what.
+ paint_record_shader->set_has_animated_images(true);
auto display_item_list = base::MakeRefCounted<DisplayItemList>();
display_item_list->StartPaint();
@@ -1737,7 +1744,7 @@ class OopRecordFilterPixelTest : public OopPixelTest,
public ::testing::WithParamInterface<bool> {
public:
bool UseLcdText() const { return GetParam(); }
- void RunTest(const SkMatrix& mat) {
+ void RunTest(const SkM44& mat) {
RasterOptions options;
options.resource_size = gfx::Size(100, 100);
options.content_size = options.resource_size;
@@ -1771,13 +1778,16 @@ class OopRecordFilterPixelTest : public OopPixelTest,
};
TEST_P(OopRecordFilterPixelTest, FilterWithTextScaled) {
- SkMatrix mat = SkMatrix::Scale(2.f, 2.f);
+ SkM44 mat = SkM44::Scale(2.f, 2.f);
RunTest(mat);
}
TEST_P(OopRecordFilterPixelTest, FilterWithTextAndComplexCTM) {
- SkMatrix mat = SkMatrix::Scale(2.f, 2.f);
- mat.preSkew(2.f, 2.f);
+ SkM44 mat = SkM44::Scale(2.f, 2.f);
+ SkM44 skew = SkM44();
+ skew.setRC(0, 1, 2.f);
+ skew.setRC(1, 0, 2.f);
+ mat.preConcat(skew);
RunTest(mat);
}
@@ -1906,12 +1916,13 @@ TEST_F(OopPixelTest, ConvertYUVToRGB) {
auto* sii = raster_context_provider_->SharedImageInterface();
gpu::Mailbox dest_mailbox = CreateMailboxSharedImage(
ri, sii, options, viz::ResourceFormat::RGBA_8888);
- gpu::Mailbox y_mailbox = CreateMailboxSharedImage(
- ri, sii, options, viz::ResourceFormat::LUMINANCE_8);
- gpu::Mailbox u_mailbox = CreateMailboxSharedImage(
- ri, sii, uv_options, viz::ResourceFormat::LUMINANCE_8);
- gpu::Mailbox v_mailbox = CreateMailboxSharedImage(
- ri, sii, uv_options, viz::ResourceFormat::LUMINANCE_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();
@@ -1926,31 +1937,33 @@ TEST_F(OopPixelTest, ConvertYUVToRGB) {
// Upload initial yuv image data
gpu::gles2::GLES2Interface* gl = gles2_context_provider_->ContextGL();
- UploadPixels(gl, y_mailbox, options.resource_size, GL_LUMINANCE,
+ UploadPixels(gl, yuv_mailboxes[0], options.resource_size, GL_LUMINANCE,
GL_UNSIGNED_BYTE, y_pix.get());
- UploadPixels(gl, u_mailbox, uv_options.resource_size, GL_LUMINANCE,
+ UploadPixels(gl, yuv_mailboxes[1], uv_options.resource_size, GL_LUMINANCE,
GL_UNSIGNED_BYTE, u_pix.get());
- UploadPixels(gl, v_mailbox, uv_options.resource_size, GL_LUMINANCE,
+ UploadPixels(gl, yuv_mailboxes[2], uv_options.resource_size, GL_LUMINANCE,
GL_UNSIGNED_BYTE, v_pix.get());
gl->OrderingBarrierCHROMIUM();
- ri->ConvertYUVMailboxesToRGB(dest_mailbox, kJPEG_SkYUVColorSpace, y_mailbox,
- u_mailbox, v_mailbox);
+ ri->ConvertYUVAMailboxesToRGB(dest_mailbox, kJPEG_SkYUVColorSpace,
+ 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, y_mailbox, options.resource_size,
- GL_LUMINANCE8_EXT);
+ backend_textures[0] = MakeBackendTexture(
+ gl, yuv_mailboxes[0], options.resource_size, GL_LUMINANCE8_EXT);
backend_textures[1] = MakeBackendTexture(
- gl, u_mailbox, uv_options.resource_size, GL_LUMINANCE8_EXT);
+ gl, yuv_mailboxes[1], uv_options.resource_size, GL_LUMINANCE8_EXT);
backend_textures[2] = MakeBackendTexture(
- gl, v_mailbox, uv_options.resource_size, GL_LUMINANCE8_EXT);
+ gl, yuv_mailboxes[2], uv_options.resource_size, GL_LUMINANCE8_EXT);
SkYUVAInfo yuva_info(
{options.resource_size.width(), options.resource_size.height()},
- SkYUVAInfo::PlanarConfig::kY_U_V_420, kJPEG_Full_SkYUVColorSpace);
+ SkYUVAInfo::PlaneConfig::kY_U_V, SkYUVAInfo::Subsampling::k420,
+ kJPEG_Full_SkYUVColorSpace);
GrYUVABackendTextures yuva_textures(yuva_info, backend_textures,
kTopLeft_GrSurfaceOrigin);
@@ -1972,9 +1985,9 @@ TEST_F(OopPixelTest, ConvertYUVToRGB) {
gpu::SyncToken sync_token;
gl->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
sii->DestroySharedImage(sync_token, dest_mailbox);
- sii->DestroySharedImage(sync_token, y_mailbox);
- sii->DestroySharedImage(sync_token, u_mailbox);
- sii->DestroySharedImage(sync_token, v_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) {
@@ -2031,10 +2044,11 @@ TEST_F(OopPixelTest, ConvertNV12ToRGB) {
gpu::Mailbox dest_mailbox = CreateMailboxSharedImage(
ri, sii, options, viz::ResourceFormat::RGBA_8888);
- gpu::Mailbox y_mailbox = CreateMailboxSharedImage(
- ri, sii, options, viz::ResourceFormat::LUMINANCE_8);
- gpu::Mailbox uv_mailbox =
- CreateMailboxSharedImage(ri, sii, uv_options, viz::ResourceFormat::RG_88);
+ gpu::Mailbox y_uv_mailboxes[2]{
+ CreateMailboxSharedImage(ri, sii, options,
+ viz::ResourceFormat::LUMINANCE_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;
@@ -2048,27 +2062,29 @@ TEST_F(OopPixelTest, ConvertNV12ToRGB) {
}
gpu::gles2::GLES2Interface* gl = gles2_context_provider_->ContextGL();
- UploadPixels(gl, y_mailbox, options.resource_size, GL_LUMINANCE,
+ UploadPixels(gl, y_uv_mailboxes[0], options.resource_size, GL_LUMINANCE,
GL_UNSIGNED_BYTE, y_pix.get());
- UploadPixels(gl, uv_mailbox, uv_options.resource_size, GL_RG,
+ UploadPixels(gl, y_uv_mailboxes[1], uv_options.resource_size, GL_RG,
GL_UNSIGNED_BYTE, uv_pix.get());
gl->OrderingBarrierCHROMIUM();
- ri->ConvertNV12MailboxesToRGB(dest_mailbox, kJPEG_SkYUVColorSpace, y_mailbox,
- uv_mailbox);
+ ri->ConvertYUVAMailboxesToRGB(dest_mailbox, kJPEG_SkYUVColorSpace,
+ 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_mailbox, options.resource_size,
- GL_LUMINANCE8_EXT);
- backend_textures[1] =
- MakeBackendTexture(gl, uv_mailbox, uv_options.resource_size, GL_RG8);
+ 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::PlanarConfig::kY_UV_420, kJPEG_Full_SkYUVColorSpace);
+ SkYUVAInfo::PlaneConfig::kY_UV, SkYUVAInfo::Subsampling::k420,
+ kJPEG_Full_SkYUVColorSpace);
GrYUVABackendTextures yuva_textures(yuva_info, backend_textures,
kTopLeft_GrSurfaceOrigin);
auto expected_image = SkImage::MakeFromYUVATextures(
@@ -2089,8 +2105,8 @@ TEST_F(OopPixelTest, ConvertNV12ToRGB) {
gpu::SyncToken sync_token;
gl->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
sii->DestroySharedImage(sync_token, dest_mailbox);
- sii->DestroySharedImage(sync_token, y_mailbox);
- sii->DestroySharedImage(sync_token, uv_mailbox);
+ sii->DestroySharedImage(sync_token, y_uv_mailboxes[0]);
+ sii->DestroySharedImage(sync_token, y_uv_mailboxes[1]);
}
#endif // !defined(OS_ANDROID)
diff --git a/chromium/cc/paint/paint_canvas.h b/chromium/cc/paint/paint_canvas.h
index 2b9c34a2336..e22af8127f6 100644
--- a/chromium/cc/paint/paint_canvas.h
+++ b/chromium/cc/paint/paint_canvas.h
@@ -76,8 +76,12 @@ class CC_PAINT_EXPORT PaintCanvas {
virtual void translate(SkScalar dx, SkScalar dy) = 0;
virtual void scale(SkScalar sx, SkScalar sy) = 0;
virtual void rotate(SkScalar degrees) = 0;
+ // TODO(aaronhk): crbug.com/1153330 deprecate these in favor of the SkM44
+ // versions.
virtual void concat(const SkMatrix& matrix) = 0;
virtual void setMatrix(const SkMatrix& matrix) = 0;
+ virtual void concat(const SkM44& matrix) = 0;
+ virtual void setMatrix(const SkM44& matrix) = 0;
virtual void clipRect(const SkRect& rect,
SkClipOp op,
@@ -141,16 +145,24 @@ class CC_PAINT_EXPORT PaintCanvas {
virtual void drawImage(const PaintImage& image,
SkScalar left,
SkScalar top,
+ const SkSamplingOptions&,
const PaintFlags* flags) = 0;
void drawImage(const PaintImage& image, SkScalar left, SkScalar top) {
- drawImage(image, left, top, nullptr);
+ drawImage(image, left, top, SkSamplingOptions(), nullptr);
}
virtual void drawImageRect(const PaintImage& image,
const SkRect& src,
const SkRect& dst,
+ const SkSamplingOptions&,
const PaintFlags* flags,
SkCanvas::SrcRectConstraint constraint) = 0;
+ void drawImageRect(const PaintImage& image,
+ const SkRect& src,
+ const SkRect& dst,
+ SkCanvas::SrcRectConstraint constraint) {
+ drawImageRect(image, src, dst, SkSamplingOptions(), nullptr, constraint);
+ }
// Draws the frame of the |skottie| animation specified by the normalized time
// t [0->first frame..1->last frame] at the destination bounds given by |dst|
diff --git a/chromium/cc/paint/paint_filter.cc b/chromium/cc/paint/paint_filter.cc
index 5018eb8bf7e..9e32ec4b729 100644
--- a/chromium/cc/paint/paint_filter.cc
+++ b/chromium/cc/paint/paint_filter.cc
@@ -10,21 +10,8 @@
#include "cc/paint/paint_record.h"
#include "third_party/skia/include/core/SkColorFilter.h"
#include "third_party/skia/include/core/SkMath.h"
-#include "third_party/skia/include/effects/SkAlphaThresholdFilter.h"
-#include "third_party/skia/include/effects/SkArithmeticImageFilter.h"
-#include "third_party/skia/include/effects/SkColorFilterImageFilter.h"
-#include "third_party/skia/include/effects/SkComposeImageFilter.h"
-#include "third_party/skia/include/effects/SkImageSource.h"
-#include "third_party/skia/include/effects/SkLightingImageFilter.h"
-#include "third_party/skia/include/effects/SkMagnifierImageFilter.h"
-#include "third_party/skia/include/effects/SkMergeImageFilter.h"
-#include "third_party/skia/include/effects/SkMorphologyImageFilter.h"
-#include "third_party/skia/include/effects/SkOffsetImageFilter.h"
-#include "third_party/skia/include/effects/SkPaintImageFilter.h"
+#include "third_party/skia/include/effects/SkImageFilters.h"
#include "third_party/skia/include/effects/SkPerlinNoiseShader.h"
-#include "third_party/skia/include/effects/SkPictureImageFilter.h"
-#include "third_party/skia/include/effects/SkTileImageFilter.h"
-#include "third_party/skia/include/effects/SkXfermodeImageFilter.h"
namespace cc {
namespace {
@@ -140,8 +127,7 @@ size_t PaintFilter::BaseSerializedSize() const {
total_size += sizeof(uint32_t);
if (crop_rect_) {
// CropRect.
- total_size += sizeof(crop_rect_->flags());
- total_size += sizeof(crop_rect_->rect());
+ total_size += sizeof(*crop_rect_);
}
return total_size;
}
@@ -159,9 +145,7 @@ bool PaintFilter::operator==(const PaintFilter& other) const {
if (!!crop_rect_ != !!other.crop_rect_)
return false;
if (crop_rect_) {
- if (crop_rect_->flags() != other.crop_rect_->flags() ||
- !PaintOp::AreSkRectsEqual(crop_rect_->rect(),
- other.crop_rect_->rect())) {
+ if (!PaintOp::AreSkRectsEqual(*crop_rect_, *other.crop_rect_)) {
return false;
}
}
@@ -248,7 +232,7 @@ ColorFilterPaintFilter::ColorFilterPaintFilter(
color_filter_(std::move(color_filter)),
input_(std::move(input)) {
DCHECK(color_filter_);
- cached_sk_filter_ = SkColorFilterImageFilter::Make(
+ cached_sk_filter_ = SkImageFilters::ColorFilter(
color_filter_, GetSkFilter(input_.get()), crop_rect);
}
@@ -277,7 +261,7 @@ bool ColorFilterPaintFilter::operator==(
BlurPaintFilter::BlurPaintFilter(SkScalar sigma_x,
SkScalar sigma_y,
- TileMode tile_mode,
+ SkTileMode tile_mode,
sk_sp<PaintFilter> input,
const CropRect* crop_rect)
: PaintFilter(kType, crop_rect, HasDiscardableImages(input)),
@@ -285,8 +269,8 @@ BlurPaintFilter::BlurPaintFilter(SkScalar sigma_x,
sigma_y_(sigma_y),
tile_mode_(tile_mode),
input_(std::move(input)) {
- cached_sk_filter_ = SkBlurImageFilter::Make(
- sigma_x_, sigma_y_, GetSkFilter(input_.get()), crop_rect, tile_mode_);
+ cached_sk_filter_ = SkImageFilters::Blur(
+ sigma_x, sigma_y, tile_mode_, GetSkFilter(input_.get()), crop_rect);
}
BlurPaintFilter::~BlurPaintFilter() = default;
@@ -329,9 +313,15 @@ DropShadowPaintFilter::DropShadowPaintFilter(SkScalar dx,
color_(color),
shadow_mode_(shadow_mode),
input_(std::move(input)) {
- cached_sk_filter_ = SkDropShadowImageFilter::Make(
- dx_, dy_, sigma_x_, sigma_y_, color_, shadow_mode_,
- GetSkFilter(input_.get()), crop_rect);
+ if (shadow_mode == ShadowMode::kDrawShadowOnly) {
+ cached_sk_filter_ =
+ SkImageFilters::DropShadowOnly(dx_, dy_, sigma_x_, sigma_y_, color_,
+ GetSkFilter(input_.get()), crop_rect);
+ } else {
+ cached_sk_filter_ =
+ SkImageFilters::DropShadow(dx_, dy_, sigma_x_, sigma_y_, color_,
+ GetSkFilter(input_.get()), crop_rect);
+ }
}
DropShadowPaintFilter::~DropShadowPaintFilter() = default;
@@ -369,7 +359,7 @@ MagnifierPaintFilter::MagnifierPaintFilter(const SkRect& src_rect,
src_rect_(src_rect),
inset_(inset),
input_(std::move(input)) {
- cached_sk_filter_ = SkMagnifierImageFilter::Make(
+ cached_sk_filter_ = SkImageFilters::Magnifier(
src_rect_, inset_, GetSkFilter(input_.get()), crop_rect);
}
@@ -401,8 +391,8 @@ ComposePaintFilter::ComposePaintFilter(sk_sp<PaintFilter> outer,
HasDiscardableImages(outer) || HasDiscardableImages(inner)),
outer_(std::move(outer)),
inner_(std::move(inner)) {
- cached_sk_filter_ = SkComposeImageFilter::Make(GetSkFilter(outer_.get()),
- GetSkFilter(inner_.get()));
+ cached_sk_filter_ = SkImageFilters::Compose(GetSkFilter(outer_.get()),
+ GetSkFilter(inner_.get()));
}
ComposePaintFilter::~ComposePaintFilter() = default;
@@ -435,7 +425,7 @@ AlphaThresholdPaintFilter::AlphaThresholdPaintFilter(const SkRegion& region,
inner_min_(inner_min),
outer_max_(outer_max),
input_(std::move(input)) {
- cached_sk_filter_ = SkAlphaThresholdFilter::Make(
+ cached_sk_filter_ = SkImageFilters::AlphaThreshold(
region_, inner_min_, outer_max_, GetSkFilter(input_.get()), crop_rect);
}
@@ -477,8 +467,8 @@ XfermodePaintFilter::XfermodePaintFilter(SkBlendMode blend_mode,
background_(std::move(background)),
foreground_(std::move(foreground)) {
cached_sk_filter_ =
- SkXfermodeImageFilter::Make(blend_mode_, GetSkFilter(background_.get()),
- GetSkFilter(foreground_.get()), crop_rect);
+ SkImageFilters::Blend(blend_mode_, GetSkFilter(background_.get()),
+ GetSkFilter(foreground_.get()), crop_rect);
}
XfermodePaintFilter::~XfermodePaintFilter() = default;
@@ -523,7 +513,7 @@ ArithmeticPaintFilter::ArithmeticPaintFilter(float k1,
enforce_pm_color_(enforce_pm_color),
background_(std::move(background)),
foreground_(std::move(foreground)) {
- cached_sk_filter_ = SkArithmeticImageFilter::Make(
+ cached_sk_filter_ = SkImageFilters::Arithmetic(
k1_, k2_, k3_, k4_, enforce_pm_color_, GetSkFilter(background_.get()),
GetSkFilter(foreground_.get()), crop_rect);
}
@@ -564,7 +554,7 @@ MatrixConvolutionPaintFilter::MatrixConvolutionPaintFilter(
SkScalar gain,
SkScalar bias,
const SkIPoint& kernel_offset,
- TileMode tile_mode,
+ SkTileMode tile_mode,
bool convolve_alpha,
sk_sp<PaintFilter> input,
const CropRect* crop_rect)
@@ -582,7 +572,7 @@ MatrixConvolutionPaintFilter::MatrixConvolutionPaintFilter(
for (size_t i = 0; i < len; ++i)
kernel_->push_back(kernel[i]);
- cached_sk_filter_ = SkMatrixConvolutionImageFilter::Make(
+ cached_sk_filter_ = SkImageFilters::MatrixConvolution(
kernel_size_, kernel, gain_, bias_, kernel_offset_, tile_mode_,
convolve_alpha_, GetSkFilter(input_.get()), crop_rect);
}
@@ -619,8 +609,8 @@ bool MatrixConvolutionPaintFilter::operator==(
}
DisplacementMapEffectPaintFilter::DisplacementMapEffectPaintFilter(
- ChannelSelectorType channel_x,
- ChannelSelectorType channel_y,
+ SkColorChannel channel_x,
+ SkColorChannel channel_y,
SkScalar scale,
sk_sp<PaintFilter> displacement,
sk_sp<PaintFilter> color,
@@ -634,7 +624,7 @@ DisplacementMapEffectPaintFilter::DisplacementMapEffectPaintFilter(
scale_(scale),
displacement_(std::move(displacement)),
color_(std::move(color)) {
- cached_sk_filter_ = SkDisplacementMapEffect::Make(
+ cached_sk_filter_ = SkImageFilters::DisplacementMap(
channel_x_, channel_y_, scale_, GetSkFilter(displacement_.get()),
GetSkFilter(color_.get()), crop_rect);
}
@@ -643,8 +633,8 @@ DisplacementMapEffectPaintFilter::~DisplacementMapEffectPaintFilter() = default;
size_t DisplacementMapEffectPaintFilter::SerializedSize() const {
base::CheckedNumeric<size_t> total_size = BaseSerializedSize() +
- sizeof(uint32_t) +
- sizeof(uint32_t) + sizeof(scale_);
+ sizeof(channel_x_) +
+ sizeof(channel_y_) + sizeof(scale_);
total_size += GetFilterSize(displacement_.get());
total_size += GetFilterSize(color_.get());
return total_size.ValueOrDefault(0u);
@@ -674,8 +664,10 @@ ImagePaintFilter::ImagePaintFilter(PaintImage image,
src_rect_(src_rect),
dst_rect_(dst_rect),
filter_quality_(filter_quality) {
- cached_sk_filter_ = SkImageSource::Make(image_.GetSkImage(), src_rect_,
- dst_rect_, filter_quality_);
+ SkSamplingOptions sampling(filter_quality,
+ SkSamplingOptions::kMedium_asMipmapLinear);
+ cached_sk_filter_ = SkImageFilters::Image(image_.GetSkImage(), src_rect_,
+ dst_rect_, sampling);
}
ImagePaintFilter::~ImagePaintFilter() = default;
@@ -726,7 +718,7 @@ RecordPaintFilter::RecordPaintFilter(sk_sp<PaintRecord> record,
: PaintFilter(kType, nullptr, record->HasDiscardableImages()),
record_(std::move(record)),
record_bounds_(record_bounds) {
- cached_sk_filter_ = SkPictureImageFilter::Make(
+ cached_sk_filter_ = SkImageFilters::Picture(
ToSkPicture(record_, record_bounds_, image_provider));
}
@@ -770,7 +762,7 @@ MergePaintFilter::MergePaintFilter(const sk_sp<PaintFilter>* const filters,
sk_filters.push_back(GetSkFilter(inputs_->back().get()));
}
- cached_sk_filter_ = SkMergeImageFilter::Make(
+ cached_sk_filter_ = SkImageFilters::Merge(
static_cast<sk_sp<SkImageFilter>*>(sk_filters.data()), count, crop_rect);
}
@@ -813,11 +805,11 @@ MorphologyPaintFilter::MorphologyPaintFilter(MorphType morph_type,
input_(std::move(input)) {
switch (morph_type_) {
case MorphType::kDilate:
- cached_sk_filter_ = SkDilateImageFilter::Make(
+ cached_sk_filter_ = SkImageFilters::Dilate(
radius_x_, radius_y_, GetSkFilter(input_.get()), crop_rect);
break;
case MorphType::kErode:
- cached_sk_filter_ = SkErodeImageFilter::Make(
+ cached_sk_filter_ = SkImageFilters::Erode(
radius_x_, radius_y_, GetSkFilter(input_.get()), crop_rect);
break;
}
@@ -856,7 +848,7 @@ OffsetPaintFilter::OffsetPaintFilter(SkScalar dx,
dy_(dy),
input_(std::move(input)) {
cached_sk_filter_ =
- SkOffsetImageFilter::Make(dx_, dy_, GetSkFilter(input_.get()), crop_rect);
+ SkImageFilters::Offset(dx_, dy_, GetSkFilter(input_.get()), crop_rect);
}
OffsetPaintFilter::~OffsetPaintFilter() = default;
@@ -888,7 +880,7 @@ TilePaintFilter::TilePaintFilter(const SkRect& src,
dst_(dst),
input_(std::move(input)) {
cached_sk_filter_ =
- SkTileImageFilter::Make(src_, dst_, GetSkFilter(input_.get()));
+ SkImageFilters::Tile(src_, dst_, GetSkFilter(input_.get()));
}
TilePaintFilter::~TilePaintFilter() = default;
@@ -940,9 +932,7 @@ TurbulencePaintFilter::TurbulencePaintFilter(TurbulenceType turbulence_type,
break;
}
- SkPaint paint;
- paint.setShader(std::move(shader));
- cached_sk_filter_ = SkPaintImageFilter::Make(paint, crop_rect);
+ cached_sk_filter_ = SkImageFilters::Shader(std::move(shader), crop_rect);
}
TurbulencePaintFilter::~TurbulencePaintFilter() = default;
@@ -984,9 +974,37 @@ PaintFlagsPaintFilter::PaintFlagsPaintFilter(PaintFlags flags,
if (image_provider) {
raster_flags_.emplace(&flags_, image_provider, SkMatrix::I(), 0, 255u);
}
- cached_sk_filter_ = SkPaintImageFilter::Make(
- raster_flags_ ? raster_flags_->flags()->ToSkPaint() : flags_.ToSkPaint(),
- crop_rect);
+
+ const SkPaint& paint =
+ raster_flags_ ? raster_flags_->flags()->ToSkPaint() : flags_.ToSkPaint();
+ // The paint flags should only be a color, shader, and filter quality,
+ // just DCHECK to make sure caller expectations are not valid.
+ DCHECK(paint.getBlendMode() == SkBlendMode::kSrcOver);
+ DCHECK(paint.getStyle() == SkPaint::kFill_Style);
+ DCHECK(!paint.getPathEffect());
+ DCHECK(!paint.getMaskFilter());
+ DCHECK(!paint.getImageFilter());
+ DCHECK(!paint.getColorFilter());
+
+ sk_sp<SkShader> shader = paint.refShader();
+ if (shader) {
+ // Combine paint's alpha if the color isn't opaque (the constant RGB is
+ // overridden by the shader's per-pixel color).
+ if (paint.getAlpha() < 255) {
+ // The blend effectively produces (shader * paint alpha).
+ shader = SkShaders::Blend(SkBlendMode::kDstIn, std::move(shader),
+ SkShaders::Color(paint.getColor()));
+ }
+ } else {
+ shader = SkShaders::Color(paint.getColor());
+ }
+
+ // TODO(michaelludwig): Remove SkFilterQuality arg once all image shaders are
+ // created with explicit filter settings
+ using Dither = SkImageFilters::Dither;
+ cached_sk_filter_ = SkImageFilters::Shader(
+ std::move(shader), paint.isDither() ? Dither::kYes : Dither::kNo,
+ paint.getFilterQuality(), crop_rect);
}
PaintFlagsPaintFilter::~PaintFlagsPaintFilter() = default;
@@ -1015,7 +1033,7 @@ MatrixPaintFilter::MatrixPaintFilter(const SkMatrix& matrix,
matrix_(matrix),
filter_quality_(filter_quality),
input_(std::move(input)) {
- cached_sk_filter_ = SkImageFilter::MakeMatrixFilter(
+ cached_sk_filter_ = SkImageFilters::MatrixTransform(
matrix_, filter_quality_, GetSkFilter(input_.get()));
}
@@ -1059,12 +1077,12 @@ LightingDistantPaintFilter::LightingDistantPaintFilter(
input_(std::move(input)) {
switch (lighting_type_) {
case LightingType::kDiffuse:
- cached_sk_filter_ = SkLightingImageFilter::MakeDistantLitDiffuse(
+ cached_sk_filter_ = SkImageFilters::DistantLitDiffuse(
direction_, light_color_, surface_scale_, kconstant_,
GetSkFilter(input_.get()), crop_rect);
break;
case LightingType::kSpecular:
- cached_sk_filter_ = SkLightingImageFilter::MakeDistantLitSpecular(
+ cached_sk_filter_ = SkImageFilters::DistantLitSpecular(
direction_, light_color_, surface_scale_, kconstant_, shininess_,
GetSkFilter(input_.get()), crop_rect);
break;
@@ -1118,12 +1136,12 @@ LightingPointPaintFilter::LightingPointPaintFilter(LightingType lighting_type,
input_(std::move(input)) {
switch (lighting_type_) {
case LightingType::kDiffuse:
- cached_sk_filter_ = SkLightingImageFilter::MakePointLitDiffuse(
+ cached_sk_filter_ = SkImageFilters::PointLitDiffuse(
location_, light_color_, surface_scale_, kconstant_,
GetSkFilter(input_.get()), crop_rect);
break;
case LightingType::kSpecular:
- cached_sk_filter_ = SkLightingImageFilter::MakePointLitSpecular(
+ cached_sk_filter_ = SkImageFilters::PointLitSpecular(
location_, light_color_, surface_scale_, kconstant_, shininess_,
GetSkFilter(input_.get()), crop_rect);
break;
@@ -1183,12 +1201,12 @@ LightingSpotPaintFilter::LightingSpotPaintFilter(LightingType lighting_type,
input_(std::move(input)) {
switch (lighting_type_) {
case LightingType::kDiffuse:
- cached_sk_filter_ = SkLightingImageFilter::MakeSpotLitDiffuse(
+ cached_sk_filter_ = SkImageFilters::SpotLitDiffuse(
location_, target_, specular_exponent_, cutoff_angle_, light_color_,
surface_scale_, kconstant_, GetSkFilter(input_.get()), crop_rect);
break;
case LightingType::kSpecular:
- cached_sk_filter_ = SkLightingImageFilter::MakeSpotLitSpecular(
+ cached_sk_filter_ = SkImageFilters::SpotLitSpecular(
location_, target_, specular_exponent_, cutoff_angle_, light_color_,
surface_scale_, kconstant_, shininess_, GetSkFilter(input_.get()),
crop_rect);
diff --git a/chromium/cc/paint/paint_filter.h b/chromium/cc/paint/paint_filter.h
index 556ab9a91e8..e4e5adcdbfb 100644
--- a/chromium/cc/paint/paint_filter.h
+++ b/chromium/cc/paint/paint_filter.h
@@ -17,10 +17,6 @@
#include "third_party/skia/include/core/SkImageFilter.h"
#include "third_party/skia/include/core/SkPoint3.h"
#include "third_party/skia/include/core/SkRegion.h"
-#include "third_party/skia/include/effects/SkBlurImageFilter.h"
-#include "third_party/skia/include/effects/SkDisplacementMapEffect.h"
-#include "third_party/skia/include/effects/SkDropShadowImageFilter.h"
-#include "third_party/skia/include/effects/SkMatrixConvolutionImageFilter.h"
namespace viz {
class GLRenderer;
@@ -33,7 +29,7 @@ class ImageProvider;
class CC_PAINT_EXPORT PaintFilter : public SkRefCnt {
public:
- enum class Type : uint32_t {
+ enum class Type {
// For serialization purposes, we reserve one enum to indicate that there
// was no PaintFilter, ie the filter is "null".
kNullFilter,
@@ -60,17 +56,17 @@ class CC_PAINT_EXPORT PaintFilter : public SkRefCnt {
kLightingPoint,
kLightingSpot,
// Update the following if kLightingSpot is not the max anymore.
- kMaxFilterType = kLightingSpot
+ kMaxValue = kLightingSpot
};
- enum class LightingType : uint32_t {
+ enum class LightingType {
kDiffuse,
kSpecular,
// Update the following if kSpecular is not the max anymore.
- kMaxLightingType = kSpecular
+ kMaxValue = kSpecular
};
using MapDirection = SkImageFilter::MapDirection;
- using CropRect = SkImageFilter::CropRect;
+ using CropRect = SkRect;
PaintFilter(const PaintFilter&) = delete;
~PaintFilter() override;
@@ -186,11 +182,10 @@ class CC_PAINT_EXPORT ColorFilterPaintFilter final : public PaintFilter {
class CC_PAINT_EXPORT BlurPaintFilter final : public PaintFilter {
public:
- using TileMode = SkBlurImageFilter::TileMode;
static constexpr Type kType = Type::kBlur;
BlurPaintFilter(SkScalar sigma_x,
SkScalar sigma_y,
- TileMode tile_mode,
+ SkTileMode tile_mode,
sk_sp<PaintFilter> input,
const CropRect* crop_rect = nullptr);
~BlurPaintFilter() override;
@@ -199,7 +194,7 @@ class CC_PAINT_EXPORT BlurPaintFilter final : public PaintFilter {
SkScalar sigma_x() const { return sigma_x_; }
SkScalar sigma_y() const { return sigma_y_; }
- TileMode tile_mode() const { return tile_mode_; }
+ SkTileMode tile_mode() const { return tile_mode_; }
size_t SerializedSize() const override;
bool operator==(const BlurPaintFilter& other) const;
@@ -211,13 +206,17 @@ class CC_PAINT_EXPORT BlurPaintFilter final : public PaintFilter {
private:
SkScalar sigma_x_;
SkScalar sigma_y_;
- TileMode tile_mode_;
+ SkTileMode tile_mode_;
sk_sp<PaintFilter> input_;
};
class CC_PAINT_EXPORT DropShadowPaintFilter final : public PaintFilter {
public:
- using ShadowMode = SkDropShadowImageFilter::ShadowMode;
+ enum class ShadowMode {
+ kDrawShadowAndForeground,
+ kDrawShadowOnly,
+ kMaxValue = kDrawShadowOnly
+ };
static constexpr Type kType = Type::kDropShadow;
DropShadowPaintFilter(SkScalar dx,
SkScalar dy,
@@ -396,14 +395,13 @@ class CC_PAINT_EXPORT ArithmeticPaintFilter final : public PaintFilter {
class CC_PAINT_EXPORT MatrixConvolutionPaintFilter final : public PaintFilter {
public:
- using TileMode = SkMatrixConvolutionImageFilter::TileMode;
static constexpr Type kType = Type::kMatrixConvolution;
MatrixConvolutionPaintFilter(const SkISize& kernel_size,
const SkScalar* kernel,
SkScalar gain,
SkScalar bias,
const SkIPoint& kernel_offset,
- TileMode tile_mode,
+ SkTileMode tile_mode,
bool convolve_alpha,
sk_sp<PaintFilter> input,
const CropRect* crop_rect = nullptr);
@@ -414,7 +412,7 @@ class CC_PAINT_EXPORT MatrixConvolutionPaintFilter final : public PaintFilter {
SkScalar gain() const { return gain_; }
SkScalar bias() const { return bias_; }
SkIPoint kernel_offset() const { return kernel_offset_; }
- TileMode tile_mode() const { return tile_mode_; }
+ SkTileMode tile_mode() const { return tile_mode_; }
bool convolve_alpha() const { return convolve_alpha_; }
const sk_sp<PaintFilter>& input() const { return input_; }
@@ -431,7 +429,7 @@ class CC_PAINT_EXPORT MatrixConvolutionPaintFilter final : public PaintFilter {
SkScalar gain_;
SkScalar bias_;
SkIPoint kernel_offset_;
- TileMode tile_mode_;
+ SkTileMode tile_mode_;
bool convolve_alpha_;
sk_sp<PaintFilter> input_;
};
@@ -439,18 +437,17 @@ class CC_PAINT_EXPORT MatrixConvolutionPaintFilter final : public PaintFilter {
class CC_PAINT_EXPORT DisplacementMapEffectPaintFilter final
: public PaintFilter {
public:
- using ChannelSelectorType = SkDisplacementMapEffect::ChannelSelectorType;
static constexpr Type kType = Type::kDisplacementMapEffect;
- DisplacementMapEffectPaintFilter(ChannelSelectorType channel_x,
- ChannelSelectorType channel_y,
+ DisplacementMapEffectPaintFilter(SkColorChannel channel_x,
+ SkColorChannel channel_y,
SkScalar scale,
sk_sp<PaintFilter> displacement,
sk_sp<PaintFilter> color,
const CropRect* crop_rect = nullptr);
~DisplacementMapEffectPaintFilter() override;
- ChannelSelectorType channel_x() const { return channel_x_; }
- ChannelSelectorType channel_y() const { return channel_y_; }
+ SkColorChannel channel_x() const { return channel_x_; }
+ SkColorChannel channel_y() const { return channel_y_; }
SkScalar scale() const { return scale_; }
const sk_sp<PaintFilter>& displacement() const { return displacement_; }
const sk_sp<PaintFilter>& color() const { return color_; }
@@ -463,8 +460,8 @@ class CC_PAINT_EXPORT DisplacementMapEffectPaintFilter final
ImageProvider* image_provider) const override;
private:
- ChannelSelectorType channel_x_;
- ChannelSelectorType channel_y_;
+ SkColorChannel channel_x_;
+ SkColorChannel channel_y_;
SkScalar scale_;
sk_sp<PaintFilter> displacement_;
sk_sp<PaintFilter> color_;
@@ -554,7 +551,7 @@ class CC_PAINT_EXPORT MergePaintFilter final : public PaintFilter {
class CC_PAINT_EXPORT MorphologyPaintFilter final : public PaintFilter {
public:
- enum class MorphType : uint32_t { kDilate, kErode, kMaxMorphType = kErode };
+ enum class MorphType { kDilate, kErode, kMaxValue = kErode };
static constexpr Type kType = Type::kMorphology;
MorphologyPaintFilter(MorphType morph_type,
float radius_x,
@@ -636,10 +633,10 @@ class CC_PAINT_EXPORT TilePaintFilter final : public PaintFilter {
class CC_PAINT_EXPORT TurbulencePaintFilter final : public PaintFilter {
public:
static constexpr Type kType = Type::kTurbulence;
- enum class TurbulenceType : uint32_t {
+ enum class TurbulenceType {
kTurbulence,
kFractalNoise,
- kMaxTurbulenceType = kFractalNoise
+ kMaxValue = kFractalNoise
};
TurbulencePaintFilter(TurbulenceType turbulence_type,
SkScalar base_frequency_x,
diff --git a/chromium/cc/paint/paint_filter_unittest.cc b/chromium/cc/paint/paint_filter_unittest.cc
index 9e562561b0d..c3461250003 100644
--- a/chromium/cc/paint/paint_filter_unittest.cc
+++ b/chromium/cc/paint/paint_filter_unittest.cc
@@ -23,7 +23,7 @@ class MockImageProvider : public ImageProvider {
return ScopedResult(
DecodedDrawImage(CreateBitmapImage(gfx::Size(10, 10)).GetSwSkImage(),
nullptr, SkSize::MakeEmpty(), SkSize::Make(1.0f, 1.0f),
- draw_image.filter_quality()));
+ draw_image.filter_quality(), true));
}
int image_count_ = 0;
};
@@ -40,11 +40,11 @@ sk_sp<PaintFilter> CreateTestFilter(PaintFilter::Type filter_type,
image, SkRect::MakeWH(100.f, 100.f), SkRect::MakeWH(100.f, 100.f),
kNone_SkFilterQuality);
auto record = sk_make_sp<PaintOpBuffer>();
- record->push<DrawImageOp>(image, 0.f, 0.f, nullptr);
+ record->push<DrawImageOp>(image, 0.f, 0.f);
auto record_filter =
sk_make_sp<RecordPaintFilter>(record, SkRect::MakeWH(100.f, 100.f));
- SkImageFilter::CropRect crop_rect(SkRect::MakeWH(100.f, 100.f));
+ PaintFilter::CropRect crop_rect(SkRect::MakeWH(100.f, 100.f));
switch (filter_type) {
case PaintFilter::Type::kNullFilter:
@@ -54,13 +54,12 @@ sk_sp<PaintFilter> CreateTestFilter(PaintFilter::Type filter_type,
return sk_make_sp<ColorFilterPaintFilter>(SkLumaColorFilter::Make(),
image_filter, &crop_rect);
case PaintFilter::Type::kBlur:
- return sk_make_sp<BlurPaintFilter>(0.1f, 0.2f,
- SkBlurImageFilter::kClamp_TileMode,
+ return sk_make_sp<BlurPaintFilter>(0.1f, 0.2f, SkTileMode::kClamp,
record_filter, &crop_rect);
case PaintFilter::Type::kDropShadow:
return sk_make_sp<DropShadowPaintFilter>(
0.1, 0.2f, 0.3f, 0.4f, SK_ColorWHITE,
- SkDropShadowImageFilter::kDrawShadowOnly_ShadowMode, image_filter,
+ DropShadowPaintFilter::ShadowMode::kDrawShadowOnly, image_filter,
&crop_rect);
case PaintFilter::Type::kMagnifier:
return sk_make_sp<MagnifierPaintFilter>(SkRect::MakeWH(100.f, 100.f),
@@ -82,14 +81,12 @@ sk_sp<PaintFilter> CreateTestFilter(PaintFilter::Type filter_type,
SkScalar scalars[9] = {1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f};
return sk_make_sp<MatrixConvolutionPaintFilter>(
SkISize::Make(3, 3), scalars, 0.1f, 0.2f, SkIPoint::Make(2, 2),
- SkMatrixConvolutionImageFilter::TileMode::kRepeat_TileMode, false,
- image_filter, &crop_rect);
+ SkTileMode::kRepeat, false, image_filter, &crop_rect);
}
case PaintFilter::Type::kDisplacementMapEffect:
return sk_make_sp<DisplacementMapEffectPaintFilter>(
- SkDisplacementMapEffect::ChannelSelectorType::kR_ChannelSelectorType,
- SkDisplacementMapEffect::ChannelSelectorType::kR_ChannelSelectorType,
- 0.1f, image_filter, record_filter, &crop_rect);
+ SkColorChannel::kR, SkColorChannel::kR, 0.1f, image_filter,
+ record_filter, &crop_rect);
case PaintFilter::Type::kImage:
return image_filter;
case PaintFilter::Type::kPaintRecord:
@@ -153,7 +150,7 @@ INSTANTIATE_TEST_SUITE_P(
P,
PaintFilterTest,
::testing::Range(static_cast<uint8_t>(PaintFilter::Type::kColorFilter),
- static_cast<uint8_t>(PaintFilter::Type::kMaxFilterType)));
+ static_cast<uint8_t>(PaintFilter::Type::kMaxValue)));
TEST_P(PaintFilterTest, HasDiscardableImagesYes) {
// TurbulencePaintFilter can not embed images.
diff --git a/chromium/cc/paint/paint_image.cc b/chromium/cc/paint/paint_image.cc
index 70853e09ca3..f57728dd4ef 100644
--- a/chromium/cc/paint/paint_image.cc
+++ b/chromium/cc/paint/paint_image.cc
@@ -298,11 +298,6 @@ void PaintImage::FlushPendingSkiaOps() {
texture_backing_->FlushPendingSkiaOps();
}
-bool PaintImage::HasExclusiveTextureAccess() const {
- DCHECK(IsTextureBacked());
- return texture_backing_->unique();
-}
-
int PaintImage::width() const {
return paint_worklet_input_
? static_cast<int>(paint_worklet_input_->GetSize().width())
diff --git a/chromium/cc/paint/paint_image.h b/chromium/cc/paint/paint_image.h
index 237ab4d8576..ab1a18c7f2d 100644
--- a/chromium/cc/paint/paint_image.h
+++ b/chromium/cc/paint/paint_image.h
@@ -21,6 +21,10 @@
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
+namespace blink {
+class VideoFrame;
+}
+
namespace cc {
class PaintImageGenerator;
@@ -235,11 +239,11 @@ class CC_PAINT_EXPORT PaintImage {
int src_x,
int src_y) const;
- SkImageInfo GetSkImageInfo() const;
+ // Returned mailbox must not outlive this PaintImage.
+ gpu::Mailbox GetMailbox() const;
Id stable_id() const { return id_; }
- const sk_sp<SkImage>& GetSkImage() const;
- gpu::Mailbox GetMailbox() const;
+ SkImageInfo GetSkImageInfo() const;
AnimationType animation_type() const { return animation_type_; }
CompletionState completion_state() const { return completion_state_; }
bool is_multipart() const { return is_multipart_; }
@@ -262,7 +266,6 @@ class CC_PAINT_EXPORT PaintImage {
// Skia internally buffers commands and flushes them as necessary but there
// are some cases where we need to force a flush.
void FlushPendingSkiaOps();
- bool HasExclusiveTextureAccess() const;
int width() const;
int height() const;
SkColorSpace* color_space() const {
@@ -324,6 +327,12 @@ class CC_PAINT_EXPORT PaintImage {
friend class DrawImageRectOp;
friend class DrawImageOp;
+ // TODO(crbug.com/1031051): Remove these once GetSkImage()
+ // is fully removed.
+ friend class ImagePaintFilter;
+ friend class PaintShader;
+ friend class blink::VideoFrame;
+
bool DecodeFromGenerator(void* memory,
SkImageInfo* info,
sk_sp<SkColorSpace> color_space,
@@ -339,6 +348,10 @@ class CC_PAINT_EXPORT PaintImage {
// Only supported in non-OOPR contexts by friend callers.
sk_sp<SkImage> GetAcceleratedSkImage() const;
+ // GetSkImage() is being deprecated, see crbug.com/1031051.
+ // Prefer using GetSwSkImage() or GetSkImageInfo().
+ const sk_sp<SkImage>& GetSkImage() const;
+
sk_sp<SkImage> sk_image_;
sk_sp<PaintRecord> paint_record_;
gfx::Rect paint_record_rect_;
diff --git a/chromium/cc/paint/paint_image_builder.cc b/chromium/cc/paint/paint_image_builder.cc
index d8b3199f935..80aa99af7b1 100644
--- a/chromium/cc/paint/paint_image_builder.cc
+++ b/chromium/cc/paint/paint_image_builder.cc
@@ -33,6 +33,7 @@ PaintImageBuilder::PaintImageBuilder(PaintImage image, bool clear_contents)
paint_image_.paint_record_rect_ = gfx::Rect();
paint_image_.paint_image_generator_ = nullptr;
paint_image_.cached_sk_image_ = nullptr;
+ paint_image_.texture_backing_ = nullptr;
}
}
PaintImageBuilder::PaintImageBuilder(PaintImageBuilder&& other) = default;
diff --git a/chromium/cc/paint/paint_image_unittest.cc b/chromium/cc/paint/paint_image_unittest.cc
index 6de36fe986b..d328030961b 100644
--- a/chromium/cc/paint/paint_image_unittest.cc
+++ b/chromium/cc/paint/paint_image_unittest.cc
@@ -74,7 +74,8 @@ TEST(PaintImageTest, GetSkImageForFrameNotGeneratorBacked) {
TEST(PaintImageTest, DecodeToYuv420NoAlpha) {
const SkISize full_size = SkISize::Make(10, 10);
- SkYUVAInfo yuva_info(full_size, SkYUVAInfo::PlanarConfig::kY_U_V_420,
+ SkYUVAInfo yuva_info(full_size, SkYUVAInfo::PlaneConfig::kY_U_V,
+ SkYUVAInfo::Subsampling::k420,
kJPEG_Full_SkYUVColorSpace);
SkYUVAPixmapInfo yuva_pixmap_info(yuva_info,
SkYUVAPixmapInfo::DataType::kUnorm8,
diff --git a/chromium/cc/paint/paint_op_buffer.cc b/chromium/cc/paint/paint_op_buffer.cc
index 1fb6e17f432..c9f9ac8bb80 100644
--- a/chromium/cc/paint/paint_op_buffer.cc
+++ b/chromium/cc/paint/paint_op_buffer.cc
@@ -27,15 +27,28 @@
namespace cc {
namespace {
+// In a future CL, convert DrawImage to explicitly take sampling instead of
+// quality
+SkFilterQuality sampling_to_quality(const SkSamplingOptions& sampling) {
+ if (sampling.useCubic) {
+ return kHigh_SkFilterQuality;
+ }
+ if (sampling.mipmap != SkMipmapMode::kNone) {
+ return kMedium_SkFilterQuality;
+ }
+ return sampling.filter == SkFilterMode::kLinear ? kLow_SkFilterQuality
+ : kNone_SkFilterQuality;
+}
+
DrawImage CreateDrawImage(const PaintImage& image,
const PaintFlags* flags,
+ const SkSamplingOptions& sampling,
const SkMatrix& matrix) {
if (!image)
return DrawImage();
return DrawImage(image, flags->useDarkModeForImage(),
SkIRect::MakeWH(image.width(), image.height()),
- flags ? flags->getFilterQuality() : kLow_SkFilterQuality,
- matrix);
+ sampling_to_quality(sampling), matrix);
}
bool IsScaleAdjustmentIdentity(const SkSize& scale_adjustment) {
@@ -312,10 +325,10 @@ std::ostream& operator<<(std::ostream& os, PaintOpType type) {
}
PlaybackParams::PlaybackParams(ImageProvider* image_provider)
- : PlaybackParams(image_provider, SkMatrix::I()) {}
+ : PlaybackParams(image_provider, SkM44()) {}
PlaybackParams::PlaybackParams(ImageProvider* image_provider,
- const SkMatrix& original_ctm,
+ const SkM44& original_ctm,
CustomDataRasterCallback custom_callback,
DidDrawOpCallback did_draw_op_callback)
: image_provider(image_provider),
@@ -339,7 +352,7 @@ PaintOp::SerializeOptions::SerializeOptions(
bool can_use_lcd_text,
bool context_supports_distance_field_text,
int max_texture_size,
- const SkMatrix& original_ctm)
+ const SkM44& original_ctm)
: image_provider(image_provider),
transfer_cache(transfer_cache),
paint_cache(paint_cache),
@@ -422,9 +435,9 @@ size_t ClipRRectOp::Serialize(const PaintOp* base_op,
}
size_t ConcatOp::Serialize(const PaintOp* base_op,
- void* memory,
- size_t size,
- const SerializeOptions& options) {
+ void* memory,
+ size_t size,
+ const SerializeOptions& options) {
auto* op = static_cast<const ConcatOp*>(base_op);
PaintOpWriter helper(memory, size, options);
helper.Write(op->matrix);
@@ -479,7 +492,7 @@ size_t DrawImageOp::Serialize(const PaintOp* base_op,
helper.Write(*serialized_flags);
SkSize scale_adjustment = SkSize::Make(1.f, 1.f);
- helper.Write(CreateDrawImage(op->image, serialized_flags,
+ helper.Write(CreateDrawImage(op->image, serialized_flags, op->sampling,
options.canvas->getTotalMatrix()),
&scale_adjustment);
helper.AlignMemory(alignof(SkScalar));
@@ -488,6 +501,7 @@ size_t DrawImageOp::Serialize(const PaintOp* base_op,
helper.Write(op->left);
helper.Write(op->top);
+ helper.Write(op->sampling);
return helper.size();
}
@@ -503,20 +517,21 @@ size_t DrawImageRectOp::Serialize(const PaintOp* base_op,
helper.Write(*serialized_flags);
// This adjustment mirrors DiscardableImageMap::GatherDiscardableImage logic.
- SkMatrix matrix = options.canvas->getTotalMatrix();
- matrix.postConcat(
- SkMatrix::MakeRectToRect(op->src, op->dst, SkMatrix::kFill_ScaleToFit));
+ SkMatrix matrix =
+ SkMatrix::RectToRect(op->src, op->dst) * options.canvas->getTotalMatrix();
// Note that we don't request subsets here since the GpuImageCache has no
// optimizations for using subsets.
SkSize scale_adjustment = SkSize::Make(1.f, 1.f);
- helper.Write(CreateDrawImage(op->image, serialized_flags, matrix),
- &scale_adjustment);
+ helper.Write(
+ CreateDrawImage(op->image, serialized_flags, op->sampling, matrix),
+ &scale_adjustment);
helper.AlignMemory(alignof(SkScalar));
helper.Write(scale_adjustment.width());
helper.Write(scale_adjustment.height());
helper.Write(op->src);
helper.Write(op->dst);
+ helper.Write(op->sampling);
helper.Write(op->constraint);
return helper.size();
}
@@ -578,6 +593,7 @@ size_t DrawPathOp::Serialize(const PaintOp* base_op,
serialized_flags = &op->flags;
helper.Write(*serialized_flags);
helper.Write(op->path);
+ helper.Write(op->sk_path_fill_type);
return helper.size();
}
@@ -726,19 +742,12 @@ size_t ScaleOp::Serialize(const PaintOp* base_op,
}
size_t SetMatrixOp::Serialize(const PaintOp* base_op,
- void* memory,
- size_t size,
- const SerializeOptions& options) {
+ void* memory,
+ size_t size,
+ const SerializeOptions& options) {
auto* op = static_cast<const SetMatrixOp*>(base_op);
PaintOpWriter helper(memory, size, options);
-
- if (options.original_ctm.isIdentity()) {
- helper.Write(op->matrix);
- } else {
- SkMatrix transformed = op->matrix;
- transformed.postConcat(options.original_ctm);
- helper.Write(transformed);
- }
+ helper.Write(options.original_ctm * op->matrix);
return helper.size();
}
@@ -869,7 +878,6 @@ PaintOp* ConcatOp::Deserialize(const volatile void* input,
}
UpdateTypeAndSkip(op);
- PaintOpReader::FixupMatrixPostSerialization(&op->matrix);
return op;
}
@@ -950,6 +958,7 @@ PaintOp* DrawImageOp::Deserialize(const volatile void* input,
helper.Read(&op->left);
helper.Read(&op->top);
+ helper.Read(&op->sampling);
if (!helper.valid() || !op->IsValid()) {
op->~DrawImageOp();
return nullptr;
@@ -976,6 +985,7 @@ PaintOp* DrawImageRectOp::Deserialize(const volatile void* input,
helper.Read(&op->src);
helper.Read(&op->dst);
+ helper.Read(&op->sampling);
helper.Read(&op->constraint);
if (!helper.valid() || !op->IsValid()) {
op->~DrawImageRectOp();
@@ -1057,6 +1067,8 @@ PaintOp* DrawPathOp::Deserialize(const volatile void* input,
PaintOpReader helper(input, input_size, options);
helper.Read(&op->flags);
helper.Read(&op->path);
+ helper.Read(&op->sk_path_fill_type);
+ op->path.setFillType(static_cast<SkPathFillType>(op->sk_path_fill_type));
if (!helper.valid() || !op->IsValid()) {
op->~DrawPathOp();
return nullptr;
@@ -1314,7 +1326,6 @@ PaintOp* SetMatrixOp::Deserialize(const volatile void* input,
}
UpdateTypeAndSkip(op);
- PaintOpReader::FixupMatrixPostSerialization(&op->matrix);
return op;
}
@@ -1394,8 +1405,8 @@ void ClipRRectOp::Raster(const ClipRRectOp* op,
}
void ConcatOp::Raster(const ConcatOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params) {
+ SkCanvas* canvas,
+ const PlaybackParams& params) {
canvas->concat(op->matrix);
}
@@ -1435,18 +1446,22 @@ void DrawImageOp::RasterWithFlags(const DrawImageOp* op,
canvas->scale(1.f / op->scale_adjustment.width(),
1.f / op->scale_adjustment.height());
}
- auto sk_image = op->image.IsTextureBacked()
- ? op->image.GetAcceleratedSkImage()
- : op->image.GetSwSkImage();
- canvas->drawImage(sk_image.get(), op->left, op->top, &paint);
+ sk_sp<SkImage> sk_image;
+ if (op->image.IsTextureBacked()) {
+ sk_image = op->image.GetAcceleratedSkImage();
+ DCHECK(sk_image || !canvas->recordingContext());
+ }
+ if (!sk_image)
+ sk_image = op->image.GetSwSkImage();
+
+ canvas->drawImage(sk_image.get(), op->left, op->top, op->sampling, &paint);
return;
}
// Dark mode is applied only for OOP raster during serialization.
DrawImage draw_image(
op->image, false, SkIRect::MakeWH(op->image.width(), op->image.height()),
- flags ? flags->getFilterQuality() : kNone_SkFilterQuality,
- canvas->getTotalMatrix());
+ sampling_to_quality(op->sampling), canvas->getTotalMatrix());
auto scoped_result = params.image_provider->GetRasterContent(draw_image);
if (!scoped_result)
return;
@@ -1466,8 +1481,11 @@ void DrawImageOp::RasterWithFlags(const DrawImageOp* op,
canvas->scale(1.f / scale_adjustment.width(),
1.f / scale_adjustment.height());
}
- paint.setFilterQuality(decoded_image.filter_quality());
- canvas->drawImage(decoded_image.image().get(), op->left, op->top, &paint);
+ canvas->drawImage(
+ decoded_image.image().get(), op->left, op->top,
+ SkSamplingOptions(decoded_image.filter_quality(),
+ SkSamplingOptions::kMedium_asMipmapLinear),
+ &paint);
}
void DrawImageRectOp::RasterWithFlags(const DrawImageRectOp* op,
@@ -1482,13 +1500,6 @@ void DrawImageRectOp::RasterWithFlags(const DrawImageRectOp* op,
// we should draw nothing.
if (!params.image_provider)
return;
- // TODO(crbug.com/1157152): We shouldn't need this check, QuickRejectDraw
- // should have done the job.
- const SkRect& clip_rect = SkRect::Make(canvas->getDeviceClipBounds());
- const SkMatrix& ctm = canvas->getTotalMatrix();
- gfx::Rect local_op_rect = PaintOp::ComputePaintRect(op, clip_rect, ctm);
- if (local_op_rect.IsEmpty())
- return;
ImageProvider::ScopedResult result =
params.image_provider->GetRasterContent(DrawImage(op->image));
@@ -1499,8 +1510,7 @@ void DrawImageRectOp::RasterWithFlags(const DrawImageRectOp* op,
DCHECK(IsScaleAdjustmentIdentity(op->scale_adjustment));
SkAutoCanvasRestore save_restore(canvas, true);
- canvas->concat(
- SkMatrix::MakeRectToRect(op->src, op->dst, SkMatrix::kFill_ScaleToFit));
+ canvas->concat(SkMatrix::RectToRect(op->src, op->dst));
canvas->clipRect(op->src);
canvas->saveLayer(&op->src, &paint);
// Compositor thread animations can cause PaintWorklet jobs to be dispatched
@@ -1516,26 +1526,28 @@ void DrawImageRectOp::RasterWithFlags(const DrawImageRectOp* op,
if (!params.image_provider) {
SkRect adjusted_src = AdjustSrcRectForScale(op->src, op->scale_adjustment);
flags->DrawToSk(canvas, [op, adjusted_src](SkCanvas* c, const SkPaint& p) {
- auto sk_image = op->image.IsTextureBacked()
- ? op->image.GetAcceleratedSkImage()
- : op->image.GetSwSkImage();
- c->drawImageRect(sk_image.get(), adjusted_src, op->dst, &p,
+ sk_sp<SkImage> sk_image;
+ if (op->image.IsTextureBacked()) {
+ sk_image = op->image.GetAcceleratedSkImage();
+ DCHECK(sk_image || !c->recordingContext());
+ }
+ if (!sk_image)
+ sk_image = op->image.GetSwSkImage();
+ c->drawImageRect(sk_image.get(), adjusted_src, op->dst, op->sampling, &p,
op->constraint);
});
return;
}
- SkMatrix matrix;
- matrix.setRectToRect(op->src, op->dst, SkMatrix::kFill_ScaleToFit);
- matrix.postConcat(canvas->getTotalMatrix());
+ SkMatrix matrix =
+ canvas->getTotalMatrix() * SkMatrix::RectToRect(op->src, op->dst);
SkIRect int_src_rect;
op->src.roundOut(&int_src_rect);
// Dark mode is applied only for OOP raster during serialization.
- DrawImage draw_image(
- op->image, false, int_src_rect,
- flags ? flags->getFilterQuality() : kNone_SkFilterQuality, matrix);
+ DrawImage draw_image(op->image, false, int_src_rect,
+ sampling_to_quality(op->sampling), matrix);
auto scoped_result = params.image_provider->GetRasterContent(draw_image);
if (!scoped_result)
return;
@@ -1553,10 +1565,11 @@ void DrawImageRectOp::RasterWithFlags(const DrawImageRectOp* op,
adjusted_src = AdjustSrcRectForScale(adjusted_src, scale_adjustment);
flags->DrawToSk(canvas, [op, &decoded_image, adjusted_src](SkCanvas* c,
const SkPaint& p) {
- SkPaint paint_with_filter_quality(p);
- paint_with_filter_quality.setFilterQuality(decoded_image.filter_quality());
- c->drawImageRect(decoded_image.image().get(), adjusted_src, op->dst,
- &paint_with_filter_quality, op->constraint);
+ c->drawImageRect(
+ decoded_image.image().get(), adjusted_src, op->dst,
+ SkSamplingOptions(decoded_image.filter_quality(),
+ SkSamplingOptions::kMedium_asMipmapLinear),
+ &p, op->constraint);
});
}
@@ -1698,9 +1711,9 @@ void ScaleOp::Raster(const ScaleOp* op,
}
void SetMatrixOp::Raster(const SetMatrixOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params) {
- canvas->setMatrix(SkMatrix::Concat(params.original_ctm, op->matrix));
+ SkCanvas* canvas,
+ const PlaybackParams& params) {
+ canvas->setMatrix(params.original_ctm * op->matrix);
}
void SetNodeIdOp::Raster(const SetNodeIdOp* op,
@@ -1780,6 +1793,18 @@ bool PaintOp::AreSkMatricesEqual(const SkMatrix& left, const SkMatrix& right) {
}
// static
+bool PaintOp::AreSkM44sEqual(const SkM44& left, const SkM44& right) {
+ for (int r = 0; r < 4; ++r) {
+ for (int c = 0; c < 4; ++c) {
+ if (!AreEqualEvenIfNaN(left.rc(r, c), right.rc(r, c)))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// static
bool PaintOp::AreSkFlattenablesEqual(SkFlattenable* left,
SkFlattenable* right) {
if (!right || !left)
@@ -1863,7 +1888,7 @@ bool ConcatOp::AreEqual(const PaintOp* base_left, const PaintOp* base_right) {
auto* right = static_cast<const ConcatOp*>(base_right);
DCHECK(left->IsValid());
DCHECK(right->IsValid());
- return AreSkMatricesEqual(left->matrix, right->matrix);
+ return AreSkM44sEqual(left->matrix, right->matrix);
}
bool CustomDataOp::AreEqual(const PaintOp* base_left,
@@ -2131,7 +2156,7 @@ bool SetMatrixOp::AreEqual(const PaintOp* base_left,
auto* right = static_cast<const SetMatrixOp*>(base_right);
DCHECK(left->IsValid());
DCHECK(right->IsValid());
- if (!AreSkMatricesEqual(left->matrix, right->matrix))
+ if (!AreSkM44sEqual(left->matrix, right->matrix))
return false;
return true;
}
@@ -2370,6 +2395,15 @@ bool PaintOp::QuickRejectDraw(const PaintOp* op, const SkCanvas* canvas) {
SkPaint paint = static_cast<const PaintOpWithFlags*>(op)->flags.ToSkPaint();
if (!paint.canComputeFastBounds())
return false;
+ // canvas->quickReject tried to be very fast, and sometimes give a false
+ // but conservative result. That's why we need the additional check for
+ // |local_op_rect| because it could quickReject could return false even if
+ // |local_op_rect| is empty.
+ const SkRect& clip_rect = SkRect::Make(canvas->getDeviceClipBounds());
+ const SkMatrix& ctm = canvas->getTotalMatrix();
+ gfx::Rect local_op_rect = PaintOp::ComputePaintRect(op, clip_rect, ctm);
+ if (local_op_rect.IsEmpty())
+ return true;
paint.computeFastBounds(rect, &rect);
}
@@ -2486,14 +2520,23 @@ AnnotateOp::~AnnotateOp() = default;
DrawImageOp::DrawImageOp() : PaintOpWithFlags(kType) {}
+DrawImageOp::DrawImageOp(const PaintImage& image, SkScalar left, SkScalar top)
+ : PaintOpWithFlags(kType, PaintFlags()),
+ image(image),
+ left(left),
+ top(top),
+ sampling(SkSamplingOptions()) {}
+
DrawImageOp::DrawImageOp(const PaintImage& image,
SkScalar left,
SkScalar top,
+ const SkSamplingOptions& sampling,
const PaintFlags* flags)
: PaintOpWithFlags(kType, flags ? *flags : PaintFlags()),
image(image),
left(left),
- top(top) {}
+ top(top),
+ sampling(sampling) {}
bool DrawImageOp::HasDiscardableImages() const {
return image && !image.IsTextureBacked();
@@ -2506,12 +2549,25 @@ DrawImageRectOp::DrawImageRectOp() : PaintOpWithFlags(kType) {}
DrawImageRectOp::DrawImageRectOp(const PaintImage& image,
const SkRect& src,
const SkRect& dst,
+ SkCanvas::SrcRectConstraint constraint)
+ : PaintOpWithFlags(kType, PaintFlags()),
+ image(image),
+ src(src),
+ dst(dst),
+ sampling(SkSamplingOptions()),
+ constraint(constraint) {}
+
+DrawImageRectOp::DrawImageRectOp(const PaintImage& image,
+ const SkRect& src,
+ const SkRect& dst,
+ const SkSamplingOptions& sampling,
const PaintFlags* flags,
SkCanvas::SrcRectConstraint constraint)
: PaintOpWithFlags(kType, flags ? *flags : PaintFlags()),
image(image),
src(src),
dst(dst),
+ sampling(sampling),
constraint(constraint) {}
bool DrawImageRectOp::HasDiscardableImages() const {
@@ -2785,7 +2841,7 @@ void PaintOpBuffer::Playback(SkCanvas* canvas,
// translate(x, y), then draw a paint record with a SetMatrix(identity),
// the translation should be preserved instead of clobbering the top level
// transform. This could probably be done more efficiently.
- PlaybackParams new_params(params.image_provider, canvas->getTotalMatrix(),
+ PlaybackParams new_params(params.image_provider, canvas->getLocalToDevice(),
params.custom_callback,
params.did_draw_op_callback);
new_params.save_layer_alpha_should_preserve_lcd_text =
diff --git a/chromium/cc/paint/paint_op_buffer.h b/chromium/cc/paint/paint_op_buffer.h
index 57b1d8e4440..ee0c79b8477 100644
--- a/chromium/cc/paint/paint_op_buffer.h
+++ b/chromium/cc/paint/paint_op_buffer.h
@@ -8,8 +8,11 @@
#include <stdint.h>
#include <limits>
+#include <memory>
#include <string>
#include <type_traits>
+#include <utility>
+#include <vector>
#include "base/callback.h"
#include "base/check_op.h"
@@ -44,14 +47,6 @@ class ClientPaintCache;
class ImageProvider;
class ServicePaintCache;
-class CC_PAINT_EXPORT ThreadsafeMatrix : public SkMatrix {
- public:
- explicit ThreadsafeMatrix(const SkMatrix& matrix) : SkMatrix(matrix) {
- (void)getType();
- }
- ThreadsafeMatrix() { (void)getType(); }
-};
-
class CC_PAINT_EXPORT ThreadsafePath : public SkPath {
public:
explicit ThreadsafePath(const SkPath& path) : SkPath(path) {
@@ -121,7 +116,7 @@ struct CC_PAINT_EXPORT PlaybackParams {
explicit PlaybackParams(ImageProvider* image_provider);
PlaybackParams(
ImageProvider* image_provider,
- const SkMatrix& original_ctm,
+ const SkM44& original_ctm,
CustomDataRasterCallback custom_callback = CustomDataRasterCallback(),
DidDrawOpCallback did_draw_op_callback = DidDrawOpCallback());
~PlaybackParams();
@@ -130,7 +125,7 @@ struct CC_PAINT_EXPORT PlaybackParams {
PlaybackParams& operator=(const PlaybackParams& other);
ImageProvider* image_provider;
- SkMatrix original_ctm;
+ SkM44 original_ctm;
CustomDataRasterCallback custom_callback;
DidDrawOpCallback did_draw_op_callback;
base::Optional<bool> save_layer_alpha_should_preserve_lcd_text;
@@ -166,7 +161,7 @@ class CC_PAINT_EXPORT PaintOp {
bool can_use_lcd_text,
bool context_supports_distance_field_text,
int max_texture_size,
- const SkMatrix& original_ctm);
+ const SkM44& original_ctm);
SerializeOptions(const SerializeOptions&);
SerializeOptions& operator=(const SerializeOptions&);
~SerializeOptions();
@@ -181,7 +176,7 @@ class CC_PAINT_EXPORT PaintOp {
bool can_use_lcd_text = false;
bool context_supports_distance_field_text = true;
int max_texture_size = 0;
- SkMatrix original_ctm = SkMatrix::I();
+ SkM44 original_ctm = SkM44(); // Identity
// Optional.
// The flags to use when serializing this op. This can be used to override
@@ -332,6 +327,7 @@ class CC_PAINT_EXPORT PaintOp {
static bool AreSkRectsEqual(const SkRect& left, const SkRect& right);
static bool AreSkRRectsEqual(const SkRRect& left, const SkRRect& right);
static bool AreSkMatricesEqual(const SkMatrix& left, const SkMatrix& right);
+ static bool AreSkM44sEqual(const SkM44& left, const SkM44& right);
static bool AreSkFlattenablesEqual(SkFlattenable* left, SkFlattenable* right);
static constexpr bool kIsDrawOp = false;
@@ -455,7 +451,7 @@ class CC_PAINT_EXPORT ClipRRectOp final : public PaintOp {
class CC_PAINT_EXPORT ConcatOp final : public PaintOp {
public:
static constexpr PaintOpType kType = PaintOpType::Concat;
- explicit ConcatOp(const SkMatrix& matrix) : PaintOp(kType), matrix(matrix) {}
+ explicit ConcatOp(const SkM44& matrix) : PaintOp(kType), matrix(matrix) {}
static void Raster(const ConcatOp* op,
SkCanvas* canvas,
const PlaybackParams& params);
@@ -463,7 +459,7 @@ class CC_PAINT_EXPORT ConcatOp final : public PaintOp {
static bool AreEqual(const PaintOp* left, const PaintOp* right);
HAS_SERIALIZATION_FUNCTIONS();
- ThreadsafeMatrix matrix;
+ SkM44 matrix;
private:
ConcatOp() : PaintOp(kType) {}
@@ -536,9 +532,11 @@ class CC_PAINT_EXPORT DrawImageOp final : public PaintOpWithFlags {
public:
static constexpr PaintOpType kType = PaintOpType::DrawImage;
static constexpr bool kIsDrawOp = true;
+ DrawImageOp(const PaintImage& image, SkScalar left, SkScalar top);
DrawImageOp(const PaintImage& image,
SkScalar left,
SkScalar top,
+ const SkSamplingOptions&,
const PaintFlags* flags);
~DrawImageOp();
static void RasterWithFlags(const DrawImageOp* op,
@@ -557,6 +555,7 @@ class CC_PAINT_EXPORT DrawImageOp final : public PaintOpWithFlags {
PaintImage image;
SkScalar left;
SkScalar top;
+ SkSamplingOptions sampling;
private:
DrawImageOp();
@@ -573,6 +572,11 @@ class CC_PAINT_EXPORT DrawImageRectOp final : public PaintOpWithFlags {
DrawImageRectOp(const PaintImage& image,
const SkRect& src,
const SkRect& dst,
+ SkCanvas::SrcRectConstraint constraint);
+ DrawImageRectOp(const PaintImage& image,
+ const SkRect& src,
+ const SkRect& dst,
+ const SkSamplingOptions&,
const PaintFlags* flags,
SkCanvas::SrcRectConstraint constraint);
~DrawImageRectOp();
@@ -592,6 +596,7 @@ class CC_PAINT_EXPORT DrawImageRectOp final : public PaintOpWithFlags {
PaintImage image;
SkRect src;
SkRect dst;
+ SkSamplingOptions sampling;
SkCanvas::SrcRectConstraint constraint;
private:
@@ -680,7 +685,9 @@ class CC_PAINT_EXPORT DrawPathOp final : public PaintOpWithFlags {
static constexpr PaintOpType kType = PaintOpType::DrawPath;
static constexpr bool kIsDrawOp = true;
DrawPathOp(const SkPath& path, const PaintFlags& flags)
- : PaintOpWithFlags(kType, flags), path(path) {}
+ : PaintOpWithFlags(kType, flags),
+ path(path),
+ sk_path_fill_type(static_cast<uint8_t>(path.getFillType())) {}
static void RasterWithFlags(const DrawPathOp* op,
const PaintFlags* flags,
SkCanvas* canvas,
@@ -692,6 +699,12 @@ class CC_PAINT_EXPORT DrawPathOp final : public PaintOpWithFlags {
ThreadsafePath path;
+ // Changing the fill type on an SkPath does not change the
+ // generation id. This can lead to caching issues so we explicitly
+ // serialize/deserialize this value and set it on the SkPath before handing it
+ // to Skia.
+ uint8_t sk_path_fill_type;
+
private:
DrawPathOp() : PaintOpWithFlags(kType) {}
};
@@ -935,8 +948,7 @@ class CC_PAINT_EXPORT ScaleOp final : public PaintOp {
class CC_PAINT_EXPORT SetMatrixOp final : public PaintOp {
public:
static constexpr PaintOpType kType = PaintOpType::SetMatrix;
- explicit SetMatrixOp(const SkMatrix& matrix)
- : PaintOp(kType), matrix(matrix) {}
+ explicit SetMatrixOp(const SkM44& matrix) : PaintOp(kType), matrix(matrix) {}
// This is the only op that needs the original ctm of the SkCanvas
// used for raster (since SetMatrix is relative to the recording origin and
// shouldn't clobber the SkCanvas raster origin).
@@ -950,7 +962,7 @@ class CC_PAINT_EXPORT SetMatrixOp final : public PaintOp {
static bool AreEqual(const PaintOp* left, const PaintOp* right);
HAS_SERIALIZATION_FUNCTIONS();
- ThreadsafeMatrix matrix;
+ SkM44 matrix;
private:
SetMatrixOp() : PaintOp(kType) {}
@@ -1290,7 +1302,7 @@ class CC_PAINT_EXPORT PaintOpBuffer : public SkRefCnt {
base::Optional<Iterator> iter_;
};
- class PlaybackFoldingIterator {
+ class CC_PAINT_EXPORT PlaybackFoldingIterator {
public:
PlaybackFoldingIterator(const PaintOpBuffer* buffer,
const std::vector<size_t>* offsets);
diff --git a/chromium/cc/paint/paint_op_buffer_fuzzer.cc b/chromium/cc/paint/paint_op_buffer_fuzzer.cc
index 562f62f093d..152b78b6511 100644
--- a/chromium/cc/paint/paint_op_buffer_fuzzer.cc
+++ b/chromium/cc/paint/paint_op_buffer_fuzzer.cc
@@ -79,7 +79,7 @@ void Raster(scoped_refptr<viz::TestContextProvider> context_provider,
context_provider->GrContext(), SkBudgeted::kYes, image_info);
SkCanvas* canvas = surface->getCanvas();
- cc::PlaybackParams params(nullptr, canvas->getTotalMatrix());
+ cc::PlaybackParams params(nullptr, canvas->getLocalToDevice());
cc::TransferCacheTestHelper transfer_cache_helper;
std::vector<uint8_t> scratch_buffer;
cc::PaintOp::DeserializeOptions deserialize_options(
diff --git a/chromium/cc/paint/paint_op_buffer_serializer.cc b/chromium/cc/paint/paint_op_buffer_serializer.cc
index 709b4321626..824df365dfb 100644
--- a/chromium/cc/paint/paint_op_buffer_serializer.cc
+++ b/chromium/cc/paint/paint_op_buffer_serializer.cc
@@ -35,7 +35,7 @@ class ScopedFlagsOverride {
PlaybackParams MakeParams(const SkCanvas* canvas) {
// We don't use an ImageProvider here since the ops are played onto a no-draw
// canvas for state tracking and don't need decoded images.
- return PlaybackParams(nullptr, canvas->getTotalMatrix());
+ return PlaybackParams(nullptr, canvas->getLocalToDevice());
}
// Use half of the max int as the extent for the SkNoDrawCanvas. The correct
@@ -259,8 +259,7 @@ void PaintOpBufferSerializer::SerializeBuffer(
Save(options, params);
// The following ops are copying the canvas's ops from
// DrawImageRectOp::RasterWithFlags.
- SkMatrix trans = SkMatrix::MakeRectToRect(draw_op->src, draw_op->dst,
- SkMatrix::kFill_ScaleToFit);
+ SkM44 trans = SkM44(SkMatrix::RectToRect(draw_op->src, draw_op->dst));
ConcatOp concat_op(trans);
bool success = SerializeOp(&concat_op, options, params);
if (!success)
@@ -380,7 +379,7 @@ PaintOp::SerializeOptions PaintOpBufferSerializer::MakeSerializeOptions() {
image_provider_, transfer_cache_, paint_cache_, text_blob_canvas_.get(),
strike_server_, color_space_, can_use_lcd_text_,
context_supports_distance_field_text_, max_texture_size_,
- text_blob_canvas_->getTotalMatrix());
+ text_blob_canvas_->getLocalToDevice());
}
SimpleBufferSerializer::SimpleBufferSerializer(
diff --git a/chromium/cc/paint/paint_op_buffer_unittest.cc b/chromium/cc/paint/paint_op_buffer_unittest.cc
index 19233b89d23..39288b97b54 100644
--- a/chromium/cc/paint/paint_op_buffer_unittest.cc
+++ b/chromium/cc/paint/paint_op_buffer_unittest.cc
@@ -5,10 +5,6 @@
#include "cc/paint/paint_op_buffer.h"
#include <algorithm>
-#include <memory>
-#include <utility>
-#include <vector>
-
#include "base/bind.h"
#include "base/memory/scoped_refptr.h"
#include "base/stl_util.h"
@@ -37,7 +33,6 @@
#include "third_party/skia/include/effects/SkColorMatrixFilter.h"
#include "third_party/skia/include/effects/SkDashPathEffect.h"
#include "third_party/skia/include/effects/SkLayerDrawLooper.h"
-#include "third_party/skia/include/effects/SkOffsetImageFilter.h"
#include "third_party/skia/src/core/SkRemoteGlyphCache.h"
using testing::_;
@@ -488,7 +483,7 @@ TEST(PaintOpBufferTest, DiscardableImagesTracking_NoImageOp) {
TEST(PaintOpBufferTest, DiscardableImagesTracking_DrawImage) {
PaintOpBuffer buffer;
PaintImage image = CreateDiscardablePaintImage(gfx::Size(100, 100));
- buffer.push<DrawImageOp>(image, SkIntToScalar(0), SkIntToScalar(0), nullptr);
+ buffer.push<DrawImageOp>(image, SkIntToScalar(0), SkIntToScalar(0));
EXPECT_TRUE(buffer.HasDiscardableImages());
}
@@ -497,7 +492,7 @@ TEST(PaintOpBufferTest, DiscardableImagesTracking_PaintWorkletImage) {
base::MakeRefCounted<TestPaintWorkletInput>(gfx::SizeF(32.0f, 32.0f));
PaintOpBuffer buffer;
PaintImage image = CreatePaintWorkletPaintImage(input);
- buffer.push<DrawImageOp>(image, SkIntToScalar(0), SkIntToScalar(0), nullptr);
+ buffer.push<DrawImageOp>(image, SkIntToScalar(0), SkIntToScalar(0));
EXPECT_TRUE(buffer.HasDiscardableImages());
}
@@ -508,7 +503,7 @@ TEST(PaintOpBufferTest, DiscardableImagesTracking_PaintWorkletImageRect) {
PaintImage image = CreatePaintWorkletPaintImage(input);
SkRect src = SkRect::MakeEmpty();
SkRect dst = SkRect::MakeEmpty();
- buffer.push<DrawImageRectOp>(image, src, dst, nullptr,
+ buffer.push<DrawImageRectOp>(image, src, dst,
SkCanvas::kStrict_SrcRectConstraint);
EXPECT_TRUE(buffer.HasDiscardableImages());
}
@@ -517,7 +512,7 @@ TEST(PaintOpBufferTest, DiscardableImagesTracking_DrawImageRect) {
PaintOpBuffer buffer;
PaintImage image = CreateDiscardablePaintImage(gfx::Size(100, 100));
buffer.push<DrawImageRectOp>(image, SkRect::MakeWH(100, 100),
- SkRect::MakeWH(100, 100), nullptr,
+ SkRect::MakeWH(100, 100),
SkCanvas::kFast_SrcRectConstraint);
EXPECT_TRUE(buffer.HasDiscardableImages());
}
@@ -665,7 +660,7 @@ TEST(PaintOpBufferTest, NonAAPaint) {
PaintFlags non_aa_flags;
non_aa_flags.setAntiAlias(true);
buffer->push<DrawImageOp>(image, SkIntToScalar(0), SkIntToScalar(0),
- &non_aa_flags);
+ SkSamplingOptions(), &non_aa_flags);
EXPECT_FALSE(buffer->HasNonAAPaint());
}
@@ -727,6 +722,31 @@ class PaintOpBufferOffsetsTest : public ::testing::Test {
PaintOpBuffer buffer_;
};
+TEST_F(PaintOpBufferOffsetsTest, EmptyClipRectShouldRejectAnOp) {
+ SkCanvas device(0, 0);
+ SkCanvas* canvas = &device;
+ canvas->translate(-254, 0);
+ SkIRect bounds = canvas->getDeviceClipBounds();
+ EXPECT_TRUE(bounds.isEmpty());
+ SkMatrix ctm = canvas->getTotalMatrix();
+ EXPECT_EQ(ctm[2], -254);
+
+ scoped_refptr<TestPaintWorkletInput> input =
+ base::MakeRefCounted<TestPaintWorkletInput>(gfx::SizeF(32.0f, 32.0f));
+ PaintImage image = CreatePaintWorkletPaintImage(input);
+ SkRect src = SkRect::MakeLTRB(0, 0, 100, 100);
+ SkRect dst = SkRect::MakeLTRB(168, -23, 268, 77);
+ push_op<DrawImageRectOp>(image, src, dst,
+ SkCanvas::kStrict_SrcRectConstraint);
+ std::vector<size_t> offsets = Select({0});
+ for (PaintOpBuffer::PlaybackFoldingIterator iter(&buffer_, &offsets); iter;
+ ++iter) {
+ const PaintOp* op = *iter;
+ EXPECT_EQ(op->GetType(), PaintOpType::DrawImageRect);
+ EXPECT_TRUE(PaintOp::QuickRejectDraw(op, canvas));
+ }
+}
+
TEST_F(PaintOpBufferOffsetsTest, ContiguousIndices) {
testing::StrictMock<MockCanvas> canvas;
@@ -1085,22 +1105,12 @@ std::vector<SkIRect> test_irects = {
std::vector<uint32_t> test_ids = {0, 1, 56, 0xFFFFFFFF, 0xFFFFFFFE, 0x10001};
-std::vector<SkMatrix> test_matrices = {
- SkMatrix::I(),
- SkMatrix::Scale(3.91f, 4.31f),
- SkMatrix::Translate(-5.2f, 8.7f),
- [] {
- SkMatrix matrix;
- SkScalar buffer[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
- matrix.set9(buffer);
- return matrix;
- }(),
- [] {
- SkMatrix matrix;
- SkScalar buffer[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
- matrix.set9(buffer);
- return matrix;
- }(),
+std::vector<SkM44> test_matrices = {
+ SkM44(),
+ SkM44::Scale(3.91f, 4.31f, 1.0f),
+ SkM44::Translate(-5.2f, 8.7f, 0.0f),
+ SkM44(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
+ SkM44(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16),
};
std::vector<SkPath> test_paths = {
@@ -1427,8 +1437,8 @@ void PushClipRRectOps(PaintOpBuffer* buffer) {
}
void PushConcatOps(PaintOpBuffer* buffer) {
- for (size_t i = 0; i < test_matrices.size(); ++i)
- buffer->push<ConcatOp>(test_matrices[i]);
+ for (auto& test_matrix : test_matrices)
+ buffer->push<ConcatOp>(test_matrix);
ValidateOps<ConcatOp>(buffer);
}
@@ -1458,14 +1468,16 @@ void PushDrawImageOps(PaintOpBuffer* buffer) {
size_t len =
std::min({test_images.size(), test_flags.size(), test_floats.size() - 1});
for (size_t i = 0; i < len; ++i) {
- buffer->push<DrawImageOp>(test_images[i], test_floats[i],
- test_floats[i + 1], &test_flags[i]);
+ buffer->push<DrawImageOp>(
+ test_images[i], test_floats[i], test_floats[i + 1],
+ SkSamplingOptions(test_flags[i].getFilterQuality(),
+ SkSamplingOptions::kMedium_asMipmapLinear),
+ &test_flags[i]);
}
// Test optional flags
// TODO(enne): maybe all these optional ops should not be optional.
- buffer->push<DrawImageOp>(test_images[0], test_floats[0], test_floats[1],
- nullptr);
+ buffer->push<DrawImageOp>(test_images[0], test_floats[0], test_floats[1]);
ValidateOps<DrawImageOp>(buffer);
}
@@ -1476,14 +1488,16 @@ void PushDrawImageRectOps(PaintOpBuffer* buffer) {
SkCanvas::SrcRectConstraint constraint =
i % 2 ? SkCanvas::kStrict_SrcRectConstraint
: SkCanvas::kFast_SrcRectConstraint;
- buffer->push<DrawImageRectOp>(test_images[i], test_rects[i],
- test_rects[i + 1], &test_flags[i],
- constraint);
+ buffer->push<DrawImageRectOp>(
+ test_images[i], test_rects[i], test_rects[i + 1],
+ SkSamplingOptions(test_flags[i].getFilterQuality(),
+ SkSamplingOptions::kMedium_asMipmapLinear),
+ &test_flags[i], constraint);
}
// Test optional flags.
buffer->push<DrawImageRectOp>(test_images[0], test_rects[0], test_rects[1],
- nullptr, SkCanvas::kStrict_SrcRectConstraint);
+ SkCanvas::kStrict_SrcRectConstraint);
ValidateOps<DrawImageRectOp>(buffer);
}
@@ -1658,8 +1672,8 @@ void PushScaleOps(PaintOpBuffer* buffer) {
}
void PushSetMatrixOps(PaintOpBuffer* buffer) {
- for (size_t i = 0; i < test_matrices.size(); ++i)
- buffer->push<SetMatrixOp>(test_matrices[i]);
+ for (auto& test_matrix : test_matrices)
+ buffer->push<SetMatrixOp>(test_matrix);
ValidateOps<SetMatrixOp>(buffer);
}
@@ -1987,7 +2001,7 @@ TEST_P(PaintOpSerializationTest, UsesOverridenFlags) {
base::AlignedAlloc(deserialized_size, PaintOpBuffer::PaintOpAlign)));
for (const auto* op : PaintOpBuffer::Iterator(&buffer_)) {
options_provider.mutable_serialize_options().flags_to_serialize =
- &static_cast<const PaintOpWithFlags*>(op)->flags;
+ &(static_cast<const PaintOpWithFlags*>(op))->flags;
size_t bytes_written = op->Serialize(output_.get(), output_size_,
options_provider.serialize_options());
@@ -2283,7 +2297,7 @@ TEST(PaintOpBufferTest, ClipsImagesDuringSerialization) {
buffer.push<DrawImageOp>(
CreateDiscardablePaintImage(test_case.image_rect.size()),
static_cast<SkScalar>(test_case.image_rect.x()),
- static_cast<SkScalar>(test_case.image_rect.y()), nullptr);
+ static_cast<SkScalar>(test_case.image_rect.y()));
std::unique_ptr<char, base::AlignedFreeDeleter> memory(
static_cast<char*>(base::AlignedAlloc(PaintOpBuffer::kInitialBufferSize,
@@ -2478,7 +2492,10 @@ TEST(PaintOpBufferTest, ValidateSkClip) {
buffer.push<ClipRectOp>(test_rects[0], bad_clip, true);
buffer.push<ClipRRectOp>(test_rrects[0], bad_clip, false);
- SkClipOp bad_clip_max = static_cast<SkClipOp>(~static_cast<uint32_t>(0));
+ // SkClipOp is serialized to uint8_t (see WriteEnum). Values outside uint8_t
+ // would crash the serialization, so this is the max value that passes checked
+ // cast but will still fail validation during deserialization.
+ SkClipOp bad_clip_max = static_cast<SkClipOp>(static_cast<uint8_t>(~0));
buffer.push<ClipRectOp>(test_rects[1], bad_clip_max, false);
TestOptionsProvider options_provider;
@@ -2540,15 +2557,15 @@ TEST(PaintOpBufferTest, ValidateSkBlendMode) {
SkBlendMode::kSaturation,
SkBlendMode::kColor,
SkBlendMode::kLuminosity,
- static_cast<SkBlendMode>(static_cast<uint32_t>(SkBlendMode::kLastMode) +
+ static_cast<SkBlendMode>(static_cast<uint8_t>(SkBlendMode::kLastMode) +
1),
- static_cast<SkBlendMode>(static_cast<uint32_t>(~0)),
+ static_cast<SkBlendMode>(static_cast<uint8_t>(~0)),
};
SkBlendMode bad_modes_for_flags[] = {
- static_cast<SkBlendMode>(static_cast<uint32_t>(SkBlendMode::kLastMode) +
+ static_cast<SkBlendMode>(static_cast<uint8_t>(SkBlendMode::kLastMode) +
1),
- static_cast<SkBlendMode>(static_cast<uint32_t>(~0)),
+ static_cast<SkBlendMode>(static_cast<uint8_t>(~0)),
};
for (size_t i = 0; i < base::size(bad_modes_for_draw_color); ++i) {
@@ -2606,9 +2623,9 @@ TEST(PaintOpBufferTest, ValidateRects) {
SkData::MakeWithCString("test1"));
buffer.push<ClipRectOp>(bad_rect, SkClipOp::kDifference, true);
- buffer.push<DrawImageRectOp>(test_images[0], bad_rect, test_rects[1], nullptr,
+ buffer.push<DrawImageRectOp>(test_images[0], bad_rect, test_rects[1],
SkCanvas::kStrict_SrcRectConstraint);
- buffer.push<DrawImageRectOp>(test_images[0], test_rects[0], bad_rect, nullptr,
+ buffer.push<DrawImageRectOp>(test_images[0], test_rects[0], bad_rect,
SkCanvas::kStrict_SrcRectConstraint);
buffer.push<DrawOvalOp>(bad_rect, test_flags[0]);
buffer.push<DrawRectOp>(bad_rect, test_flags[0]);
@@ -2810,7 +2827,7 @@ class MockImageProvider : public ImageProvider {
sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
size_t i = index_++;
return ScopedResult(DecodedDrawImage(image, nullptr, src_rect_offset_[i],
- scale_[i], quality_[i]));
+ scale_[i], quality_[i], true));
}
void SetRecord(sk_sp<PaintRecord> record) { record_ = std::move(record); }
@@ -2834,9 +2851,8 @@ TEST(PaintOpBufferTest, SkipsOpsOutsideClip) {
buffer.push<ClipRectOp>(SkRect::MakeXYWH(0, 0, 100, 100),
SkClipOp::kIntersect, false);
- PaintFlags flags;
PaintImage paint_image = CreateDiscardablePaintImage(gfx::Size(10, 10));
- buffer.push<DrawImageOp>(paint_image, 105.0f, 105.0f, &flags);
+ buffer.push<DrawImageOp>(paint_image, 105.0f, 105.0f);
PaintFlags image_flags;
image_flags.setShader(PaintShader::MakeImage(paint_image, SkTileMode::kRepeat,
SkTileMode::kRepeat, nullptr));
@@ -2859,9 +2875,8 @@ TEST(PaintOpBufferTest, SkipsOpsWithFailedDecodes) {
MockImageProvider image_provider(true);
PaintOpBuffer buffer;
- PaintFlags flags;
PaintImage paint_image = CreateDiscardablePaintImage(gfx::Size(10, 10));
- buffer.push<DrawImageOp>(paint_image, 105.0f, 105.0f, &flags);
+ buffer.push<DrawImageOp>(paint_image, 105.0f, 105.0f);
PaintFlags image_flags;
image_flags.setShader(PaintShader::MakeImage(paint_image, SkTileMode::kRepeat,
SkTileMode::kRepeat, nullptr));
@@ -2879,10 +2894,10 @@ MATCHER(NonLazyImage, "") {
}
MATCHER_P2(MatchesRect, rect, scale, "") {
- EXPECT_EQ(arg->x(), rect.x() * scale.width());
- EXPECT_EQ(arg->y(), rect.y() * scale.height());
- EXPECT_EQ(arg->width(), rect.width() * scale.width());
- EXPECT_EQ(arg->height(), rect.height() * scale.height());
+ EXPECT_EQ(arg.x(), rect.x() * scale.width());
+ EXPECT_EQ(arg.y(), rect.y() * scale.height());
+ EXPECT_EQ(arg.width(), rect.width() * scale.width());
+ EXPECT_EQ(arg.height(), rect.height() * scale.height());
return true;
}
@@ -2928,7 +2943,7 @@ TEST(PaintOpBufferTest, RasterPaintWorkletImageRectBasicCase) {
PaintImage image = CreatePaintWorkletPaintImage(input);
SkRect src = SkRect::MakeXYWH(0, 0, 100, 100);
SkRect dst = SkRect::MakeXYWH(0, 0, 100, 100);
- blink_buffer.push<DrawImageRectOp>(image, src, dst, nullptr,
+ blink_buffer.push<DrawImageRectOp>(image, src, dst,
SkCanvas::kStrict_SrcRectConstraint);
testing::StrictMock<MockCanvas> canvas;
@@ -2953,10 +2968,10 @@ TEST(PaintOpBufferTest, RasterPaintWorkletImageRectTranslated) {
PaintFlags noop_flags;
SkRect savelayer_rect = SkRect::MakeXYWH(0, 0, 10, 10);
paint_worklet_buffer->push<SaveLayerOp>(&savelayer_rect, &noop_flags);
- PaintFlags draw_flags;
- draw_flags.setFilterQuality(kLow_SkFilterQuality);
PaintImage paint_image = CreateDiscardablePaintImage(gfx::Size(10, 10));
- paint_worklet_buffer->push<DrawImageOp>(paint_image, 0.0f, 0.0f, &draw_flags);
+ paint_worklet_buffer->push<DrawImageOp>(
+ paint_image, 0.0f, 0.0f, SkSamplingOptions(SkFilterMode::kLinear),
+ nullptr);
std::vector<SkSize> src_rect_offset = {SkSize::MakeEmpty()};
std::vector<SkSize> scale_adjustment = {SkSize::Make(0.2f, 0.2f)};
@@ -2970,21 +2985,22 @@ TEST(PaintOpBufferTest, RasterPaintWorkletImageRectTranslated) {
PaintImage image = CreatePaintWorkletPaintImage(input);
SkRect src = SkRect::MakeXYWH(0, 0, 100, 100);
SkRect dst = SkRect::MakeXYWH(5, 7, 100, 100);
- blink_buffer.push<DrawImageRectOp>(image, src, dst, nullptr,
+ blink_buffer.push<DrawImageRectOp>(image, src, dst,
SkCanvas::kStrict_SrcRectConstraint);
testing::StrictMock<MockCanvas> canvas;
testing::Sequence s;
+ SkSamplingOptions sampling({1.0f / 3, 1.0f / 3});
+
EXPECT_CALL(canvas, willSave()).InSequence(s);
EXPECT_CALL(canvas, OnSaveLayer()).InSequence(s);
EXPECT_CALL(canvas, OnSaveLayer()).InSequence(s);
- EXPECT_CALL(canvas, didConcat(SkMatrix::Translate(5.0f, 7.0f)));
+ EXPECT_CALL(canvas, didConcat44(SkM44::Translate(5.0f, 7.0f)));
EXPECT_CALL(canvas, willSave()).InSequence(s);
EXPECT_CALL(canvas, didScale(1.0f / scale_adjustment[0].width(),
1.0f / scale_adjustment[0].height()));
- EXPECT_CALL(canvas, onDrawImage(NonLazyImage(), 0.0f, 0.0f,
- MatchesQuality(quality[0])));
+ EXPECT_CALL(canvas, onDrawImage2(NonLazyImage(), 0.0f, 0.0f, sampling, _));
EXPECT_CALL(canvas, willRestore()).InSequence(s);
EXPECT_CALL(canvas, willRestore()).InSequence(s);
EXPECT_CALL(canvas, willRestore()).InSequence(s);
@@ -2998,10 +3014,10 @@ TEST(PaintOpBufferTest, RasterPaintWorkletImageRectScaled) {
PaintFlags noop_flags;
SkRect savelayer_rect = SkRect::MakeXYWH(0, 0, 10, 10);
paint_worklet_buffer->push<SaveLayerOp>(&savelayer_rect, &noop_flags);
- PaintFlags draw_flags;
- draw_flags.setFilterQuality(kLow_SkFilterQuality);
PaintImage paint_image = CreateDiscardablePaintImage(gfx::Size(10, 10));
- paint_worklet_buffer->push<DrawImageOp>(paint_image, 0.0f, 0.0f, &draw_flags);
+ paint_worklet_buffer->push<DrawImageOp>(
+ paint_image, 0.0f, 0.0f, SkSamplingOptions(SkFilterMode::kLinear),
+ nullptr);
std::vector<SkSize> src_rect_offset = {SkSize::MakeEmpty()};
std::vector<SkSize> scale_adjustment = {SkSize::Make(0.2f, 0.2f)};
@@ -3015,21 +3031,22 @@ TEST(PaintOpBufferTest, RasterPaintWorkletImageRectScaled) {
PaintImage image = CreatePaintWorkletPaintImage(input);
SkRect src = SkRect::MakeXYWH(0, 0, 100, 100);
SkRect dst = SkRect::MakeXYWH(0, 0, 200, 150);
- blink_buffer.push<DrawImageRectOp>(image, src, dst, nullptr,
+ blink_buffer.push<DrawImageRectOp>(image, src, dst,
SkCanvas::kStrict_SrcRectConstraint);
testing::StrictMock<MockCanvas> canvas;
testing::Sequence s;
+ SkSamplingOptions sampling({1.0f / 3, 1.0f / 3});
+
EXPECT_CALL(canvas, willSave()).InSequence(s);
EXPECT_CALL(canvas, OnSaveLayer()).InSequence(s);
EXPECT_CALL(canvas, OnSaveLayer()).InSequence(s);
- EXPECT_CALL(canvas, didConcat(SkMatrix::Scale(2.f, 1.5f)));
+ EXPECT_CALL(canvas, didConcat44(SkM44::Scale(2.f, 1.5f)));
EXPECT_CALL(canvas, willSave()).InSequence(s);
EXPECT_CALL(canvas, didScale(1.0f / scale_adjustment[0].width(),
1.0f / scale_adjustment[0].height()));
- EXPECT_CALL(canvas, onDrawImage(NonLazyImage(), 0.0f, 0.0f,
- MatchesQuality(quality[0])));
+ EXPECT_CALL(canvas, onDrawImage2(NonLazyImage(), 0.0f, 0.0f, sampling, _));
EXPECT_CALL(canvas, willRestore()).InSequence(s);
EXPECT_CALL(canvas, willRestore()).InSequence(s);
EXPECT_CALL(canvas, willRestore()).InSequence(s);
@@ -3043,13 +3060,13 @@ TEST(PaintOpBufferTest, RasterPaintWorkletImageRectClipped) {
PaintFlags noop_flags;
SkRect savelayer_rect = SkRect::MakeXYWH(0, 0, 60, 60);
paint_worklet_buffer->push<SaveLayerOp>(&savelayer_rect, &noop_flags);
- PaintFlags draw_flags;
- draw_flags.setFilterQuality(kLow_SkFilterQuality);
+ SkSamplingOptions linear(SkFilterMode::kLinear);
PaintImage paint_image = CreateDiscardablePaintImage(gfx::Size(10, 10));
// One rect inside the src-rect, one outside.
- paint_worklet_buffer->push<DrawImageOp>(paint_image, 0.0f, 0.0f, &draw_flags);
- paint_worklet_buffer->push<DrawImageOp>(paint_image, 50.0f, 50.0f,
- &draw_flags);
+ paint_worklet_buffer->push<DrawImageOp>(paint_image, 0.0f, 0.0f, linear,
+ nullptr);
+ paint_worklet_buffer->push<DrawImageOp>(paint_image, 50.0f, 50.0f, linear,
+ nullptr);
std::vector<SkSize> src_rect_offset = {SkSize::MakeEmpty()};
std::vector<SkSize> scale_adjustment = {SkSize::Make(0.2f, 0.2f)};
@@ -3063,20 +3080,21 @@ TEST(PaintOpBufferTest, RasterPaintWorkletImageRectClipped) {
PaintImage image = CreatePaintWorkletPaintImage(input);
SkRect src = SkRect::MakeXYWH(0, 0, 20, 20);
SkRect dst = SkRect::MakeXYWH(0, 0, 20, 20);
- blink_buffer.push<DrawImageRectOp>(image, src, dst, nullptr,
+ blink_buffer.push<DrawImageRectOp>(image, src, dst,
SkCanvas::kStrict_SrcRectConstraint);
testing::StrictMock<MockCanvas> canvas;
testing::Sequence s;
+ SkSamplingOptions sampling({1.0f / 3, 1.0f / 3});
+
EXPECT_CALL(canvas, willSave()).InSequence(s);
EXPECT_CALL(canvas, OnSaveLayer()).InSequence(s);
EXPECT_CALL(canvas, OnSaveLayer()).InSequence(s);
EXPECT_CALL(canvas, willSave()).InSequence(s);
EXPECT_CALL(canvas, didScale(1.0f / scale_adjustment[0].width(),
1.0f / scale_adjustment[0].height()));
- EXPECT_CALL(canvas, onDrawImage(NonLazyImage(), 0.0f, 0.0f,
- MatchesQuality(quality[0])));
+ EXPECT_CALL(canvas, onDrawImage2(NonLazyImage(), 0.0f, 0.0f, sampling, _));
EXPECT_CALL(canvas, willRestore()).InSequence(s);
EXPECT_CALL(canvas, willRestore()).InSequence(s);
EXPECT_CALL(canvas, willRestore()).InSequence(s);
@@ -3098,12 +3116,12 @@ TEST(PaintOpBufferTest, ReplacesImagesFromProvider) {
PaintOpBuffer buffer;
SkRect rect = SkRect::MakeWH(10, 10);
- PaintFlags flags;
- flags.setFilterQuality(kLow_SkFilterQuality);
+ SkSamplingOptions sampling(SkFilterMode::kLinear);
PaintImage paint_image = CreateDiscardablePaintImage(gfx::Size(10, 10));
- buffer.push<DrawImageOp>(paint_image, 0.0f, 0.0f, &flags);
- buffer.push<DrawImageRectOp>(paint_image, rect, rect, &flags,
+ buffer.push<DrawImageOp>(paint_image, 0.0f, 0.0f, sampling, nullptr);
+ buffer.push<DrawImageRectOp>(paint_image, rect, rect, sampling, nullptr,
SkCanvas::kFast_SrcRectConstraint);
+ PaintFlags flags;
flags.setShader(PaintShader::MakeImage(paint_image, SkTileMode::kRepeat,
SkTileMode::kRepeat, nullptr));
buffer.push<DrawOvalOp>(SkRect::MakeWH(10, 10), flags);
@@ -3111,22 +3129,24 @@ TEST(PaintOpBufferTest, ReplacesImagesFromProvider) {
testing::StrictMock<MockCanvas> canvas;
testing::Sequence s;
+ SkSamplingOptions sampling0({1.0f / 3, 1.0f / 3});
+ SkSamplingOptions sampling1(SkFilterMode::kLinear, SkMipmapMode::kLinear);
+
// Save/scale/image/restore from DrawImageop.
EXPECT_CALL(canvas, willSave()).InSequence(s);
EXPECT_CALL(canvas, didScale(1.0f / scale_adjustment[0].width(),
1.0f / scale_adjustment[0].height()));
- EXPECT_CALL(canvas, onDrawImage(NonLazyImage(), 0.0f, 0.0f,
- MatchesQuality(quality[0])));
+ EXPECT_CALL(canvas, onDrawImage2(NonLazyImage(), 0.0f, 0.0f, sampling0, _));
EXPECT_CALL(canvas, willRestore()).InSequence(s);
// DrawImageRectop.
SkRect src_rect =
rect.makeOffset(src_rect_offset[1].width(), src_rect_offset[1].height());
EXPECT_CALL(canvas,
- onDrawImageRect(
- NonLazyImage(), MatchesRect(src_rect, scale_adjustment[1]),
- SkRect::MakeWH(10, 10), MatchesQuality(quality[1]),
- SkCanvas::kFast_SrcRectConstraint));
+ onDrawImageRect2(NonLazyImage(),
+ MatchesRect(src_rect, scale_adjustment[1]),
+ SkRect::MakeWH(10, 10), sampling1, _,
+ SkCanvas::kFast_SrcRectConstraint));
// DrawOvalop.
EXPECT_CALL(canvas, onDrawOval(SkRect::MakeWH(10, 10),
@@ -3146,14 +3166,14 @@ TEST(PaintOpBufferTest, DrawImageRectOpWithLooperNoImageProvider) {
PaintFlags paint_flags;
paint_flags.setLooper(sk_draw_looper_builder.detach());
buffer.push<DrawImageRectOp>(image, SkRect::MakeWH(100, 100),
- SkRect::MakeWH(100, 100), &paint_flags,
- SkCanvas::kFast_SrcRectConstraint);
+ SkRect::MakeWH(100, 100), SkSamplingOptions(),
+ &paint_flags, SkCanvas::kFast_SrcRectConstraint);
testing::StrictMock<MockCanvas> canvas;
EXPECT_CALL(canvas, willSave);
EXPECT_CALL(canvas, didTranslate);
EXPECT_CALL(canvas, willRestore);
- EXPECT_CALL(canvas, onDrawImageRect).Times(2);
+ EXPECT_CALL(canvas, onDrawImageRect2).Times(2);
buffer.Playback(&canvas, PlaybackParams(nullptr));
}
@@ -3169,14 +3189,14 @@ TEST(PaintOpBufferTest, DrawImageRectOpWithLooperWithImageProvider) {
PaintFlags paint_flags;
paint_flags.setLooper(sk_draw_looper_builder.detach());
buffer.push<DrawImageRectOp>(image, SkRect::MakeWH(100, 100),
- SkRect::MakeWH(100, 100), &paint_flags,
- SkCanvas::kFast_SrcRectConstraint);
+ SkRect::MakeWH(100, 100), SkSamplingOptions(),
+ &paint_flags, SkCanvas::kFast_SrcRectConstraint);
testing::StrictMock<MockCanvas> canvas;
EXPECT_CALL(canvas, willSave);
EXPECT_CALL(canvas, didTranslate);
EXPECT_CALL(canvas, willRestore);
- EXPECT_CALL(canvas, onDrawImageRect).Times(2);
+ EXPECT_CALL(canvas, onDrawImageRect2).Times(2);
std::vector<SkSize> src_rect_offset = {SkSize::MakeEmpty()};
std::vector<SkSize> scale_adjustment = {SkSize::Make(1.0f, 1.0f)};
@@ -3191,11 +3211,11 @@ TEST(PaintOpBufferTest, ReplacesImagesFromProviderOOP) {
SkRect rect = SkRect::MakeWH(10, 10);
PaintFlags flags;
- flags.setFilterQuality(kLow_SkFilterQuality);
+ SkSamplingOptions sampling(SkFilterMode::kLinear);
PaintImage paint_image = CreateDiscardablePaintImage(gfx::Size(10, 10));
buffer.push<ScaleOp>(expected_scale.width(), expected_scale.height());
- buffer.push<DrawImageOp>(paint_image, 0.0f, 0.0f, &flags);
- buffer.push<DrawImageRectOp>(paint_image, rect, rect, &flags,
+ buffer.push<DrawImageOp>(paint_image, 0.0f, 0.0f, sampling, nullptr);
+ buffer.push<DrawImageRectOp>(paint_image, rect, rect, sampling, nullptr,
SkCanvas::kFast_SrcRectConstraint);
flags.setShader(PaintShader::MakeImage(paint_image, SkTileMode::kRepeat,
SkTileMode::kRepeat, nullptr));
@@ -3231,14 +3251,14 @@ TEST(PaintOpBufferTest, ReplacesImagesFromProviderOOP) {
EXPECT_CALL(canvas, willSave()).InSequence(s);
EXPECT_CALL(canvas, didScale(1.0f / expected_scale.width(),
1.0f / expected_scale.height()));
- EXPECT_CALL(canvas, onDrawImage(NonLazyImage(), 0.0f, 0.0f, _));
+ EXPECT_CALL(canvas, onDrawImage2(NonLazyImage(), 0.0f, 0.0f, _, _));
EXPECT_CALL(canvas, willRestore()).InSequence(s);
op->Raster(&canvas, params);
} else if (op->GetType() == PaintOpType::DrawImageRect) {
- EXPECT_CALL(canvas, onDrawImageRect(NonLazyImage(),
- MatchesRect(rect, expected_scale),
- SkRect::MakeWH(10, 10), _,
- SkCanvas::kFast_SrcRectConstraint));
+ EXPECT_CALL(canvas, onDrawImageRect2(NonLazyImage(),
+ MatchesRect(rect, expected_scale),
+ SkRect::MakeWH(10, 10), _, _,
+ SkCanvas::kFast_SrcRectConstraint));
op->Raster(&canvas, params);
} else if (op->GetType() == PaintOpType::DrawOval) {
EXPECT_CALL(canvas, onDrawOval(SkRect::MakeWH(10, 10),
@@ -3259,19 +3279,18 @@ TEST_P(PaintFilterSerializationTest, Basic) {
std::vector<sk_sp<PaintFilter>> filters = {
sk_sp<PaintFilter>{new ColorFilterPaintFilter(
SkColorFilters::LinearToSRGBGamma(), nullptr)},
- sk_sp<PaintFilter>{new BlurPaintFilter(
- 0.5f, 0.3f, SkBlurImageFilter::kRepeat_TileMode, nullptr)},
+ 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,
- SkDropShadowImageFilter::kDrawShadowOnly_ShadowMode, nullptr)},
+ DropShadowPaintFilter::ShadowMode::kDrawShadowOnly, nullptr)},
sk_sp<PaintFilter>{new MagnifierPaintFilter(SkRect::MakeXYWH(5, 6, 7, 8),
10.5f, nullptr)},
sk_sp<PaintFilter>{new AlphaThresholdPaintFilter(
SkRegion(SkIRect::MakeXYWH(0, 0, 100, 200)), 10.f, 20.f, nullptr)},
sk_sp<PaintFilter>{new MatrixConvolutionPaintFilter(
SkISize::Make(3, 3), scalars, 30.f, 123.f, SkIPoint::Make(0, 0),
- SkMatrixConvolutionImageFilter::kClampToBlack_TileMode, true,
- nullptr)},
+ SkTileMode::kDecal, true, nullptr)},
sk_sp<PaintFilter>{new MorphologyPaintFilter(
MorphologyPaintFilter::MorphType::kErode, 15.5f, 30.2f, nullptr)},
sk_sp<PaintFilter>{new OffsetPaintFilter(-1.f, -2.f, nullptr)},
@@ -3300,12 +3319,10 @@ TEST_P(PaintFilterSerializationTest, Basic) {
filters.emplace_back(new ComposePaintFilter(filters[0], filters[1]));
filters.emplace_back(
new XfermodePaintFilter(SkBlendMode::kDst, filters[2], filters[3]));
- filters.emplace_back(new ArithmeticPaintFilter(
- 1.1f, 2.2f, 3.3f, 4.4f, false, filters[4], filters[5], nullptr));
+ filters.emplace_back(new ArithmeticPaintFilter(1.1f, 2.2f, 3.3f, 4.4f, false,
+ filters[4], filters[5]));
filters.emplace_back(new DisplacementMapEffectPaintFilter(
- SkDisplacementMapEffect::kR_ChannelSelectorType,
- SkDisplacementMapEffect::kG_ChannelSelectorType, 10, filters[6],
- filters[7]));
+ SkColorChannel::kR, SkColorChannel::kG, 10, filters[6], filters[7]));
filters.emplace_back(new MergePaintFilter(filters.data(), filters.size()));
filters.emplace_back(new RecordPaintFilter(
sk_sp<PaintRecord>{new PaintRecord}, SkRect::MakeXYWH(10, 15, 20, 25)));
@@ -3521,7 +3538,7 @@ TEST(PaintOpBufferTest, CustomData) {
buffer.push<CustomDataOp>(9999u);
testing::StrictMock<MockCanvas> canvas;
EXPECT_CALL(canvas, onCustomCallback(&canvas, 9999)).Times(1);
- buffer.Playback(&canvas, PlaybackParams(nullptr, SkMatrix::I(),
+ buffer.Playback(&canvas, PlaybackParams(nullptr, SkM44(),
base::BindRepeating(
&MockCanvas::onCustomCallback,
base::Unretained(&canvas))));
@@ -3561,8 +3578,7 @@ TEST(PaintOpBufferTest, DrawImageRectSerializeScaledImages) {
SkRect src = SkRect::MakeXYWH(3, 4, 20, 6);
SkRect dst = SkRect::MakeXYWH(20, 38, 5, 30);
buffer->push<DrawImageRectOp>(CreateDiscardablePaintImage(gfx::Size(32, 16)),
- src, dst, nullptr,
- SkCanvas::kStrict_SrcRectConstraint);
+ src, dst, SkCanvas::kStrict_SrcRectConstraint);
std::unique_ptr<char, base::AlignedFreeDeleter> memory(
static_cast<char*>(base::AlignedAlloc(PaintOpBuffer::kInitialBufferSize,
@@ -3587,7 +3603,7 @@ TEST(PaintOpBufferTest, DrawImageRectSerializeScaledImages) {
TEST(PaintOpBufferTest, RecordShadersSerializeScaledImages) {
auto record_buffer = sk_make_sp<PaintOpBuffer>();
record_buffer->push<DrawImageOp>(
- CreateDiscardablePaintImage(gfx::Size(10, 10)), 0.f, 0.f, nullptr);
+ CreateDiscardablePaintImage(gfx::Size(10, 10)), 0.f, 0.f);
auto shader = PaintShader::MakePaintRecord(
record_buffer, SkRect::MakeWH(10.f, 10.f), SkTileMode::kRepeat,
@@ -3622,7 +3638,7 @@ TEST(PaintOpBufferTest, RecordShadersSerializeScaledImages) {
TEST(PaintOpBufferTest, RecordShadersCached) {
auto record_buffer = sk_make_sp<PaintOpBuffer>();
record_buffer->push<DrawImageOp>(
- CreateDiscardablePaintImage(gfx::Size(10, 10)), 0.f, 0.f, nullptr);
+ CreateDiscardablePaintImage(gfx::Size(10, 10)), 0.f, 0.f);
auto shader = PaintShader::MakePaintRecord(
record_buffer, SkRect::MakeWH(10.f, 10.f), SkTileMode::kRepeat,
SkTileMode::kRepeat, nullptr);
@@ -3740,7 +3756,7 @@ TEST(PaintOpBufferTest, RecordShadersCachedSize) {
auto record_buffer = sk_make_sp<PaintOpBuffer>();
size_t estimated_image_size = 30 * 30 * 4;
auto image = CreateBitmapImage(gfx::Size(30, 30));
- record_buffer->push<DrawImageOp>(image, 0.f, 0.f, nullptr);
+ record_buffer->push<DrawImageOp>(image, 0.f, 0.f);
auto shader = PaintShader::MakePaintRecord(
record_buffer, SkRect::MakeWH(10.f, 10.f), SkTileMode::kRepeat,
SkTileMode::kRepeat, nullptr);
@@ -3804,7 +3820,7 @@ TEST(PaintOpBufferTest, TotalOpCount) {
TEST(PaintOpBufferTest, NullImages) {
PaintOpBuffer buffer;
- buffer.push<DrawImageOp>(PaintImage(), 0.f, 0.f, nullptr);
+ buffer.push<DrawImageOp>(PaintImage(), 0.f, 0.f);
std::unique_ptr<char, base::AlignedFreeDeleter> memory(
static_cast<char*>(base::AlignedAlloc(PaintOpBuffer::kInitialBufferSize,
@@ -3935,4 +3951,22 @@ TEST(PaintOpBufferTest, NeedsAdditionalInvalidationForLCDText) {
}
}
+// A regression test for crbug.com/1195276. Ensure that PlaybackParams works
+// with SetMatrix operations.
+TEST(PaintOpBufferTest, SetMatrixOpWithNonIdentityPlaybackParams) {
+ for (const auto& original_ctm : test_matrices) {
+ for (const auto& matrix : test_matrices) {
+ SkCanvas device(0, 0);
+ SkCanvas* canvas = &device;
+
+ PlaybackParams params(nullptr, original_ctm);
+ SetMatrixOp op(matrix);
+ SetMatrixOp::Raster(&op, canvas, params);
+
+ EXPECT_TRUE(AnnotateOp::AreSkM44sEqual(canvas->getLocalToDevice(),
+ SkM44(original_ctm, matrix)));
+ }
+ }
+}
+
} // namespace cc
diff --git a/chromium/cc/paint/paint_op_helper_unittest.cc b/chromium/cc/paint/paint_op_helper_unittest.cc
index 3d5db9a8710..3710ef041fe 100644
--- a/chromium/cc/paint/paint_op_helper_unittest.cc
+++ b/chromium/cc/paint/paint_op_helper_unittest.cc
@@ -43,11 +43,12 @@ TEST(PaintOpHelper, ClipRRectToString) {
}
TEST(PaintOpHelper, ConcatToString) {
- ConcatOp op(SkMatrix::MakeAll(1, 2, 3, 4, 5, 6, 7, 8, 9));
+ ConcatOp op(SkM44(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16));
std::string str = PaintOpHelper::ToString(&op);
EXPECT_EQ(str,
- "ConcatOp(matrix=[ 1.0000 2.0000 3.0000][ 4.0000 5.0000 "
- "6.0000][ 7.0000 8.0000 9.0000])");
+ "ConcatOp(matrix=[ 1.0000 2.0000 3.0000 4.0000][ 5.0000 "
+ "6.0000 7.0000 8.0000][ 9.0000 10.0000 11.0000 12.0000][ "
+ "13.0000 14.0000 15.0000 16.0000]])");
}
TEST(PaintOpHelper, DrawColorToString) {
@@ -76,7 +77,7 @@ TEST(PaintOpHelper, DrawDRRectToString) {
}
TEST(PaintOpHelper, DrawImageToString) {
- DrawImageOp op(PaintImage(), 10.5f, 20.3f, nullptr);
+ DrawImageOp op(PaintImage(), 10.5f, 20.3f);
std::string str = PaintOpHelper::ToString(&op);
EXPECT_EQ(
str,
@@ -92,7 +93,7 @@ TEST(PaintOpHelper, DrawImageToString) {
TEST(PaintOpHelper, DrawImageRectToString) {
DrawImageRectOp op(PaintImage(), SkRect::MakeXYWH(1, 2, 3, 4),
- SkRect::MakeXYWH(5, 6, 7, 8), nullptr,
+ SkRect::MakeXYWH(5, 6, 7, 8),
SkCanvas::kStrict_SrcRectConstraint);
std::string str = PaintOpHelper::ToString(&op);
EXPECT_EQ(
@@ -278,11 +279,12 @@ TEST(PaintOpHelper, ScaleToString) {
}
TEST(PaintOpHelper, SetMatrixToString) {
- SetMatrixOp op(SkMatrix::MakeAll(-1, 2, -3, 4, -5, 6, -7, 8, -9));
+ SetMatrixOp op(SkM44(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16));
std::string str = PaintOpHelper::ToString(&op);
EXPECT_EQ(str,
- "SetMatrixOp(matrix=[ -1.0000 2.0000 -3.0000][ 4.0000 -5.0000 "
- " 6.0000][ -7.0000 8.0000 -9.0000])");
+ "SetMatrixOp(matrix=[ 1.0000 2.0000 3.0000 4.0000][ 5.0000 "
+ " 6.0000 7.0000 8.0000][ 9.0000 10.0000 11.0000 12.0000][ "
+ "13.0000 14.0000 15.0000 16.0000]])");
}
TEST(PaintOpHelper, TranslateToString) {
diff --git a/chromium/cc/paint/paint_op_perftest.cc b/chromium/cc/paint/paint_op_perftest.cc
index 4dd80d1c7ac..8ef166e44f1 100644
--- a/chromium/cc/paint/paint_op_perftest.cc
+++ b/chromium/cc/paint/paint_op_perftest.cc
@@ -15,7 +15,6 @@
#include "third_party/skia/include/effects/SkColorMatrixFilter.h"
#include "third_party/skia/include/effects/SkDashPathEffect.h"
#include "third_party/skia/include/effects/SkLayerDrawLooper.h"
-#include "third_party/skia/include/effects/SkOffsetImageFilter.h"
namespace cc {
namespace {
@@ -112,7 +111,7 @@ class PaintOpPerfTest : public testing::Test {
TEST_F(PaintOpPerfTest, SimpleOps) {
PaintOpBuffer buffer;
for (size_t i = 0; i < 100; ++i)
- buffer.push<ConcatOp>(SkMatrix::I());
+ buffer.push<ConcatOp>(SkM44());
RunTest("simple", buffer);
}
diff --git a/chromium/cc/paint/paint_op_reader.cc b/chromium/cc/paint/paint_op_reader.cc
index 59c594dc250..eb795ba528e 100644
--- a/chromium/cc/paint/paint_op_reader.cc
+++ b/chromium/cc/paint/paint_op_reader.cc
@@ -41,18 +41,6 @@ bool IsValidPaintShaderType(PaintShader::Type type) {
static_cast<uint8_t>(PaintShader::Type::kShaderCount);
}
-// SkTileMode has no defined backing type, so read/write int32_t's.
-// If read_mode is a valid tile mode, this returns true and updates mode to the
-// equivalent enum value. Otherwise false is returned and mode is not modified.
-bool ValidateAndGetSkShaderTileMode(int32_t read_mode, SkTileMode* mode) {
- if (read_mode < 0 || read_mode >= kSkTileModeCount) {
- return false;
- }
-
- *mode = static_cast<SkTileMode>(read_mode);
- return true;
-}
-
bool IsValidPaintShaderScalingBehavior(PaintShader::ScalingBehavior behavior) {
return behavior == PaintShader::ScalingBehavior::kRasterAtScale ||
behavior == PaintShader::ScalingBehavior::kFixedScale;
@@ -266,11 +254,7 @@ void PaintOpReader::Read(PaintFlags* flags) {
Read(&flags->width_);
Read(&flags->miter_limit_);
- ReadSimple(&flags->blend_mode_);
- if (flags->blend_mode_ > static_cast<uint32_t>(SkBlendMode::kLastMode)) {
- SetInvalid();
- return;
- }
+ Read(&flags->blend_mode_);
ReadSimple(&flags->bitfields_uint_);
@@ -523,16 +507,8 @@ void PaintOpReader::Read(sk_sp<PaintShader>* shader) {
ReadSimple(&ref.flags_);
ReadSimple(&ref.end_radius_);
ReadSimple(&ref.start_radius_);
-
- // See ValidateAndGetSkShaderTileMode
- int32_t tx = 0;
- int32_t ty = 0;
- Read(&tx);
- Read(&ty);
- if (!ValidateAndGetSkShaderTileMode(tx, &ref.tx_) ||
- !ValidateAndGetSkShaderTileMode(ty, &ref.ty_)) {
- SetInvalid();
- }
+ Read(&ref.tx_);
+ Read(&ref.ty_);
ReadSimple(&ref.fallback_color_);
ReadSimple(&ref.scaling_behavior_);
if (!IsValidPaintShaderScalingBehavior(ref.scaling_behavior_))
@@ -646,16 +622,25 @@ void PaintOpReader::Read(SkMatrix* matrix) {
FixupMatrixPostSerialization(matrix);
}
-void PaintOpReader::Read(SkColorType* color_type) {
- uint32_t raw_color_type = kUnknown_SkColorType;
- ReadSimple(&raw_color_type);
+void PaintOpReader::Read(SkM44* matrix) {
+ ReadSimple(matrix);
+}
- if (raw_color_type > kLastEnum_SkColorType) {
- SetInvalid();
- return;
+void PaintOpReader::Read(SkSamplingOptions* sampling) {
+ bool useCubic;
+ Read(&useCubic);
+ if (useCubic) {
+ SkCubicResampler cubic;
+ Read(&cubic.B);
+ Read(&cubic.C);
+ *sampling = SkSamplingOptions(cubic);
+ } else {
+ SkFilterMode filter;
+ SkMipmapMode mipmap;
+ Read(&filter);
+ Read(&mipmap);
+ *sampling = SkSamplingOptions(filter, mipmap);
}
-
- *color_type = static_cast<SkColorType>(raw_color_type);
}
void PaintOpReader::Read(SkYUVColorSpace* yuv_color_space) {
@@ -670,6 +655,33 @@ void PaintOpReader::Read(SkYUVColorSpace* yuv_color_space) {
*yuv_color_space = static_cast<SkYUVColorSpace>(raw_yuv_color_space);
}
+void PaintOpReader::Read(SkYUVAInfo::PlaneConfig* plane_config) {
+ uint32_t raw_plane_config =
+ static_cast<uint32_t>(SkYUVAInfo::PlaneConfig::kUnknown);
+ ReadSimple(&raw_plane_config);
+
+ if (raw_plane_config >
+ static_cast<uint32_t>(SkYUVAInfo::PlaneConfig::kLast)) {
+ SetInvalid();
+ return;
+ }
+
+ *plane_config = static_cast<SkYUVAInfo::PlaneConfig>(raw_plane_config);
+}
+
+void PaintOpReader::Read(SkYUVAInfo::Subsampling* subsampling) {
+ uint32_t raw_subsampling =
+ static_cast<uint32_t>(SkYUVAInfo::Subsampling::kUnknown);
+ ReadSimple(&raw_subsampling);
+
+ if (raw_subsampling > static_cast<uint32_t>(SkYUVAInfo::Subsampling::kLast)) {
+ SetInvalid();
+ return;
+ }
+
+ *subsampling = static_cast<SkYUVAInfo::Subsampling>(raw_subsampling);
+}
+
void PaintOpReader::Read(gpu::Mailbox* mailbox) {
ReadData(sizeof(gpu::Mailbox::Name), (*mailbox).name);
}
@@ -742,14 +754,11 @@ const volatile void* PaintOpReader::ExtractReadableMemory(size_t bytes) {
}
void PaintOpReader::Read(sk_sp<PaintFilter>* filter) {
- uint32_t type_int = 0;
- ReadSimple(&type_int);
- if (type_int > static_cast<uint32_t>(PaintFilter::Type::kMaxFilterType))
- SetInvalid();
+ PaintFilter::Type type;
+ ReadEnum(&type);
if (!valid_)
return;
- auto type = static_cast<PaintFilter::Type>(type_int);
if (type == PaintFilter::Type::kNullFilter) {
*filter = nullptr;
return;
@@ -759,11 +768,9 @@ void PaintOpReader::Read(sk_sp<PaintFilter>* filter) {
base::Optional<PaintFilter::CropRect> crop_rect;
ReadSimple(&has_crop_rect);
if (has_crop_rect) {
- uint32_t flags = 0;
SkRect rect = SkRect::MakeEmpty();
- ReadSimple(&flags);
ReadSimple(&rect);
- crop_rect.emplace(rect, flags);
+ crop_rect.emplace(rect);
}
AlignMemory(4);
@@ -862,12 +869,12 @@ void PaintOpReader::ReadBlurPaintFilter(
const base::Optional<PaintFilter::CropRect>& crop_rect) {
SkScalar sigma_x = 0.f;
SkScalar sigma_y = 0.f;
- BlurPaintFilter::TileMode tile_mode = SkBlurImageFilter::kClamp_TileMode;
+ SkTileMode tile_mode;
sk_sp<PaintFilter> input;
Read(&sigma_x);
Read(&sigma_y);
- ReadSimple(&tile_mode);
+ Read(&tile_mode);
Read(&input);
if (!valid_)
return;
@@ -884,8 +891,7 @@ void PaintOpReader::ReadDropShadowPaintFilter(
SkScalar sigma_x = 0.f;
SkScalar sigma_y = 0.f;
SkColor color = SK_ColorBLACK;
- DropShadowPaintFilter::ShadowMode shadow_mode =
- SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode;
+ DropShadowPaintFilter::ShadowMode shadow_mode;
sk_sp<PaintFilter> input;
Read(&dx);
@@ -893,11 +899,9 @@ void PaintOpReader::ReadDropShadowPaintFilter(
Read(&sigma_x);
Read(&sigma_y);
Read(&color);
- ReadSimple(&shadow_mode);
+ ReadEnum(&shadow_mode);
Read(&input);
- if (shadow_mode > SkDropShadowImageFilter::kLast_ShadowMode)
- SetInvalid();
if (!valid_)
return;
filter->reset(new DropShadowPaintFilter(dx, dy, sigma_x, sigma_y, color,
@@ -956,19 +960,15 @@ void PaintOpReader::ReadAlphaThresholdPaintFilter(
void PaintOpReader::ReadXfermodePaintFilter(
sk_sp<PaintFilter>* filter,
const base::Optional<PaintFilter::CropRect>& crop_rect) {
- uint32_t blend_mode_int = 0;
+ SkBlendMode blend_mode;
sk_sp<PaintFilter> background;
sk_sp<PaintFilter> foreground;
- Read(&blend_mode_int);
+ Read(&blend_mode);
Read(&background);
Read(&foreground);
- SkBlendMode blend_mode = SkBlendMode::kClear;
- if (blend_mode_int > static_cast<uint32_t>(SkBlendMode::kLastMode))
- SetInvalid();
if (!valid_)
return;
- blend_mode = static_cast<SkBlendMode>(blend_mode_int);
filter->reset(new XfermodePaintFilter(blend_mode, std::move(background),
std::move(foreground),
@@ -1006,7 +1006,7 @@ void PaintOpReader::ReadMatrixConvolutionPaintFilter(
SkScalar gain = 0.f;
SkScalar bias = 0.f;
SkIPoint kernel_offset = SkIPoint::Make(0, 0);
- uint32_t tile_mode_int = 0;
+ SkTileMode tile_mode;
bool convolve_alpha = false;
sk_sp<PaintFilter> input;
@@ -1025,15 +1025,11 @@ void PaintOpReader::ReadMatrixConvolutionPaintFilter(
Read(&gain);
Read(&bias);
ReadSimple(&kernel_offset);
- Read(&tile_mode_int);
+ Read(&tile_mode);
Read(&convolve_alpha);
Read(&input);
- if (tile_mode_int > SkMatrixConvolutionImageFilter::kMax_TileMode)
- SetInvalid();
if (!valid_)
return;
- MatrixConvolutionPaintFilter::TileMode tile_mode =
- static_cast<MatrixConvolutionPaintFilter::TileMode>(tile_mode_int);
filter->reset(new MatrixConvolutionPaintFilter(
kernel_size, kernel.data(), gain, bias, kernel_offset, tile_mode,
convolve_alpha, std::move(input), base::OptionalOrNullptr(crop_rect)));
@@ -1042,33 +1038,20 @@ void PaintOpReader::ReadMatrixConvolutionPaintFilter(
void PaintOpReader::ReadDisplacementMapEffectPaintFilter(
sk_sp<PaintFilter>* filter,
const base::Optional<PaintFilter::CropRect>& crop_rect) {
- // Unknown, R, G, B, A: max type is 4.
- static const int kMaxChannelSelectorType = 4;
-
- uint32_t channel_x_int = 0;
- uint32_t channel_y_int = 0;
+ SkColorChannel channel_x;
+ SkColorChannel channel_y;
SkScalar scale = 0.f;
sk_sp<PaintFilter> displacement;
sk_sp<PaintFilter> color;
- Read(&channel_x_int);
- Read(&channel_y_int);
+ ReadEnum<SkColorChannel, SkColorChannel::kA>(&channel_x);
+ ReadEnum<SkColorChannel, SkColorChannel::kA>(&channel_y);
Read(&scale);
Read(&displacement);
Read(&color);
- if (channel_x_int > kMaxChannelSelectorType ||
- channel_y_int > kMaxChannelSelectorType) {
- SetInvalid();
- }
if (!valid_)
return;
- DisplacementMapEffectPaintFilter::ChannelSelectorType channel_x =
- static_cast<DisplacementMapEffectPaintFilter::ChannelSelectorType>(
- channel_x_int);
- DisplacementMapEffectPaintFilter::ChannelSelectorType channel_y =
- static_cast<DisplacementMapEffectPaintFilter::ChannelSelectorType>(
- channel_y_int);
filter->reset(new DisplacementMapEffectPaintFilter(
channel_x, channel_y, scale, std::move(displacement), std::move(color),
base::OptionalOrNullptr(crop_rect)));
@@ -1136,22 +1119,16 @@ void PaintOpReader::ReadMergePaintFilter(
void PaintOpReader::ReadMorphologyPaintFilter(
sk_sp<PaintFilter>* filter,
const base::Optional<PaintFilter::CropRect>& crop_rect) {
- uint32_t morph_type_int = 0;
+ MorphologyPaintFilter::MorphType morph_type;
float radius_x = 0;
float radius_y = 0;
sk_sp<PaintFilter> input;
- Read(&morph_type_int);
+ ReadEnum(&morph_type);
Read(&radius_x);
Read(&radius_y);
Read(&input);
- if (morph_type_int >
- static_cast<uint32_t>(MorphologyPaintFilter::MorphType::kMaxMorphType)) {
- SetInvalid();
- }
if (!valid_)
return;
- MorphologyPaintFilter::MorphType morph_type =
- static_cast<MorphologyPaintFilter::MorphType>(morph_type_int);
filter->reset(new MorphologyPaintFilter(morph_type, radius_x, radius_y,
std::move(input),
base::OptionalOrNullptr(crop_rect)));
@@ -1191,28 +1168,21 @@ void PaintOpReader::ReadTilePaintFilter(
void PaintOpReader::ReadTurbulencePaintFilter(
sk_sp<PaintFilter>* filter,
const base::Optional<PaintFilter::CropRect>& crop_rect) {
- uint32_t turbulence_type_int = 0;
+ TurbulencePaintFilter::TurbulenceType turbulence_type;
SkScalar base_frequency_x = 0.f;
SkScalar base_frequency_y = 0.f;
int num_octaves = 0;
SkScalar seed = 0.f;
SkISize tile_size = SkISize::MakeEmpty();
- Read(&turbulence_type_int);
+ ReadEnum(&turbulence_type);
Read(&base_frequency_x);
Read(&base_frequency_y);
Read(&num_octaves);
Read(&seed);
ReadSimple(&tile_size);
- if (turbulence_type_int >
- static_cast<uint32_t>(
- TurbulencePaintFilter::TurbulenceType::kMaxTurbulenceType)) {
- SetInvalid();
- }
if (!valid_)
return;
- TurbulencePaintFilter::TurbulenceType turbulence_type =
- static_cast<TurbulencePaintFilter::TurbulenceType>(turbulence_type_int);
filter->reset(new TurbulencePaintFilter(
turbulence_type, base_frequency_x, base_frequency_y, num_octaves, seed,
&tile_size, base::OptionalOrNullptr(crop_rect)));
@@ -1221,7 +1191,6 @@ void PaintOpReader::ReadTurbulencePaintFilter(
void PaintOpReader::ReadPaintFlagsPaintFilter(
sk_sp<PaintFilter>* filter,
const base::Optional<PaintFilter::CropRect>& crop_rect) {
- AlignMemory(4);
PaintFlags flags;
Read(&flags);
if (!valid_)
@@ -1238,10 +1207,8 @@ void PaintOpReader::ReadMatrixPaintFilter(
sk_sp<PaintFilter> input;
Read(&matrix);
- ReadSimple(&filter_quality);
+ Read(&filter_quality);
Read(&input);
- if (filter_quality > kLast_SkFilterQuality)
- SetInvalid();
if (!valid_)
return;
filter->reset(
@@ -1251,7 +1218,7 @@ void PaintOpReader::ReadMatrixPaintFilter(
void PaintOpReader::ReadLightingDistantPaintFilter(
sk_sp<PaintFilter>* filter,
const base::Optional<PaintFilter::CropRect>& crop_rect) {
- uint32_t lighting_type_int = 0;
+ PaintFilter::LightingType lighting_type;
SkPoint3 direction = SkPoint3::Make(0.f, 0.f, 0.f);
SkColor light_color = SK_ColorBLACK;
SkScalar surface_scale = 0.f;
@@ -1259,21 +1226,15 @@ void PaintOpReader::ReadLightingDistantPaintFilter(
SkScalar shininess = 0.f;
sk_sp<PaintFilter> input;
- Read(&lighting_type_int);
+ ReadEnum(&lighting_type);
ReadSimple(&direction);
Read(&light_color);
Read(&surface_scale);
Read(&kconstant);
Read(&shininess);
Read(&input);
- if (lighting_type_int >
- static_cast<uint32_t>(PaintFilter::LightingType::kMaxLightingType)) {
- SetInvalid();
- }
if (!valid_)
return;
- PaintFilter::LightingType lighting_type =
- static_cast<PaintFilter::LightingType>(lighting_type_int);
filter->reset(new LightingDistantPaintFilter(
lighting_type, direction, light_color, surface_scale, kconstant,
shininess, std::move(input), base::OptionalOrNullptr(crop_rect)));
@@ -1282,7 +1243,7 @@ void PaintOpReader::ReadLightingDistantPaintFilter(
void PaintOpReader::ReadLightingPointPaintFilter(
sk_sp<PaintFilter>* filter,
const base::Optional<PaintFilter::CropRect>& crop_rect) {
- uint32_t lighting_type_int = 0;
+ PaintFilter::LightingType lighting_type;
SkPoint3 location = SkPoint3::Make(0.f, 0.f, 0.f);
SkColor light_color = SK_ColorBLACK;
SkScalar surface_scale = 0.f;
@@ -1290,21 +1251,15 @@ void PaintOpReader::ReadLightingPointPaintFilter(
SkScalar shininess = 0.f;
sk_sp<PaintFilter> input;
- Read(&lighting_type_int);
+ ReadEnum(&lighting_type);
ReadSimple(&location);
Read(&light_color);
Read(&surface_scale);
Read(&kconstant);
Read(&shininess);
Read(&input);
- if (lighting_type_int >
- static_cast<uint32_t>(PaintFilter::LightingType::kMaxLightingType)) {
- SetInvalid();
- }
if (!valid_)
return;
- PaintFilter::LightingType lighting_type =
- static_cast<PaintFilter::LightingType>(lighting_type_int);
filter->reset(new LightingPointPaintFilter(
lighting_type, location, light_color, surface_scale, kconstant, shininess,
std::move(input), base::OptionalOrNullptr(crop_rect)));
@@ -1313,7 +1268,7 @@ void PaintOpReader::ReadLightingPointPaintFilter(
void PaintOpReader::ReadLightingSpotPaintFilter(
sk_sp<PaintFilter>* filter,
const base::Optional<PaintFilter::CropRect>& crop_rect) {
- uint32_t lighting_type_int = 0;
+ PaintFilter::LightingType lighting_type;
SkPoint3 location = SkPoint3::Make(0.f, 0.f, 0.f);
SkPoint3 target = SkPoint3::Make(0.f, 0.f, 0.f);
SkScalar specular_exponent = 0.f;
@@ -1324,7 +1279,7 @@ void PaintOpReader::ReadLightingSpotPaintFilter(
SkScalar shininess = 0.f;
sk_sp<PaintFilter> input;
- Read(&lighting_type_int);
+ ReadEnum(&lighting_type);
ReadSimple(&location);
ReadSimple(&target);
Read(&specular_exponent);
@@ -1335,14 +1290,8 @@ void PaintOpReader::ReadLightingSpotPaintFilter(
Read(&shininess);
Read(&input);
- if (lighting_type_int >
- static_cast<uint32_t>(PaintFilter::LightingType::kMaxLightingType)) {
- SetInvalid();
- }
if (!valid_)
return;
- PaintFilter::LightingType lighting_type =
- static_cast<PaintFilter::LightingType>(lighting_type_int);
filter->reset(new LightingSpotPaintFilter(
lighting_type, location, target, specular_exponent, cutoff_angle,
light_color, surface_scale, kconstant, shininess, std::move(input),
diff --git a/chromium/cc/paint/paint_op_reader.h b/chromium/cc/paint/paint_op_reader.h
index c9ab0842ccc..fc8cda79bf0 100644
--- a/chromium/cc/paint/paint_op_reader.h
+++ b/chromium/cc/paint/paint_op_reader.h
@@ -71,49 +71,47 @@ class CC_PAINT_EXPORT PaintOpReader {
void Read(sk_sp<PaintFilter>* filter);
void Read(sk_sp<PaintShader>* shader);
void Read(SkMatrix* matrix);
- void Read(SkColorType* color_type);
+ void Read(SkM44* matrix);
void Read(SkImageInfo* info);
+ void Read(SkSamplingOptions* sampling);
void Read(sk_sp<SkColorSpace>* color_space);
void Read(SkYUVColorSpace* yuv_color_space);
+ void Read(SkYUVAInfo::PlaneConfig* plane_config);
+ void Read(SkYUVAInfo::Subsampling* subsampling);
void Read(gpu::Mailbox* mailbox);
#if !defined(OS_ANDROID)
void Read(scoped_refptr<SkottieWrapper>* skottie);
#endif
- void Read(SkClipOp* op) {
- uint8_t value = 0u;
- Read(&value);
- *op = static_cast<SkClipOp>(value);
- }
+ void Read(SkClipOp* op) { ReadEnum<SkClipOp, SkClipOp::kMax_EnumValue>(op); }
void Read(PaintCanvas::AnnotationType* type) {
- uint8_t value = 0u;
- Read(&value);
- *type = static_cast<PaintCanvas::AnnotationType>(value);
+ ReadEnum<PaintCanvas::AnnotationType,
+ PaintCanvas::AnnotationType::LINK_TO_DESTINATION>(type);
}
void Read(SkCanvas::SrcRectConstraint* constraint) {
- uint8_t value = 0u;
- Read(&value);
- *constraint = static_cast<SkCanvas::SrcRectConstraint>(value);
+ ReadEnum<SkCanvas::SrcRectConstraint, SkCanvas::kFast_SrcRectConstraint>(
+ constraint);
+ }
+ void Read(SkColorType* color_type) {
+ ReadEnum<SkColorType, kLastEnum_SkColorType>(color_type);
}
void Read(SkFilterQuality* quality) {
- uint8_t value = 0u;
- Read(&value);
- if (value > static_cast<uint8_t>(kLast_SkFilterQuality)) {
- SetInvalid();
- return;
- }
- *quality = static_cast<SkFilterQuality>(value);
+ ReadEnum<SkFilterQuality, kLast_SkFilterQuality>(quality);
}
void Read(SkBlendMode* blend_mode) {
- uint8_t value = 0u;
- Read(&value);
- if (value > static_cast<uint8_t>(SkBlendMode::kLastMode)) {
- SetInvalid();
- return;
- }
- *blend_mode = static_cast<SkBlendMode>(value);
+ ReadEnum<SkBlendMode, SkBlendMode::kLastMode>(blend_mode);
+ }
+ void Read(SkTileMode* tile_mode) {
+ ReadEnum<SkTileMode, SkTileMode::kLastTileMode>(tile_mode);
}
+ void Read(SkFilterMode* filter_mode) {
+ ReadEnum<SkFilterMode, SkFilterMode::kLast>(filter_mode);
+ }
+ void Read(SkMipmapMode* mipmap_mode) {
+ ReadEnum<SkMipmapMode, SkMipmapMode::kLast>(mipmap_mode);
+ }
+
void Read(bool* data) {
uint8_t value = 0u;
Read(&value);
@@ -135,6 +133,19 @@ class CC_PAINT_EXPORT PaintOpReader {
template <typename T>
void ReadFlattenable(sk_sp<T>* val);
+ template <typename Enum, Enum kMaxValue = Enum::kMaxValue>
+ void ReadEnum(Enum* enum_value) {
+ static_assert(static_cast<unsigned>(kMaxValue) <= 255,
+ "Max value must fit in uint8_t");
+ uint8_t value = 0u;
+ Read(&value);
+ if (value > static_cast<uint8_t>(kMaxValue)) {
+ SetInvalid();
+ return;
+ }
+ *enum_value = static_cast<Enum>(value);
+ }
+
void SetInvalid(bool skip_crash_dump = false);
// The main entry point is Read(sk_sp<PaintFilter>* filter) which calls one of
diff --git a/chromium/cc/paint/paint_op_writer.cc b/chromium/cc/paint/paint_op_writer.cc
index e6b9d93b630..32aae4f2ce9 100644
--- a/chromium/cc/paint/paint_op_writer.cc
+++ b/chromium/cc/paint/paint_op_writer.cc
@@ -210,7 +210,7 @@ void PaintOpWriter::Write(const PaintFlags& flags) {
WriteSimple(flags.color_);
Write(flags.width_);
Write(flags.miter_limit_);
- WriteSimple(flags.blend_mode_);
+ Write(flags.blend_mode_);
WriteSimple(flags.bitfields_uint_);
WriteFlattenable(flags.path_effect_.get());
@@ -352,6 +352,17 @@ void PaintOpWriter::Write(const sk_sp<SkData>& data) {
}
}
+void PaintOpWriter::Write(const SkSamplingOptions& sampling) {
+ Write(sampling.useCubic);
+ if (sampling.useCubic) {
+ Write(sampling.cubic.B);
+ Write(sampling.cubic.C);
+ } else {
+ Write(sampling.filter);
+ Write(sampling.mipmap);
+ }
+}
+
void PaintOpWriter::Write(const SkColorSpace* color_space) {
if (!color_space) {
WriteSize(static_cast<size_t>(0));
@@ -449,6 +460,10 @@ void PaintOpWriter::Write(SkMatrix matrix) {
WriteSimple(matrix);
}
+void PaintOpWriter::Write(const SkM44& matrix) {
+ WriteSimple(matrix);
+}
+
void PaintOpWriter::Write(const PaintShader* shader, SkFilterQuality quality) {
sk_sp<PaintShader> transformed_shader;
uint32_t paint_image_transfer_cache_id = kInvalidImageTransferCacheEntryId;
@@ -476,10 +491,8 @@ void PaintOpWriter::Write(const PaintShader* shader, SkFilterQuality quality) {
WriteSimple(shader->flags_);
WriteSimple(shader->end_radius_);
WriteSimple(shader->start_radius_);
- // SkTileMode does not have an explicitly defined backing type, so
- // write a consistently sized value.
- Write(static_cast<int32_t>(shader->tx_));
- Write(static_cast<int32_t>(shader->ty_));
+ Write(shader->tx_);
+ Write(shader->ty_);
WriteSimple(shader->fallback_color_);
WriteSimple(shader->scaling_behavior_);
if (shader->local_matrix_) {
@@ -534,14 +547,18 @@ void PaintOpWriter::Write(const PaintShader* shader, SkFilterQuality quality) {
// using other fields.
}
-void PaintOpWriter::Write(SkColorType color_type) {
- WriteSimple(static_cast<uint32_t>(color_type));
-}
-
void PaintOpWriter::Write(SkYUVColorSpace yuv_color_space) {
WriteSimple(static_cast<uint32_t>(yuv_color_space));
}
+void PaintOpWriter::Write(SkYUVAInfo::PlaneConfig plane_config) {
+ WriteSimple(static_cast<uint32_t>(plane_config));
+}
+
+void PaintOpWriter::Write(SkYUVAInfo::Subsampling subsampling) {
+ WriteSimple(static_cast<uint32_t>(subsampling));
+}
+
void PaintOpWriter::WriteData(size_t bytes, const void* input) {
EnsureBytes(bytes);
if (!valid_)
@@ -575,15 +592,14 @@ void PaintOpWriter::AlignMemory(size_t alignment) {
void PaintOpWriter::Write(const PaintFilter* filter) {
if (!filter) {
- WriteSimple(static_cast<uint32_t>(PaintFilter::Type::kNullFilter));
+ WriteEnum(PaintFilter::Type::kNullFilter);
return;
}
- WriteSimple(static_cast<uint32_t>(filter->type()));
+ WriteEnum(filter->type());
auto* crop_rect = filter->crop_rect();
WriteSimple(static_cast<uint32_t>(!!crop_rect));
if (crop_rect) {
- WriteSimple(crop_rect->flags());
- WriteSimple(crop_rect->rect());
+ WriteSimple(*crop_rect);
}
if (!valid_)
@@ -671,7 +687,7 @@ void PaintOpWriter::Write(const ColorFilterPaintFilter& filter) {
void PaintOpWriter::Write(const BlurPaintFilter& filter) {
WriteSimple(filter.sigma_x());
WriteSimple(filter.sigma_y());
- WriteSimple(filter.tile_mode());
+ Write(filter.tile_mode());
Write(filter.input().get());
}
@@ -681,7 +697,7 @@ void PaintOpWriter::Write(const DropShadowPaintFilter& filter) {
WriteSimple(filter.sigma_x());
WriteSimple(filter.sigma_y());
WriteSimple(filter.color());
- WriteSimple(filter.shadow_mode());
+ WriteEnum(filter.shadow_mode());
Write(filter.input().get());
}
@@ -704,7 +720,7 @@ void PaintOpWriter::Write(const AlphaThresholdPaintFilter& filter) {
}
void PaintOpWriter::Write(const XfermodePaintFilter& filter) {
- WriteSimple(static_cast<uint32_t>(filter.blend_mode()));
+ Write(filter.blend_mode());
Write(filter.background().get());
Write(filter.foreground().get());
}
@@ -728,14 +744,14 @@ void PaintOpWriter::Write(const MatrixConvolutionPaintFilter& filter) {
WriteSimple(filter.gain());
WriteSimple(filter.bias());
WriteSimple(filter.kernel_offset());
- WriteSimple(static_cast<uint32_t>(filter.tile_mode()));
+ Write(filter.tile_mode());
WriteSimple(filter.convolve_alpha());
Write(filter.input().get());
}
void PaintOpWriter::Write(const DisplacementMapEffectPaintFilter& filter) {
- WriteSimple(static_cast<uint32_t>(filter.channel_x()));
- WriteSimple(static_cast<uint32_t>(filter.channel_y()));
+ WriteEnum(filter.channel_x());
+ WriteEnum(filter.channel_y());
WriteSimple(filter.scale());
Write(filter.displacement().get());
Write(filter.color().get());
@@ -783,7 +799,7 @@ void PaintOpWriter::Write(const MergePaintFilter& filter) {
}
void PaintOpWriter::Write(const MorphologyPaintFilter& filter) {
- WriteSimple(filter.morph_type());
+ WriteEnum(filter.morph_type());
WriteSimple(filter.radius_x());
WriteSimple(filter.radius_y());
Write(filter.input().get());
@@ -802,7 +818,7 @@ void PaintOpWriter::Write(const TilePaintFilter& filter) {
}
void PaintOpWriter::Write(const TurbulencePaintFilter& filter) {
- WriteSimple(filter.turbulence_type());
+ WriteEnum(filter.turbulence_type());
WriteSimple(filter.base_frequency_x());
WriteSimple(filter.base_frequency_y());
WriteSimple(filter.num_octaves());
@@ -816,12 +832,12 @@ void PaintOpWriter::Write(const PaintFlagsPaintFilter& filter) {
void PaintOpWriter::Write(const MatrixPaintFilter& filter) {
Write(filter.matrix());
- WriteSimple(filter.filter_quality());
+ Write(filter.filter_quality());
Write(filter.input().get());
}
void PaintOpWriter::Write(const LightingDistantPaintFilter& filter) {
- WriteSimple(filter.lighting_type());
+ WriteEnum(filter.lighting_type());
WriteSimple(filter.direction());
WriteSimple(filter.light_color());
WriteSimple(filter.surface_scale());
@@ -831,7 +847,7 @@ void PaintOpWriter::Write(const LightingDistantPaintFilter& filter) {
}
void PaintOpWriter::Write(const LightingPointPaintFilter& filter) {
- WriteSimple(filter.lighting_type());
+ WriteEnum(filter.lighting_type());
WriteSimple(filter.location());
WriteSimple(filter.light_color());
WriteSimple(filter.surface_scale());
@@ -841,7 +857,7 @@ void PaintOpWriter::Write(const LightingPointPaintFilter& filter) {
}
void PaintOpWriter::Write(const LightingSpotPaintFilter& filter) {
- WriteSimple(filter.lighting_type());
+ WriteEnum(filter.lighting_type());
WriteSimple(filter.location());
WriteSimple(filter.target());
WriteSimple(filter.specular_exponent());
diff --git a/chromium/cc/paint/paint_op_writer.h b/chromium/cc/paint/paint_op_writer.h
index d00eeea1d36..682ba1c8dff 100644
--- a/chromium/cc/paint/paint_op_writer.h
+++ b/chromium/cc/paint/paint_op_writer.h
@@ -13,6 +13,7 @@
#include "cc/paint/paint_filter.h"
#include "cc/paint/paint_op_buffer_serializer.h"
#include "third_party/skia/include/core/SkImageInfo.h"
+#include "third_party/skia/include/core/SkYUVAInfo.h"
struct SkRect;
struct SkIRect;
@@ -52,6 +53,7 @@ class CC_PAINT_EXPORT PaintOpWriter {
void Write(SkScalar data);
void Write(SkMatrix data);
+ void Write(const SkM44& data);
void Write(uint8_t data);
void Write(uint32_t data);
void Write(uint64_t data);
@@ -64,26 +66,25 @@ class CC_PAINT_EXPORT PaintOpWriter {
void Write(const PaintFlags& flags);
void Write(const sk_sp<SkData>& data);
void Write(const SkColorSpace* data);
+ void Write(const SkSamplingOptions&);
void Write(const PaintShader* shader, SkFilterQuality quality);
void Write(const PaintFilter* filter);
void Write(const sk_sp<SkTextBlob>& blob);
- void Write(SkColorType color_type);
void Write(SkYUVColorSpace yuv_color_space);
+ void Write(SkYUVAInfo::PlaneConfig plane_config);
+ void Write(SkYUVAInfo::Subsampling subsampling);
void Write(const gpu::Mailbox& mailbox);
- void Write(SkClipOp op) { Write(static_cast<uint8_t>(op)); }
- void Write(PaintCanvas::AnnotationType type) {
- Write(static_cast<uint8_t>(type));
- }
- void Write(SkCanvas::SrcRectConstraint constraint) {
- Write(static_cast<uint8_t>(constraint));
- }
- void Write(SkFilterQuality filter_quality) {
- Write(static_cast<uint8_t>(filter_quality));
- }
- void Write(SkBlendMode blend_mode) {
- Write(static_cast<uint8_t>(blend_mode));
- }
+ void Write(SkClipOp op) { WriteEnum(op); }
+ void Write(PaintCanvas::AnnotationType type) { WriteEnum(type); }
+ void Write(SkCanvas::SrcRectConstraint constraint) { WriteEnum(constraint); }
+ void Write(SkColorType color_type) { WriteEnum(color_type); }
+ void Write(SkFilterQuality filter_quality) { WriteEnum(filter_quality); }
+ void Write(SkBlendMode blend_mode) { WriteEnum(blend_mode); }
+ void Write(SkTileMode tile_mode) { WriteEnum(tile_mode); }
+ void Write(SkFilterMode filter_mode) { WriteEnum(filter_mode); }
+ void Write(SkMipmapMode mipmap_mode) { WriteEnum(mipmap_mode); }
+
void Write(bool data) { Write(static_cast<uint8_t>(data)); }
// Aligns the memory to the given alignment.
@@ -123,6 +124,11 @@ class CC_PAINT_EXPORT PaintOpWriter {
void WriteFlattenable(const SkFlattenable* val);
+ template <typename Enum>
+ void WriteEnum(Enum value) {
+ Write(base::checked_cast<uint8_t>(value));
+ }
+
// The main entry point is Write(const PaintFilter* filter) which casts the
// filter and calls one of the following functions.
void Write(const ColorFilterPaintFilter& filter);
diff --git a/chromium/cc/paint/paint_shader_unittest.cc b/chromium/cc/paint/paint_shader_unittest.cc
index e7e2223639d..4a33b87ffc2 100644
--- a/chromium/cc/paint/paint_shader_unittest.cc
+++ b/chromium/cc/paint/paint_shader_unittest.cc
@@ -48,7 +48,7 @@ class MockImageProvider : public ImageProvider {
sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
return ScopedResult(DecodedDrawImage(image, nullptr, SkSize::MakeEmpty(),
SkSize::Make(1.0f, 1.0f),
- draw_image.filter_quality()));
+ draw_image.filter_quality(), true));
}
const DrawImage& draw_image() const { return draw_image_; }
@@ -84,7 +84,7 @@ TEST(PaintShaderTest, DecodePaintRecord) {
.set_paint_image_generator(generator)
.TakePaintImage();
- record->push<DrawImageOp>(paint_image, 0.f, 0.f, nullptr);
+ record->push<DrawImageOp>(paint_image, 0.f, 0.f);
SkMatrix local_matrix = SkMatrix::Scale(0.5f, 0.5f);
auto record_shader = PaintShader::MakePaintRecord(
record, SkRect::MakeWH(100, 100), SkTileMode::kClamp, SkTileMode::kClamp,
diff --git a/chromium/cc/paint/paint_worklet_input.cc b/chromium/cc/paint/paint_worklet_input.cc
index 2e156bf1cb3..d0e05799183 100644
--- a/chromium/cc/paint/paint_worklet_input.cc
+++ b/chromium/cc/paint/paint_worklet_input.cc
@@ -4,10 +4,52 @@
#include "cc/paint/paint_worklet_input.h"
-#include <utility>
-
namespace cc {
+PaintWorkletInput::PropertyKey::PropertyKey(
+ const std::string& custom_property_name,
+ ElementId element_id)
+ : custom_property_name(custom_property_name), element_id(element_id) {}
+
+PaintWorkletInput::PropertyKey::PropertyKey(
+ NativePropertyType native_property_type,
+ ElementId element_id)
+ : native_property_type(native_property_type), element_id(element_id) {}
+
+PaintWorkletInput::PropertyKey::PropertyKey(const PropertyKey& other) = default;
+
+PaintWorkletInput::PropertyKey::~PropertyKey() = default;
+
+bool PaintWorkletInput::PropertyKey::operator==(
+ const PropertyKey& other) const {
+ return custom_property_name == other.custom_property_name &&
+ native_property_type == other.native_property_type &&
+ element_id == other.element_id;
+}
+
+bool PaintWorkletInput::PropertyKey::operator!=(
+ const PropertyKey& other) const {
+ return !(*this == other);
+}
+
+bool PaintWorkletInput::PropertyKey::operator<(const PropertyKey& other) const {
+ if (custom_property_name.has_value() &&
+ !other.custom_property_name.has_value())
+ return true;
+ if (!custom_property_name.has_value() &&
+ other.custom_property_name.has_value())
+ return false;
+ if (custom_property_name.has_value() &&
+ other.custom_property_name.has_value()) {
+ if (custom_property_name.value() == other.custom_property_name.value())
+ return element_id < other.element_id;
+ return custom_property_name.value() < other.custom_property_name.value();
+ }
+ if (native_property_type.value() == other.native_property_type.value())
+ return element_id < other.element_id;
+ return native_property_type.value() < other.native_property_type.value();
+}
+
PaintWorkletInput::PropertyValue::PropertyValue() = default;
PaintWorkletInput::PropertyValue::PropertyValue(float value)
diff --git a/chromium/cc/paint/paint_worklet_input.h b/chromium/cc/paint/paint_worklet_input.h
index 0f8eaec7602..18dbc8b7116 100644
--- a/chromium/cc/paint/paint_worklet_input.h
+++ b/chromium/cc/paint/paint_worklet_input.h
@@ -5,6 +5,10 @@
#ifndef CC_PAINT_PAINT_WORKLET_INPUT_H_
#define CC_PAINT_PAINT_WORKLET_INPUT_H_
+#include <string>
+#include <utility>
+#include <vector>
+
#include "base/containers/flat_map.h"
#include "base/memory/ref_counted.h"
#include "base/optional.h"
@@ -23,15 +27,38 @@ using PaintRecord = PaintOpBuffer;
class CC_PAINT_EXPORT PaintWorkletInput
: public base::RefCountedThreadSafe<PaintWorkletInput> {
public:
+ enum class NativePropertyType {
+ kBackgroundColor,
+ kInvalid,
+ };
// Uniquely identifies a property from the animation system, so that a
// PaintWorkletInput can specify the properties it depends on to be painted
// (and for which it must be repainted if their values change).
//
- // PropertyKey is designed to support both native and custom properties. The
- // same ElementId will be produced for all custom properties for a given
- // element. As such we require the custom property name as an additional key
- // to uniquely identify custom properties.
- using PropertyKey = std::pair<std::string, ElementId>;
+ // PropertyKey is designed to support both native and custom properties.
+ // 1. Custom properties: The same ElementId will be produced for all custom
+ // properties for a given element. As such we require the custom property
+ // name as an additional key to uniquely identify custom properties.
+ // 2. Native properties: When fetching the current value of a native
+ // property from property tree, we need the ElementId, plus knowing which
+ // tree to fetch the value from, and that's why we need the
+ // |native_property_type|.
+ // One property key should have either |custom_property_name| or
+ // |native_property_type|, and should never have both or neither.
+ struct CC_PAINT_EXPORT PropertyKey {
+ PropertyKey(const std::string& custom_property_name, ElementId element_id);
+ PropertyKey(NativePropertyType native_property_type, ElementId element_id);
+ PropertyKey(const PropertyKey&);
+ ~PropertyKey();
+
+ bool operator==(const PropertyKey& other) const;
+ bool operator!=(const PropertyKey& other) const;
+ bool operator<(const PropertyKey&) const;
+
+ base::Optional<std::string> custom_property_name;
+ base::Optional<NativePropertyType> native_property_type;
+ ElementId element_id;
+ };
// A structure that can hold either a float or color type value, depending
// on the type of custom property. Only one of |float_val| and |color_val|
diff --git a/chromium/cc/paint/paint_worklet_input_unittest.cc b/chromium/cc/paint/paint_worklet_input_unittest.cc
new file mode 100644
index 00000000000..37965a40a05
--- /dev/null
+++ b/chromium/cc/paint/paint_worklet_input_unittest.cc
@@ -0,0 +1,24 @@
+// 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.
+
+#include "cc/paint/paint_worklet_input.h"
+
+#include "base/containers/flat_set.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+
+TEST(PaintWorkletInputTest, InsertPropertyKeyToFlatSet) {
+ base::flat_set<PaintWorkletInput::PropertyKey> property_keys;
+
+ PaintWorkletInput::PropertyKey key1("foo", ElementId(128u));
+ property_keys.insert(key1);
+ EXPECT_EQ(property_keys.size(), 1u);
+
+ PaintWorkletInput::PropertyKey key2("foo", ElementId(130u));
+ property_keys.insert(key2);
+ EXPECT_EQ(property_keys.size(), 2u);
+}
+
+} // namespace cc
diff --git a/chromium/cc/paint/paint_worklet_job.h b/chromium/cc/paint/paint_worklet_job.h
index e83c0629761..ccba901196d 100644
--- a/chromium/cc/paint/paint_worklet_job.h
+++ b/chromium/cc/paint/paint_worklet_job.h
@@ -5,6 +5,8 @@
#ifndef CC_PAINT_PAINT_WORKLET_JOB_H_
#define CC_PAINT_PAINT_WORKLET_JOB_H_
+#include <vector>
+
#include "base/containers/flat_map.h"
#include "base/memory/scoped_refptr.h"
#include "cc/paint/paint_export.h"
@@ -24,7 +26,8 @@ class CC_PAINT_EXPORT PaintWorkletJob {
// For a custom property, its name is sufficient to uniquely identify it.
// TODO(xidachen): support more property types such as color.
using AnimatedPropertyValues =
- base::flat_map<std::string, PaintWorkletInput::PropertyValue>;
+ base::flat_map<PaintWorkletInput::PropertyKey,
+ PaintWorkletInput::PropertyValue>;
PaintWorkletJob(int layer_id,
scoped_refptr<const PaintWorkletInput> input,
AnimatedPropertyValues animated_property_values);
diff --git a/chromium/cc/paint/record_paint_canvas.cc b/chromium/cc/paint/record_paint_canvas.cc
index e8758c76972..d4870865146 100644
--- a/chromium/cc/paint/record_paint_canvas.cc
+++ b/chromium/cc/paint/record_paint_canvas.cc
@@ -108,11 +108,23 @@ void RecordPaintCanvas::rotate(SkScalar degrees) {
}
void RecordPaintCanvas::concat(const SkMatrix& matrix) {
+ SkM44 m = SkM44(matrix);
+ list_->push<ConcatOp>(m);
+ GetCanvas()->concat(m);
+}
+
+void RecordPaintCanvas::concat(const SkM44& matrix) {
list_->push<ConcatOp>(matrix);
GetCanvas()->concat(matrix);
}
void RecordPaintCanvas::setMatrix(const SkMatrix& matrix) {
+ SkM44 m = SkM44(matrix);
+ list_->push<SetMatrixOp>(m);
+ GetCanvas()->setMatrix(m);
+}
+
+void RecordPaintCanvas::setMatrix(const SkM44& matrix) {
list_->push<SetMatrixOp>(matrix);
GetCanvas()->setMatrix(matrix);
}
@@ -252,17 +264,19 @@ void RecordPaintCanvas::drawPath(const SkPath& path, const PaintFlags& flags) {
void RecordPaintCanvas::drawImage(const PaintImage& image,
SkScalar left,
SkScalar top,
+ const SkSamplingOptions& sampling,
const PaintFlags* flags) {
DCHECK(!image.IsPaintWorklet());
- list_->push<DrawImageOp>(image, left, top, flags);
+ list_->push<DrawImageOp>(image, left, top, sampling, flags);
}
void RecordPaintCanvas::drawImageRect(const PaintImage& image,
const SkRect& src,
const SkRect& dst,
+ const SkSamplingOptions& sampling,
const PaintFlags* flags,
SkCanvas::SrcRectConstraint constraint) {
- list_->push<DrawImageRectOp>(image, src, dst, flags, constraint);
+ list_->push<DrawImageRectOp>(image, src, dst, sampling, flags, constraint);
}
void RecordPaintCanvas::drawSkottie(scoped_refptr<SkottieWrapper> skottie,
diff --git a/chromium/cc/paint/record_paint_canvas.h b/chromium/cc/paint/record_paint_canvas.h
index 4917088a76e..b08c8c8e064 100644
--- a/chromium/cc/paint/record_paint_canvas.h
+++ b/chromium/cc/paint/record_paint_canvas.h
@@ -46,8 +46,12 @@ class CC_PAINT_EXPORT RecordPaintCanvas : public PaintCanvas {
void translate(SkScalar dx, SkScalar dy) override;
void scale(SkScalar sx, SkScalar sy) override;
void rotate(SkScalar degrees) override;
+ // TODO(crbug.com/1167153): The concat and setMatrix methods that take an
+ // SkMatrix should be removed in favor of the SkM44 versions.
void concat(const SkMatrix& matrix) override;
void setMatrix(const SkMatrix& matrix) override;
+ void concat(const SkM44& matrix) override;
+ void setMatrix(const SkM44& matrix) override;
void clipRect(const SkRect& rect, SkClipOp op, bool antialias) override;
void clipRRect(const SkRRect& rrect, SkClipOp op, bool antialias) override;
@@ -79,10 +83,12 @@ class CC_PAINT_EXPORT RecordPaintCanvas : public PaintCanvas {
void drawImage(const PaintImage& image,
SkScalar left,
SkScalar top,
+ const SkSamplingOptions&,
const PaintFlags* flags) override;
void drawImageRect(const PaintImage& image,
const SkRect& src,
const SkRect& dst,
+ const SkSamplingOptions&,
const PaintFlags* flags,
SkCanvas::SrcRectConstraint constraint) override;
void drawSkottie(scoped_refptr<SkottieWrapper> skottie,
diff --git a/chromium/cc/paint/render_surface_filters.cc b/chromium/cc/paint/render_surface_filters.cc
index 913cd402028..d8b243ee1a1 100644
--- a/chromium/cc/paint/render_surface_filters.cc
+++ b/chromium/cc/paint/render_surface_filters.cc
@@ -12,14 +12,7 @@
#include "cc/paint/filter_operations.h"
#include "cc/paint/paint_filter.h"
#include "third_party/skia/include/core/SkColorFilter.h"
-#include "third_party/skia/include/core/SkImageFilter.h"
#include "third_party/skia/include/core/SkRegion.h"
-#include "third_party/skia/include/effects/SkAlphaThresholdFilter.h"
-#include "third_party/skia/include/effects/SkColorFilterImageFilter.h"
-#include "third_party/skia/include/effects/SkColorMatrixFilter.h"
-#include "third_party/skia/include/effects/SkComposeImageFilter.h"
-#include "third_party/skia/include/effects/SkDropShadowImageFilter.h"
-#include "third_party/skia/include/effects/SkMagnifierImageFilter.h"
#include "ui/gfx/geometry/size_f.h"
#include "ui/gfx/skia_util.h"
@@ -209,7 +202,7 @@ sk_sp<PaintFilter> RenderSurfaceFilters::BuildImageFilter(
SkIntToScalar(op.drop_shadow_offset().y()),
SkIntToScalar(op.amount()), SkIntToScalar(op.amount()),
op.drop_shadow_color(),
- SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
+ DropShadowPaintFilter::ShadowMode::kDrawShadowAndForeground,
std::move(image_filter));
break;
case FilterOperation::COLOR_MATRIX:
diff --git a/chromium/cc/paint/scoped_raster_flags_unittest.cc b/chromium/cc/paint/scoped_raster_flags_unittest.cc
index bfd32db2a49..1b2439b9fdc 100644
--- a/chromium/cc/paint/scoped_raster_flags_unittest.cc
+++ b/chromium/cc/paint/scoped_raster_flags_unittest.cc
@@ -5,7 +5,6 @@
#include "cc/paint/scoped_raster_flags.h"
#include <utility>
-
#include "base/bind.h"
#include "base/callback.h"
#include "cc/paint/paint_op_buffer.h"
@@ -31,7 +30,8 @@ class MockImageProvider : public ImageProvider {
return ScopedResult(
DecodedDrawImage(image, nullptr, SkSize::MakeEmpty(),
- SkSize::Make(1.0f, 1.0f), draw_image.filter_quality()),
+ SkSize::Make(1.0f, 1.0f), draw_image.filter_quality(),
+ true),
base::BindOnce(&MockImageProvider::UnrefImage, base::Unretained(this)));
}
@@ -82,11 +82,11 @@ TEST(ScopedRasterFlagsTest, DecodePaintWorkletImageShader) {
TEST(ScopedRasterFlagsTest, KeepsDecodesAlive) {
auto record = sk_make_sp<PaintOpBuffer>();
record->push<DrawImageOp>(CreateDiscardablePaintImage(gfx::Size(10, 10)), 0.f,
- 0.f, nullptr);
+ 0.f);
record->push<DrawImageOp>(CreateDiscardablePaintImage(gfx::Size(10, 10)), 0.f,
- 0.f, nullptr);
+ 0.f);
record->push<DrawImageOp>(CreateDiscardablePaintImage(gfx::Size(10, 10)), 0.f,
- 0.f, nullptr);
+ 0.f);
auto record_shader = PaintShader::MakePaintRecord(
record, SkRect::MakeWH(100, 100), SkTileMode::kClamp, SkTileMode::kClamp,
&SkMatrix::I());
diff --git a/chromium/cc/paint/skia_paint_canvas.cc b/chromium/cc/paint/skia_paint_canvas.cc
index a9674da95a3..2067070cfe4 100644
--- a/chromium/cc/paint/skia_paint_canvas.cc
+++ b/chromium/cc/paint/skia_paint_canvas.cc
@@ -93,6 +93,14 @@ void SkiaPaintCanvas::rotate(SkScalar degrees) {
canvas_->rotate(degrees);
}
+void SkiaPaintCanvas::setMatrix(const SkM44& matrix) {
+ canvas_->setMatrix(matrix);
+}
+
+void SkiaPaintCanvas::concat(const SkM44& matrix) {
+ canvas_->concat(matrix);
+}
+
void SkiaPaintCanvas::concat(const SkMatrix& matrix) {
canvas_->concat(matrix);
}
@@ -255,6 +263,7 @@ void SkiaPaintCanvas::drawPath(const SkPath& path, const PaintFlags& flags) {
void SkiaPaintCanvas::drawImage(const PaintImage& image,
SkScalar left,
SkScalar top,
+ const SkSamplingOptions& sampling,
const PaintFlags* flags) {
DCHECK(!image.IsPaintWorklet());
base::Optional<ScopedRasterFlags> scoped_flags;
@@ -266,8 +275,8 @@ void SkiaPaintCanvas::drawImage(const PaintImage& image,
}
const PaintFlags* raster_flags = scoped_flags ? scoped_flags->flags() : flags;
- PlaybackParams params(image_provider_, canvas_->getTotalMatrix());
- DrawImageOp draw_image_op(image, left, top, nullptr);
+ PlaybackParams params(image_provider_, canvas_->getLocalToDevice());
+ DrawImageOp draw_image_op(image, left, top, sampling, nullptr);
DrawImageOp::RasterWithFlags(&draw_image_op, raster_flags, canvas_, params);
FlushAfterDrawIfNeeded();
}
@@ -275,6 +284,7 @@ void SkiaPaintCanvas::drawImage(const PaintImage& image,
void SkiaPaintCanvas::drawImageRect(const PaintImage& image,
const SkRect& src,
const SkRect& dst,
+ const SkSamplingOptions& sampling,
const PaintFlags* flags,
SkCanvas::SrcRectConstraint constraint) {
base::Optional<ScopedRasterFlags> scoped_flags;
@@ -286,8 +296,9 @@ void SkiaPaintCanvas::drawImageRect(const PaintImage& image,
}
const PaintFlags* raster_flags = scoped_flags ? scoped_flags->flags() : flags;
- PlaybackParams params(image_provider_, canvas_->getTotalMatrix());
- DrawImageRectOp draw_image_rect_op(image, src, dst, flags, constraint);
+ PlaybackParams params(image_provider_, canvas_->getLocalToDevice());
+ DrawImageRectOp draw_image_rect_op(image, src, dst, sampling, flags,
+ constraint);
DrawImageRectOp::RasterWithFlags(&draw_image_rect_op, raster_flags, canvas_,
params);
FlushAfterDrawIfNeeded();
@@ -369,7 +380,7 @@ void SkiaPaintCanvas::drawPicture(
? base::BindRepeating(&SkiaPaintCanvas::FlushAfterDrawIfNeeded,
base::Unretained(this))
: PlaybackParams::DidDrawOpCallback();
- PlaybackParams params(image_provider_, canvas_->getTotalMatrix(),
+ PlaybackParams params(image_provider_, canvas_->getLocalToDevice(),
custom_raster_callback, did_draw_op_cb);
record->Playback(canvas_, params);
}
diff --git a/chromium/cc/paint/skia_paint_canvas.h b/chromium/cc/paint/skia_paint_canvas.h
index dcc7f46a9a9..ff4f96a0c6a 100644
--- a/chromium/cc/paint/skia_paint_canvas.h
+++ b/chromium/cc/paint/skia_paint_canvas.h
@@ -70,6 +70,8 @@ class CC_PAINT_EXPORT SkiaPaintCanvas final : public PaintCanvas {
void rotate(SkScalar degrees) override;
void concat(const SkMatrix& matrix) override;
void setMatrix(const SkMatrix& matrix) override;
+ void concat(const SkM44& matrix) override;
+ void setMatrix(const SkM44& matrix) override;
void clipRect(const SkRect& rect, SkClipOp op, bool do_anti_alias) override;
void clipRRect(const SkRRect& rrect,
@@ -103,10 +105,12 @@ class CC_PAINT_EXPORT SkiaPaintCanvas final : public PaintCanvas {
void drawImage(const PaintImage& image,
SkScalar left,
SkScalar top,
+ const SkSamplingOptions&,
const PaintFlags* flags) override;
void drawImageRect(const PaintImage& image,
const SkRect& src,
const SkRect& dst,
+ const SkSamplingOptions&,
const PaintFlags* flags,
SkCanvas::SrcRectConstraint constraint) override;
void drawSkottie(scoped_refptr<SkottieWrapper> skottie,
diff --git a/chromium/cc/paint/solid_color_analyzer.cc b/chromium/cc/paint/solid_color_analyzer.cc
index 4e3ca84770f..c90cb6ab0eb 100644
--- a/chromium/cc/paint/solid_color_analyzer.cc
+++ b/chromium/cc/paint/solid_color_analyzer.cc
@@ -93,32 +93,40 @@ bool IsSolidColorPaint(const PaintFlags& flags) {
// Returns true if the specified |drawn_shape| will cover the entire canvas
// and that the canvas is not clipped (i.e. it covers ALL of the canvas).
+// We expect this method to return false most of the time so we take
+// conservative early-outs when possible.
template <typename T>
bool IsFullQuad(const SkCanvas& canvas, const T& drawn_shape) {
if (!canvas.isClipRect())
return false;
- SkIRect clip_irect;
- if (!canvas.getDeviceClipBounds(&clip_irect))
+ SkIRect clip_bounds;
+ if (!canvas.getDeviceClipBounds(&clip_bounds))
return false;
// if the clip is smaller than the canvas, we're partly clipped, so abort.
- if (!clip_irect.contains(SkIRect::MakeSize(canvas.getBaseLayerSize())))
+ if (!clip_bounds.contains(SkIRect::MakeSize(canvas.getBaseLayerSize())))
return false;
- const SkMatrix& matrix = canvas.getTotalMatrix();
- // If the transform results in a non-axis aligned
- // rect, then be conservative and return false.
- if (!matrix.rectStaysRect())
+ const SkM44& matrix = canvas.getLocalToDevice();
+ // If the transform results in a non-axis aligned rectangle, then be
+ // conservative and return false.
+ if (!MathUtil::SkM44Preserves2DAxisAlignment(matrix))
return false;
- SkMatrix inverse;
+ SkM44 inverse;
if (!matrix.invert(&inverse))
return false;
- SkRect clip_rect = SkRect::Make(clip_irect);
- inverse.mapRect(&clip_rect, clip_rect);
- return drawn_shape.contains(clip_rect);
+ // Check that the drawn shape contains the canvas bounds when those bounds
+ // are transformed into the shape's coordinate space. Since we know the
+ // transform is axis aligned we only need to test two corners.
+ SkV4 upper_left = inverse.map(clip_bounds.left(), clip_bounds.top(), 0, 1);
+ SkV4 lower_right =
+ inverse.map(clip_bounds.right(), clip_bounds.bottom(), 0, 1);
+ SkRect transformed_clip_bounds = SkRect::MakeLTRB(
+ upper_left.x, upper_left.y, lower_right.x, lower_right.y);
+ return drawn_shape.contains(transformed_clip_bounds);
}
void CalculateSolidColor(SkColor src_color,
@@ -231,12 +239,12 @@ base::Optional<SkColor> SolidColorAnalyzer::DetermineIfSolidColor(
struct Frame {
Frame(PaintOpBuffer::CompositeIterator iter,
- const SkMatrix& original_ctm,
+ const SkM44& original_ctm,
int save_count)
: iter(iter), original_ctm(original_ctm), save_count(save_count) {}
PaintOpBuffer::CompositeIterator iter;
- const SkMatrix original_ctm;
+ const SkM44 original_ctm;
int save_count = 0;
};
@@ -249,7 +257,7 @@ base::Optional<SkColor> SolidColorAnalyzer::DetermineIfSolidColor(
// constructed. Reserve this to 2, and go from there.
stack.reserve(2);
stack.emplace_back(PaintOpBuffer::CompositeIterator(buffer, offsets),
- canvas.getTotalMatrix(), canvas.getSaveCount());
+ canvas.getLocalToDevice(), canvas.getSaveCount());
int num_draw_ops = 0;
while (!stack.empty()) {
@@ -263,13 +271,13 @@ base::Optional<SkColor> SolidColorAnalyzer::DetermineIfSolidColor(
}
const PaintOp* op = *frame.iter;
- PlaybackParams params(nullptr, frame.original_ctm);
+ PlaybackParams params(nullptr, SkM44(frame.original_ctm));
switch (op->GetType()) {
case PaintOpType::DrawRecord: {
const DrawRecordOp* record_op = static_cast<const DrawRecordOp*>(op);
stack.emplace_back(
PaintOpBuffer::CompositeIterator(record_op->record.get(), nullptr),
- canvas.getTotalMatrix(), canvas.getSaveCount());
+ canvas.getLocalToDevice(), canvas.getSaveCount());
continue;
}
diff --git a/chromium/cc/paint/transfer_cache_deserialize_helper.h b/chromium/cc/paint/transfer_cache_deserialize_helper.h
index 59b1ca645e2..6c94c515bf1 100644
--- a/chromium/cc/paint/transfer_cache_deserialize_helper.h
+++ b/chromium/cc/paint/transfer_cache_deserialize_helper.h
@@ -7,6 +7,8 @@
#include <cstdint>
+#include <memory>
+
#include "cc/paint/paint_export.h"
#include "cc/paint/transfer_cache_entry.h"
@@ -18,7 +20,7 @@ namespace cc {
// we need to figure out layering. crbug.com/777622
class CC_PAINT_EXPORT TransferCacheDeserializeHelper {
public:
- virtual ~TransferCacheDeserializeHelper() {}
+ virtual ~TransferCacheDeserializeHelper() = default;
// Type safe access to an entry in the transfer cache. Returns null if the
// entry is missing or of the wrong type.
diff --git a/chromium/cc/paint/transfer_cache_entry.h b/chromium/cc/paint/transfer_cache_entry.h
index cd209df7315..9b96cd34162 100644
--- a/chromium/cc/paint/transfer_cache_entry.h
+++ b/chromium/cc/paint/transfer_cache_entry.h
@@ -32,7 +32,7 @@ enum class TransferCacheEntryType : uint32_t {
// into raw bytes that can be sent to the service.
class CC_PAINT_EXPORT ClientTransferCacheEntry {
public:
- virtual ~ClientTransferCacheEntry() {}
+ virtual ~ClientTransferCacheEntry() = default;
// Returns the type of this entry. Combined with id, it should form a unique
// identifier.
@@ -73,7 +73,7 @@ class CC_PAINT_EXPORT ServiceTransferCacheEntry {
// Returns true if the entry needs a GrContext during deserialization.
static bool UsesGrContext(TransferCacheEntryType type);
- virtual ~ServiceTransferCacheEntry() {}
+ virtual ~ServiceTransferCacheEntry() = default;
// Returns the type of this entry.
virtual TransferCacheEntryType Type() const = 0;
diff --git a/chromium/cc/raster/bitmap_raster_buffer_provider.cc b/chromium/cc/raster/bitmap_raster_buffer_provider.cc
index 0e6287c50a7..397fe0867be 100644
--- a/chromium/cc/raster/bitmap_raster_buffer_provider.cc
+++ b/chromium/cc/raster/bitmap_raster_buffer_provider.cc
@@ -160,8 +160,4 @@ uint64_t BitmapRasterBufferProvider::SetReadyToDrawCallback(
void BitmapRasterBufferProvider::Shutdown() {}
-bool BitmapRasterBufferProvider::CheckRasterFinishedQueries() {
- return false;
-}
-
} // namespace cc
diff --git a/chromium/cc/raster/bitmap_raster_buffer_provider.h b/chromium/cc/raster/bitmap_raster_buffer_provider.h
index 60a01b00aa3..88a1837acde 100644
--- a/chromium/cc/raster/bitmap_raster_buffer_provider.h
+++ b/chromium/cc/raster/bitmap_raster_buffer_provider.h
@@ -51,7 +51,6 @@ class CC_EXPORT BitmapRasterBufferProvider : public RasterBufferProvider {
base::OnceClosure callback,
uint64_t pending_callback_id) const override;
void Shutdown() override;
- bool CheckRasterFinishedQueries() override;
private:
std::unique_ptr<base::trace_event::ConvertableToTraceFormat> StateAsValue()
diff --git a/chromium/cc/raster/gpu_raster_buffer_provider.cc b/chromium/cc/raster/gpu_raster_buffer_provider.cc
index 76ecd0d6366..0f76c1a85c2 100644
--- a/chromium/cc/raster/gpu_raster_buffer_provider.cc
+++ b/chromium/cc/raster/gpu_raster_buffer_provider.cc
@@ -45,78 +45,6 @@
namespace cc {
namespace {
-class ScopedSkSurfaceForUnpremultiplyAndDither {
- public:
- ScopedSkSurfaceForUnpremultiplyAndDither(
- viz::RasterContextProvider* context_provider,
- sk_sp<SkColorSpace> color_space,
- const gfx::Rect& playback_rect,
- const gfx::Rect& raster_full_rect,
- const gfx::Size& max_tile_size,
- GLuint texture_id,
- const gfx::Size& texture_size,
- bool can_use_lcd_text,
- int msaa_sample_count)
- : context_provider_(context_provider),
- texture_id_(texture_id),
- offset_(playback_rect.OffsetFromOrigin() -
- raster_full_rect.OffsetFromOrigin()),
- size_(playback_rect.size()) {
- // Determine the |intermediate_size| to use for our 32-bit texture. If we
- // know the max tile size, use that. This prevents GPU cache explosion due
- // to using lots of different 32-bit texture sizes. Otherwise just use the
- // exact size of the target texture.
- gfx::Size intermediate_size;
- if (!max_tile_size.IsEmpty()) {
- DCHECK_GE(max_tile_size.width(), texture_size.width());
- DCHECK_GE(max_tile_size.height(), texture_size.height());
- intermediate_size = max_tile_size;
- } else {
- intermediate_size = texture_size;
- }
-
- // Allocate a 32-bit surface for raster. We will copy from that into our
- // actual surface in destruction.
- SkImageInfo n32Info = SkImageInfo::MakeN32Premul(intermediate_size.width(),
- intermediate_size.height(),
- std::move(color_space));
- SkSurfaceProps surface_props =
- skia::LegacyDisplayGlobals::ComputeSurfaceProps(can_use_lcd_text);
- surface_ = SkSurface::MakeRenderTarget(
- context_provider->GrContext(), SkBudgeted::kNo, n32Info,
- msaa_sample_count, kTopLeft_GrSurfaceOrigin, &surface_props);
- }
-
- ~ScopedSkSurfaceForUnpremultiplyAndDither() {
- // In lost-context cases, |surface_| may be null and there's nothing
- // meaningful to do here.
- if (!surface_)
- return;
-
- GrBackendTexture backend_texture =
- surface_->getBackendTexture(SkSurface::kFlushRead_BackendHandleAccess);
- if (!backend_texture.isValid()) {
- return;
- }
- GrGLTextureInfo info;
- if (!backend_texture.getGLTextureInfo(&info)) {
- return;
- }
- context_provider_->ContextGL()->UnpremultiplyAndDitherCopyCHROMIUM(
- info.fID, texture_id_, offset_.x(), offset_.y(), size_.width(),
- size_.height());
- }
-
- SkSurface* surface() { return surface_.get(); }
-
- private:
- viz::RasterContextProvider* context_provider_;
- GLuint texture_id_;
- gfx::Vector2d offset_;
- gfx::Size size_;
- sk_sp<SkSurface> surface_;
-};
-
static void RasterizeSourceOOP(
const RasterSource* raster_source,
bool resource_has_previous_content,
@@ -186,7 +114,6 @@ static void RasterizeSource(
const gfx::AxisTransform2d& transform,
const RasterSource::PlaybackSettings& playback_settings,
viz::RasterContextProvider* context_provider,
- bool unpremultiply_and_dither,
const gfx::Size& max_tile_size) {
gpu::raster::RasterInterface* ri = context_provider->RasterInterface();
if (mailbox->IsZero()) {
@@ -211,26 +138,15 @@ static void RasterizeSource(
texture_id, GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM);
{
ScopedGrContextAccess gr_context_access(context_provider);
- base::Optional<viz::ClientResourceProvider::ScopedSkSurface> scoped_surface;
- base::Optional<ScopedSkSurfaceForUnpremultiplyAndDither>
- scoped_dither_surface;
SkSurface* surface;
sk_sp<SkColorSpace> sk_color_space = color_space.ToSkColorSpace();
- if (!unpremultiply_and_dither) {
- scoped_surface.emplace(context_provider->GrContext(), sk_color_space,
- texture_id, texture_target, resource_size,
- resource_format,
- skia::LegacyDisplayGlobals::ComputeSurfaceProps(
- playback_settings.use_lcd_text),
- playback_settings.msaa_sample_count);
- surface = scoped_surface->surface();
- } else {
- scoped_dither_surface.emplace(
- context_provider, sk_color_space, playback_rect, raster_full_rect,
- max_tile_size, texture_id, resource_size,
- playback_settings.use_lcd_text, playback_settings.msaa_sample_count);
- surface = scoped_dither_surface->surface();
- }
+ viz::ClientResourceProvider::ScopedSkSurface scoped_surface(
+ context_provider->GrContext(), sk_color_space, texture_id,
+ texture_target, resource_size, resource_format,
+ skia::LegacyDisplayGlobals::ComputeSurfaceProps(
+ playback_settings.use_lcd_text),
+ playback_settings.msaa_sample_count);
+ surface = scoped_surface.surface();
// Allocating an SkSurface will fail after a lost context. Pretend we
// rasterized, as the contents of the resource don't matter anymore.
@@ -372,17 +288,18 @@ GpuRasterBufferProvider::GpuRasterBufferProvider(
const gfx::Size& max_tile_size,
bool unpremultiply_and_dither_low_bit_depth_tiles,
bool enable_oop_rasterization,
+ RasterQueryQueue* const pending_raster_queries,
float raster_metric_probability)
: compositor_context_provider_(compositor_context_provider),
worker_context_provider_(worker_context_provider),
use_gpu_memory_buffer_resources_(use_gpu_memory_buffer_resources),
tile_format_(tile_format),
max_tile_size_(max_tile_size),
- unpremultiply_and_dither_low_bit_depth_tiles_(
- unpremultiply_and_dither_low_bit_depth_tiles),
enable_oop_rasterization_(enable_oop_rasterization),
+ pending_raster_queries_(pending_raster_queries),
random_generator_(static_cast<uint32_t>(base::RandUint64())),
bernoulli_distribution_(raster_metric_probability) {
+ DCHECK(pending_raster_queries);
DCHECK(compositor_context_provider);
DCHECK(worker_context_provider);
}
@@ -494,7 +411,7 @@ gpu::SyncToken GpuRasterBufferProvider::PlaybackOnWorkerThread(
bool depends_on_at_raster_decodes,
bool depends_on_hardware_accelerated_jpeg_candidates,
bool depends_on_hardware_accelerated_webp_candidates) {
- PendingRasterQuery query;
+ RasterQuery query;
query.depends_on_hardware_accelerated_jpeg_candidates =
depends_on_hardware_accelerated_jpeg_candidates;
query.depends_on_hardware_accelerated_webp_candidates =
@@ -511,13 +428,12 @@ gpu::SyncToken GpuRasterBufferProvider::PlaybackOnWorkerThread(
query.raster_buffer_creation_time = raster_buffer_creation_time;
// Note that it is important to scope the raster context lock to
- // PlaybackOnWorkerThreadInternal and release it before acquiring this lock
- // to avoid a deadlock in CheckRasterFinishedQueries which acquires the
- // raster context lock while holding this lock.
- base::AutoLock hold(pending_raster_queries_lock_);
- pending_raster_queries_.push_back(query);
+ // PlaybackOnWorkerThreadInternal and release it before calling this
+ // function to avoid a deadlock in
+ // RasterQueryQueue::CheckRasterFinishedQueries which acquires the raster
+ // context lock while holding a lock used in the function.
+ pending_raster_queries_->Append(std::move(query));
}
- DCHECK(!query.raster_start_query_id || query.raster_duration_query_id);
return raster_finished_token;
}
@@ -539,7 +455,7 @@ gpu::SyncToken GpuRasterBufferProvider::PlaybackOnWorkerThreadInternal(
const RasterSource::PlaybackSettings& playback_settings,
const GURL& url,
bool depends_on_at_raster_decodes,
- PendingRasterQuery* query) {
+ RasterQuery* query) {
viz::RasterContextProvider::ScopedRasterContextLock scoped_context(
worker_context_provider_, url.possibly_invalid_spec().c_str());
gpu::raster::RasterInterface* ri = scoped_context.RasterInterface();
@@ -597,7 +513,6 @@ gpu::SyncToken GpuRasterBufferProvider::PlaybackOnWorkerThreadInternal(
resource_size, resource_format, color_space,
raster_full_rect, playback_rect, transform,
playback_settings, worker_context_provider_,
- ShouldUnpremultiplyAndDitherResource(resource_format),
max_tile_size_);
}
if (measure_raster_metric) {
@@ -612,121 +527,8 @@ gpu::SyncToken GpuRasterBufferProvider::PlaybackOnWorkerThreadInternal(
bool GpuRasterBufferProvider::ShouldUnpremultiplyAndDitherResource(
viz::ResourceFormat format) const {
- switch (format) {
- case viz::RGBA_4444:
- return unpremultiply_and_dither_low_bit_depth_tiles_;
- default:
- return false;
- }
-}
-
-#define UMA_HISTOGRAM_RASTER_TIME_CUSTOM_MICROSECONDS(name, total_time) \
- UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES( \
- name, total_time, base::TimeDelta::FromMicroseconds(1), \
- base::TimeDelta::FromMilliseconds(100), 100);
-
-bool GpuRasterBufferProvider::CheckRasterFinishedQueries() {
- base::AutoLock hold(pending_raster_queries_lock_);
- if (pending_raster_queries_.empty())
- return false;
-
- viz::RasterContextProvider::ScopedRasterContextLock scoped_context(
- worker_context_provider_);
- auto* ri = scoped_context.RasterInterface();
-
- auto it = pending_raster_queries_.begin();
- while (it != pending_raster_queries_.end()) {
- GLuint complete = 0;
- ri->GetQueryObjectuivEXT(it->raster_duration_query_id,
- GL_QUERY_RESULT_AVAILABLE_NO_FLUSH_CHROMIUM_EXT,
- &complete);
- if (!complete)
- break;
-
-#if DCHECK_IS_ON()
- if (it->raster_start_query_id) {
- // We issued the GL_COMMANDS_ISSUED_TIMESTAMP_CHROMIUM query prior to the
- // GL_COMMANDS_ISSUED_CHROMIUM query. Therefore, if the result of the
- // latter is available, the result of the former should be too.
- complete = 0;
- ri->GetQueryObjectuivEXT(it->raster_start_query_id,
- GL_QUERY_RESULT_AVAILABLE_NO_FLUSH_CHROMIUM_EXT,
- &complete);
- DCHECK(complete);
- }
-#endif
-
- GLuint gpu_raster_duration = 0u;
- ri->GetQueryObjectuivEXT(it->raster_duration_query_id, GL_QUERY_RESULT_EXT,
- &gpu_raster_duration);
- ri->DeleteQueriesEXT(1, &it->raster_duration_query_id);
-
- base::TimeDelta raster_duration =
- it->worker_raster_duration +
- base::TimeDelta::FromMicroseconds(gpu_raster_duration);
-
- // It is safe to use the UMA macros here with runtime generated strings
- // because the client name should be initialized once in the process, before
- // recording any metrics here.
- const char* client_name = GetClientNameForMetrics();
-
- if (it->raster_start_query_id) {
- GLuint64 gpu_raster_start_time = 0u;
- ri->GetQueryObjectui64vEXT(it->raster_start_query_id, GL_QUERY_RESULT_EXT,
- &gpu_raster_start_time);
- ri->DeleteQueriesEXT(1, &it->raster_start_query_id);
-
- // The base::checked_cast<int64_t> should not crash as long as the GPU
- // process was not compromised: that's because the result of the query
- // should have been generated using base::TimeDelta::InMicroseconds()
- // there, so the result should fit in an int64_t.
- base::TimeDelta raster_scheduling_delay =
- base::TimeDelta::FromMicroseconds(
- base::checked_cast<int64_t>(gpu_raster_start_time)) -
- it->raster_buffer_creation_time.since_origin();
-
- // We expect the clock we're using to be monotonic, so we shouldn't get a
- // negative scheduling delay.
- DCHECK_GE(raster_scheduling_delay.InMicroseconds(), 0u);
- UMA_HISTOGRAM_RASTER_TIME_CUSTOM_MICROSECONDS(
- base::StringPrintf(
- "Renderer4.%s.RasterTaskSchedulingDelayNoAtRasterDecodes.All",
- client_name),
- raster_scheduling_delay);
- if (it->depends_on_hardware_accelerated_jpeg_candidates) {
- UMA_HISTOGRAM_RASTER_TIME_CUSTOM_MICROSECONDS(
- base::StringPrintf(
- "Renderer4.%s.RasterTaskSchedulingDelayNoAtRasterDecodes."
- "TilesWithJpegHwDecodeCandidates",
- client_name),
- raster_scheduling_delay);
- }
- if (it->depends_on_hardware_accelerated_webp_candidates) {
- UMA_HISTOGRAM_RASTER_TIME_CUSTOM_MICROSECONDS(
- base::StringPrintf(
- "Renderer4.%s.RasterTaskSchedulingDelayNoAtRasterDecodes."
- "TilesWithWebPHwDecodeCandidates",
- client_name),
- raster_scheduling_delay);
- }
- }
-
- if (enable_oop_rasterization_) {
- UMA_HISTOGRAM_RASTER_TIME_CUSTOM_MICROSECONDS(
- base::StringPrintf("Renderer4.%s.RasterTaskTotalDuration.Oop",
- client_name),
- raster_duration);
- } else {
- UMA_HISTOGRAM_RASTER_TIME_CUSTOM_MICROSECONDS(
- base::StringPrintf("Renderer4.%s.RasterTaskTotalDuration.Gpu",
- client_name),
- raster_duration);
- }
-
- it = pending_raster_queries_.erase(it);
- }
-
- return pending_raster_queries_.size() > 0u;
+ // TODO(crbug.com/1151490): Re-enable for OOPR.
+ return false;
}
} // namespace cc
diff --git a/chromium/cc/raster/gpu_raster_buffer_provider.h b/chromium/cc/raster/gpu_raster_buffer_provider.h
index 780f3304f5c..2980c4c3b5c 100644
--- a/chromium/cc/raster/gpu_raster_buffer_provider.h
+++ b/chromium/cc/raster/gpu_raster_buffer_provider.h
@@ -12,6 +12,7 @@
#include "base/time/time.h"
#include "cc/raster/raster_buffer_provider.h"
+#include "cc/raster/raster_query_queue.h"
#include "gpu/command_buffer/common/sync_token.h"
namespace gpu {
@@ -38,6 +39,7 @@ class CC_EXPORT GpuRasterBufferProvider : public RasterBufferProvider {
const gfx::Size& max_tile_size,
bool unpremultiply_and_dither_low_bit_depth_tiles,
bool enable_oop_rasterization,
+ RasterQueryQueue* const pending_raster_queries,
float raster_metric_probability = kRasterMetricProbability);
GpuRasterBufferProvider(const GpuRasterBufferProvider&) = delete;
~GpuRasterBufferProvider() override;
@@ -63,7 +65,6 @@ class CC_EXPORT GpuRasterBufferProvider : public RasterBufferProvider {
base::OnceClosure callback,
uint64_t pending_callback_id) const override;
void Shutdown() override;
- bool CheckRasterFinishedQueries() override;
gpu::SyncToken PlaybackOnWorkerThread(
gpu::Mailbox* mailbox,
@@ -138,26 +139,6 @@ class CC_EXPORT GpuRasterBufferProvider : public RasterBufferProvider {
base::TimeTicks creation_time_;
};
- struct PendingRasterQuery {
- // The id for querying the duration in executing the GPU side work.
- GLuint raster_duration_query_id = 0u;
-
- // The duration for executing the work on the raster worker thread.
- base::TimeDelta worker_raster_duration;
-
- // The id for querying the time at which we're about to start issuing raster
- // work to the driver.
- GLuint raster_start_query_id = 0u;
-
- // The time at which the raster buffer was created.
- base::TimeTicks raster_buffer_creation_time;
-
- // Whether the raster work depends on candidates for hardware accelerated
- // JPEG or WebP decodes.
- bool depends_on_hardware_accelerated_jpeg_candidates = false;
- bool depends_on_hardware_accelerated_webp_candidates = false;
- };
-
bool ShouldUnpremultiplyAndDitherResource(viz::ResourceFormat format) const;
gpu::SyncToken PlaybackOnWorkerThreadInternal(
gpu::Mailbox* mailbox,
@@ -176,21 +157,16 @@ class CC_EXPORT GpuRasterBufferProvider : public RasterBufferProvider {
const RasterSource::PlaybackSettings& playback_settings,
const GURL& url,
bool depends_on_at_raster_decodes,
- PendingRasterQuery* query);
+ RasterQuery* query);
viz::ContextProvider* const compositor_context_provider_;
viz::RasterContextProvider* const worker_context_provider_;
const bool use_gpu_memory_buffer_resources_;
const viz::ResourceFormat tile_format_;
const gfx::Size max_tile_size_;
- const bool unpremultiply_and_dither_low_bit_depth_tiles_;
const bool enable_oop_rasterization_;
- // Note that this lock should never be acquired while holding the raster
- // context lock.
- base::Lock pending_raster_queries_lock_;
- base::circular_deque<PendingRasterQuery> pending_raster_queries_
- GUARDED_BY(pending_raster_queries_lock_);
+ RasterQueryQueue* const pending_raster_queries_;
// Accessed with the worker context lock acquired.
std::mt19937 random_generator_;
diff --git a/chromium/cc/raster/one_copy_raster_buffer_provider.cc b/chromium/cc/raster/one_copy_raster_buffer_provider.cc
index 191a1aa759b..fd09b836dda 100644
--- a/chromium/cc/raster/one_copy_raster_buffer_provider.cc
+++ b/chromium/cc/raster/one_copy_raster_buffer_provider.cc
@@ -491,8 +491,4 @@ gpu::SyncToken OneCopyRasterBufferProvider::CopyOnWorkerThread(
return out_sync_token;
}
-bool OneCopyRasterBufferProvider::CheckRasterFinishedQueries() {
- return false;
-}
-
} // namespace cc
diff --git a/chromium/cc/raster/one_copy_raster_buffer_provider.h b/chromium/cc/raster/one_copy_raster_buffer_provider.h
index b42952904ba..a5f91e15081 100644
--- a/chromium/cc/raster/one_copy_raster_buffer_provider.h
+++ b/chromium/cc/raster/one_copy_raster_buffer_provider.h
@@ -66,7 +66,6 @@ class CC_EXPORT OneCopyRasterBufferProvider : public RasterBufferProvider {
base::OnceClosure callback,
uint64_t pending_callback_id) const override;
void Shutdown() override;
- bool CheckRasterFinishedQueries() override;
// Playback raster source and copy result into |resource|.
gpu::SyncToken PlaybackAndCopyOnWorkerThread(
diff --git a/chromium/cc/raster/playback_image_provider.cc b/chromium/cc/raster/playback_image_provider.cc
index 596166b2745..bb8dc8110c5 100644
--- a/chromium/cc/raster/playback_image_provider.cc
+++ b/chromium/cc/raster/playback_image_provider.cc
@@ -5,7 +5,6 @@
#include "cc/raster/playback_image_provider.h"
#include <utility>
-
#include "base/bind.h"
#include "cc/tiles/image_decode_cache.h"
#include "gpu/command_buffer/common/mailbox.h"
@@ -66,11 +65,13 @@ ImageProvider::ScopedResult PlaybackImageProvider::GetRasterContent(
} else if (settings_->raster_mode == RasterMode::kGpu) {
return ScopedResult(DecodedDrawImage(
paint_image.GetAcceleratedSkImage(), nullptr, SkSize::Make(0, 0),
- SkSize::Make(1.f, 1.f), draw_image.filter_quality()));
+ SkSize::Make(1.f, 1.f), draw_image.filter_quality(),
+ true /* is_budgeted */));
} else {
return ScopedResult(DecodedDrawImage(
paint_image.GetSwSkImage(), nullptr, SkSize::Make(0, 0),
- SkSize::Make(1.f, 1.f), draw_image.filter_quality()));
+ SkSize::Make(1.f, 1.f), draw_image.filter_quality(),
+ true /* is_budgeted */));
}
}
diff --git a/chromium/cc/raster/playback_image_provider_unittest.cc b/chromium/cc/raster/playback_image_provider_unittest.cc
index 71096682530..9001f7ebb63 100644
--- a/chromium/cc/raster/playback_image_provider_unittest.cc
+++ b/chromium/cc/raster/playback_image_provider_unittest.cc
@@ -25,7 +25,8 @@ sk_sp<SkImage> CreateRasterImage() {
DecodedDrawImage CreateDecode() {
return DecodedDrawImage(CreateRasterImage(), nullptr, SkSize::MakeEmpty(),
- SkSize::Make(1.0f, 1.0f), kMedium_SkFilterQuality);
+ SkSize::Make(1.0f, 1.0f), kMedium_SkFilterQuality,
+ true);
}
class MockDecodeCache : public StubDecodeCache {
diff --git a/chromium/cc/raster/raster_buffer_provider.cc b/chromium/cc/raster/raster_buffer_provider.cc
index 49b0f2689a4..465315f763c 100644
--- a/chromium/cc/raster/raster_buffer_provider.cc
+++ b/chromium/cc/raster/raster_buffer_provider.cc
@@ -38,6 +38,7 @@ bool IsSupportedPlaybackToMemoryFormat(viz::ResourceFormat format) {
case viz::RED_8:
case viz::LUMINANCE_F16:
case viz::R16_EXT:
+ case viz::RG16_EXT:
case viz::BGR_565:
case viz::RG_88:
case viz::RGBX_8888:
@@ -127,7 +128,7 @@ void RasterBufferProvider::PlaybackToMemory(
SkPaint paint;
paint.setDither(true);
paint.setBlendMode(SkBlendMode::kSrc);
- surface->draw(dst_canvas.get(), 0, 0, &paint);
+ surface->draw(dst_canvas.get(), 0, 0, SkSamplingOptions(), &paint);
return;
}
case viz::ETC1:
@@ -137,6 +138,7 @@ void RasterBufferProvider::PlaybackToMemory(
case viz::RED_8:
case viz::LUMINANCE_F16:
case viz::R16_EXT:
+ case viz::RG16_EXT:
case viz::BGR_565:
case viz::RG_88:
case viz::RGBX_8888:
diff --git a/chromium/cc/raster/raster_buffer_provider.h b/chromium/cc/raster/raster_buffer_provider.h
index 71632ec2fc2..d0da1460aff 100644
--- a/chromium/cc/raster/raster_buffer_provider.h
+++ b/chromium/cc/raster/raster_buffer_provider.h
@@ -90,14 +90,6 @@ class CC_EXPORT RasterBufferProvider {
// Shutdown for doing cleanup.
virtual void Shutdown() = 0;
-
- // Checks whether GPU side queries issued for previous raster work have been
- // finished. Note that this will acquire the worker context lock so it can be
- // used from any thread. But usage from the compositor thread should be
- // avoided to prevent contention with worker threads.
- // Returns true if there are pending queries that could not be completed in
- // this check.
- virtual bool CheckRasterFinishedQueries() = 0;
};
} // namespace cc
diff --git a/chromium/cc/raster/raster_buffer_provider_perftest.cc b/chromium/cc/raster/raster_buffer_provider_perftest.cc
index 8290aa08f19..f4d55dbf180 100644
--- a/chromium/cc/raster/raster_buffer_provider_perftest.cc
+++ b/chromium/cc/raster/raster_buffer_provider_perftest.cc
@@ -13,6 +13,7 @@
#include "cc/raster/gpu_raster_buffer_provider.h"
#include "cc/raster/one_copy_raster_buffer_provider.h"
#include "cc/raster/raster_buffer_provider.h"
+#include "cc/raster/raster_query_queue.h"
#include "cc/raster/synchronous_task_graph_runner.h"
#include "cc/raster/zero_copy_raster_buffer_provider.h"
#include "cc/resources/resource_pool.h"
@@ -354,6 +355,9 @@ class RasterBufferProviderPerfTest
public:
// Overridden from testing::Test:
void SetUp() override {
+ pending_raster_queries_ = std::make_unique<RasterQueryQueue>(
+ worker_context_provider_.get(), /*oop_rasterization_enabled=*/false);
+
switch (GetParam()) {
case RASTER_BUFFER_PROVIDER_TYPE_ZERO_COPY:
Create3dResourceProvider();
@@ -374,7 +378,8 @@ class RasterBufferProviderPerfTest
Create3dResourceProvider();
raster_buffer_provider_ = std::make_unique<GpuRasterBufferProvider>(
compositor_context_provider_.get(), worker_context_provider_.get(),
- false, viz::RGBA_8888, gfx::Size(), true, false);
+ false, viz::RGBA_8888, gfx::Size(), true, false,
+ pending_raster_queries_.get());
break;
case RASTER_BUFFER_PROVIDER_TYPE_BITMAP:
CreateSoftwareResourceProvider();
@@ -553,6 +558,7 @@ class RasterBufferProviderPerfTest
std::unique_ptr<TileTaskManager> tile_task_manager_;
std::unique_ptr<RasterBufferProvider> raster_buffer_provider_;
viz::TestGpuMemoryBufferManager gpu_memory_buffer_manager_;
+ std::unique_ptr<RasterQueryQueue> pending_raster_queries_;
};
TEST_P(RasterBufferProviderPerfTest, ScheduleTasks) {
diff --git a/chromium/cc/raster/raster_buffer_provider_unittest.cc b/chromium/cc/raster/raster_buffer_provider_unittest.cc
index a429683cdff..a19a04e98a9 100644
--- a/chromium/cc/raster/raster_buffer_provider_unittest.cc
+++ b/chromium/cc/raster/raster_buffer_provider_unittest.cc
@@ -35,6 +35,7 @@
#include "cc/raster/bitmap_raster_buffer_provider.h"
#include "cc/raster/gpu_raster_buffer_provider.h"
#include "cc/raster/one_copy_raster_buffer_provider.h"
+#include "cc/raster/raster_query_queue.h"
#include "cc/raster/synchronous_task_graph_runner.h"
#include "cc/raster/zero_copy_raster_buffer_provider.h"
#include "cc/resources/resource_pool.h"
@@ -232,13 +233,15 @@ class RasterBufferProviderTest
Create3dResourceProvider();
raster_buffer_provider_ = std::make_unique<GpuRasterBufferProvider>(
context_provider_.get(), worker_context_provider_.get(), false,
- viz::RGBA_8888, gfx::Size(), true, false, 1);
+ viz::RGBA_8888, gfx::Size(), true, false,
+ pending_raster_queries_.get(), 1);
break;
case RASTER_BUFFER_PROVIDER_TYPE_GPU_OOPR:
Create3dResourceProvider();
raster_buffer_provider_ = std::make_unique<GpuRasterBufferProvider>(
context_provider_.get(), worker_context_provider_.get(), false,
- viz::RGBA_8888, gfx::Size(), true, true, 1);
+ viz::RGBA_8888, gfx::Size(), true, true,
+ pending_raster_queries_.get(), 1);
break;
case RASTER_BUFFER_PROVIDER_TYPE_BITMAP:
CreateSoftwareResourceProvider();
@@ -381,7 +384,9 @@ class RasterBufferProviderTest
context_provider_ = viz::TestContextProvider::Create(std::move(gl_owned));
context_provider_->BindToCurrentThread();
+ bool oop_rasterization_enabled = false;
if (GetParam() == RASTER_BUFFER_PROVIDER_TYPE_GPU_OOPR) {
+ oop_rasterization_enabled = true;
auto worker_gl_owned = std::make_unique<viz::TestGLES2Interface>();
auto worker_support_owned = std::make_unique<viz::TestContextSupport>();
auto worker_ri_owned = std::make_unique<RasterImplementationForOOPR>(
@@ -398,6 +403,9 @@ class RasterBufferProviderTest
layer_tree_frame_sink_ = FakeLayerTreeFrameSink::Create3d();
resource_provider_ = std::make_unique<viz::ClientResourceProvider>();
+
+ pending_raster_queries_ = std::make_unique<RasterQueryQueue>(
+ worker_context_provider_.get(), oop_rasterization_enabled);
}
void CreateSoftwareResourceProvider() {
@@ -427,6 +435,7 @@ class RasterBufferProviderTest
std::vector<RasterTaskResult> completed_tasks_;
std::vector<ResourcePool::InUsePoolResource> resources_;
TaskGraph graph_;
+ std::unique_ptr<RasterQueryQueue> pending_raster_queries_;
};
TEST_P(RasterBufferProviderTest, Basic) {
@@ -655,7 +664,7 @@ TEST_P(RasterBufferProviderTest, MeasureGpuRasterDuration) {
histogram_tester.ExpectTotalCount(delay_histogram_jpeg_tiles, 0);
histogram_tester.ExpectTotalCount(delay_histogram_webp_tiles, 0);
bool has_pending_queries =
- raster_buffer_provider_->CheckRasterFinishedQueries();
+ pending_raster_queries_->CheckRasterFinishedQueries();
EXPECT_FALSE(has_pending_queries);
histogram_tester.ExpectTotalCount(duration_histogram, 9);
diff --git a/chromium/cc/raster/raster_query_queue.cc b/chromium/cc/raster/raster_query_queue.cc
new file mode 100644
index 00000000000..b77d3c69b97
--- /dev/null
+++ b/chromium/cc/raster/raster_query_queue.cc
@@ -0,0 +1,145 @@
+// 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.
+
+#include "cc/raster/raster_query_queue.h"
+
+#include <utility>
+
+#include "cc/base/histograms.h"
+#include "components/viz/common/gpu/raster_context_provider.h"
+#include "gpu/GLES2/gl2extchromium.h"
+#include "gpu/command_buffer/client/raster_interface.h"
+
+namespace cc {
+
+RasterQuery::RasterQuery() = default;
+
+RasterQuery::~RasterQuery() = default;
+
+RasterQueryQueue::RasterQueryQueue(
+ viz::RasterContextProvider* const worker_context_provider,
+ bool oop_rasterization_enabled)
+ : worker_context_provider_(worker_context_provider),
+ oop_rasterization_enabled_(oop_rasterization_enabled) {}
+
+RasterQueryQueue::~RasterQueryQueue() = default;
+
+void RasterQueryQueue::Append(RasterQuery raster_query) {
+ // It is important for this method to not be called with the raster context
+ // lock to avoid a deadlock in CheckRasterFinishedQueries, which acquired
+ // the raster context lock while holding this lock.
+ base::AutoLock hold(pending_raster_queries_lock_);
+ pending_raster_queries_.push_back(std::move(raster_query));
+}
+
+#define UMA_HISTOGRAM_RASTER_TIME_CUSTOM_MICROSECONDS(name, total_time) \
+ UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES( \
+ name, total_time, base::TimeDelta::FromMicroseconds(1), \
+ base::TimeDelta::FromMilliseconds(100), 100);
+
+bool RasterQueryQueue::CheckRasterFinishedQueries() {
+ base::AutoLock hold(pending_raster_queries_lock_);
+ if (pending_raster_queries_.empty())
+ return false;
+
+ viz::RasterContextProvider::ScopedRasterContextLock scoped_context(
+ worker_context_provider_);
+ auto* ri = scoped_context.RasterInterface();
+
+ auto it = pending_raster_queries_.begin();
+ while (it != pending_raster_queries_.end()) {
+ GLuint complete = 0;
+ ri->GetQueryObjectuivEXT(it->raster_duration_query_id,
+ GL_QUERY_RESULT_AVAILABLE_NO_FLUSH_CHROMIUM_EXT,
+ &complete);
+ if (!complete)
+ break;
+
+#if DCHECK_IS_ON()
+ if (it->raster_start_query_id) {
+ // We issued the GL_COMMANDS_ISSUED_TIMESTAMP_CHROMIUM query prior to the
+ // GL_COMMANDS_ISSUED_CHROMIUM query. Therefore, if the result of the
+ // latter is available, the result of the former should be too.
+ complete = 0;
+ ri->GetQueryObjectuivEXT(it->raster_start_query_id,
+ GL_QUERY_RESULT_AVAILABLE_NO_FLUSH_CHROMIUM_EXT,
+ &complete);
+ DCHECK(complete);
+ }
+#endif
+
+ GLuint gpu_raster_duration = 0u;
+ ri->GetQueryObjectuivEXT(it->raster_duration_query_id, GL_QUERY_RESULT_EXT,
+ &gpu_raster_duration);
+ ri->DeleteQueriesEXT(1, &it->raster_duration_query_id);
+
+ base::TimeDelta raster_duration =
+ it->worker_raster_duration +
+ base::TimeDelta::FromMicroseconds(gpu_raster_duration);
+
+ // It is safe to use the UMA macros here with runtime generated strings
+ // because the client name should be initialized once in the process, before
+ // recording any metrics here.
+ const char* client_name = GetClientNameForMetrics();
+
+ if (it->raster_start_query_id) {
+ GLuint64 gpu_raster_start_time = 0u;
+ ri->GetQueryObjectui64vEXT(it->raster_start_query_id, GL_QUERY_RESULT_EXT,
+ &gpu_raster_start_time);
+ ri->DeleteQueriesEXT(1, &it->raster_start_query_id);
+
+ // The base::checked_cast<int64_t> should not crash as long as the GPU
+ // process was not compromised: that's because the result of the query
+ // should have been generated using base::TimeDelta::InMicroseconds()
+ // there, so the result should fit in an int64_t.
+ base::TimeDelta raster_scheduling_delay =
+ base::TimeDelta::FromMicroseconds(
+ base::checked_cast<int64_t>(gpu_raster_start_time)) -
+ it->raster_buffer_creation_time.since_origin();
+
+ // We expect the clock we're using to be monotonic, so we shouldn't get a
+ // negative scheduling delay.
+ DCHECK_GE(raster_scheduling_delay.InMicroseconds(), 0u);
+ UMA_HISTOGRAM_RASTER_TIME_CUSTOM_MICROSECONDS(
+ base::StringPrintf(
+ "Renderer4.%s.RasterTaskSchedulingDelayNoAtRasterDecodes.All",
+ client_name),
+ raster_scheduling_delay);
+ if (it->depends_on_hardware_accelerated_jpeg_candidates) {
+ UMA_HISTOGRAM_RASTER_TIME_CUSTOM_MICROSECONDS(
+ base::StringPrintf(
+ "Renderer4.%s.RasterTaskSchedulingDelayNoAtRasterDecodes."
+ "TilesWithJpegHwDecodeCandidates",
+ client_name),
+ raster_scheduling_delay);
+ }
+ if (it->depends_on_hardware_accelerated_webp_candidates) {
+ UMA_HISTOGRAM_RASTER_TIME_CUSTOM_MICROSECONDS(
+ base::StringPrintf(
+ "Renderer4.%s.RasterTaskSchedulingDelayNoAtRasterDecodes."
+ "TilesWithWebPHwDecodeCandidates",
+ client_name),
+ raster_scheduling_delay);
+ }
+ }
+
+ if (oop_rasterization_enabled_) {
+ UMA_HISTOGRAM_RASTER_TIME_CUSTOM_MICROSECONDS(
+ base::StringPrintf("Renderer4.%s.RasterTaskTotalDuration.Oop",
+ client_name),
+ raster_duration);
+ } else {
+ UMA_HISTOGRAM_RASTER_TIME_CUSTOM_MICROSECONDS(
+ base::StringPrintf("Renderer4.%s.RasterTaskTotalDuration.Gpu",
+ client_name),
+ raster_duration);
+ }
+
+ it = pending_raster_queries_.erase(it);
+ }
+
+ return pending_raster_queries_.size() > 0u;
+}
+
+} // namespace cc
diff --git a/chromium/cc/raster/raster_query_queue.h b/chromium/cc/raster/raster_query_queue.h
new file mode 100644
index 00000000000..e81400a30e1
--- /dev/null
+++ b/chromium/cc/raster/raster_query_queue.h
@@ -0,0 +1,69 @@
+// 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_RASTER_RASTER_QUERY_QUEUE_H_
+#define CC_RASTER_RASTER_QUERY_QUEUE_H_
+
+#include "base/containers/circular_deque.h"
+#include "base/synchronization/lock.h"
+#include "base/thread_annotations.h"
+#include "base/time/time.h"
+#include "cc/cc_export.h"
+#include "third_party/khronos/GLES2/gl2.h"
+
+namespace viz {
+class RasterContextProvider;
+} // namespace viz
+
+namespace cc {
+
+struct CC_EXPORT RasterQuery {
+ RasterQuery();
+ ~RasterQuery();
+
+ // The id for querying the duration in executing the GPU side work.
+ GLuint raster_duration_query_id = 0u;
+
+ // The duration for executing the work on the raster worker thread.
+ base::TimeDelta worker_raster_duration;
+
+ // The id for querying the time at which we're about to start issuing raster
+ // work to the driver.
+ GLuint raster_start_query_id = 0u;
+
+ // The time at which the raster buffer was created.
+ base::TimeTicks raster_buffer_creation_time;
+
+ // Whether the raster work depends on candidates for hardware accelerated
+ // JPEG or WebP decodes.
+ bool depends_on_hardware_accelerated_jpeg_candidates = false;
+ bool depends_on_hardware_accelerated_webp_candidates = false;
+};
+
+class CC_EXPORT RasterQueryQueue {
+ public:
+ RasterQueryQueue(viz::RasterContextProvider* const worker_context_provider,
+ bool oop_rasterization_enabled);
+ virtual ~RasterQueryQueue();
+
+ // These functions should never be called with the raster context lock
+ // acquired.
+ void Append(RasterQuery raster_query);
+ // This function is only virtual for testing purposes.
+ virtual bool CheckRasterFinishedQueries();
+
+ private:
+ viz::RasterContextProvider* const worker_context_provider_;
+ const bool oop_rasterization_enabled_;
+
+ // Note that this lock should never be acquired while holding the raster
+ // context lock.
+ base::Lock pending_raster_queries_lock_;
+ base::circular_deque<RasterQuery> pending_raster_queries_
+ GUARDED_BY(pending_raster_queries_lock_);
+};
+
+} // namespace cc
+
+#endif // CC_RASTER_RASTER_QUERY_QUEUE_H_
diff --git a/chromium/cc/raster/raster_source.cc b/chromium/cc/raster/raster_source.cc
index 84f3f59ff68..f02d0e2cf7b 100644
--- a/chromium/cc/raster/raster_source.cc
+++ b/chromium/cc/raster/raster_source.cc
@@ -149,8 +149,9 @@ RasterSource::TakeDecodingModeMap() {
return display_list_->TakeDecodingModeMap();
}
-bool RasterSource::CoversRect(const gfx::Rect& layer_rect,
- const PictureLayerTilingClient& client) const {
+bool RasterSource::IntersectsRect(
+ const gfx::Rect& layer_rect,
+ const PictureLayerTilingClient& client) const {
if (size_.IsEmpty())
return false;
@@ -163,7 +164,7 @@ bool RasterSource::CoversRect(const gfx::Rect& layer_rect,
gfx::Rect bounded_rect = layer_rect;
bounded_rect.Intersect(gfx::Rect(size_));
- return recorded_viewport_.Contains(bounded_rect);
+ return recorded_viewport_.Intersects(bounded_rect);
}
gfx::Size RasterSource::GetSize() const {
diff --git a/chromium/cc/raster/raster_source.h b/chromium/cc/raster/raster_source.h
index 5b08b9cc445..99138adb46c 100644
--- a/chromium/cc/raster/raster_source.h
+++ b/chromium/cc/raster/raster_source.h
@@ -89,8 +89,8 @@ class CC_EXPORT RasterSource : public base::RefCountedThreadSafe<RasterSource> {
// Return true iff this raster source can raster the given rect in layer
// space.
- bool CoversRect(const gfx::Rect& layer_rect,
- const PictureLayerTilingClient& client) const;
+ bool IntersectsRect(const gfx::Rect& layer_rect,
+ const PictureLayerTilingClient& client) const;
// Returns true if this raster source has anything to rasterize.
bool HasRecordings() const;
diff --git a/chromium/cc/raster/task_graph_work_queue.cc b/chromium/cc/raster/task_graph_work_queue.cc
index a041d0ad42f..48575f7cdbe 100644
--- a/chromium/cc/raster/task_graph_work_queue.cc
+++ b/chromium/cc/raster/task_graph_work_queue.cc
@@ -12,7 +12,7 @@
#include <unordered_map>
#include <utility>
-#include "base/stl_util.h"
+#include "base/containers/contains.h"
#include "base/trace_event/trace_event.h"
namespace cc {
diff --git a/chromium/cc/raster/zero_copy_raster_buffer_provider.cc b/chromium/cc/raster/zero_copy_raster_buffer_provider.cc
index e8e5c214638..cca62553915 100644
--- a/chromium/cc/raster/zero_copy_raster_buffer_provider.cc
+++ b/chromium/cc/raster/zero_copy_raster_buffer_provider.cc
@@ -236,8 +236,4 @@ uint64_t ZeroCopyRasterBufferProvider::SetReadyToDrawCallback(
void ZeroCopyRasterBufferProvider::Shutdown() {}
-bool ZeroCopyRasterBufferProvider::CheckRasterFinishedQueries() {
- return false;
-}
-
} // namespace cc
diff --git a/chromium/cc/raster/zero_copy_raster_buffer_provider.h b/chromium/cc/raster/zero_copy_raster_buffer_provider.h
index 18ab5a9ce57..f2322a81f5e 100644
--- a/chromium/cc/raster/zero_copy_raster_buffer_provider.h
+++ b/chromium/cc/raster/zero_copy_raster_buffer_provider.h
@@ -57,7 +57,6 @@ class CC_EXPORT ZeroCopyRasterBufferProvider : public RasterBufferProvider {
base::OnceClosure callback,
uint64_t pending_callback_id) const override;
void Shutdown() override;
- bool CheckRasterFinishedQueries() override;
private:
std::unique_ptr<base::trace_event::ConvertableToTraceFormat> StateAsValue()
diff --git a/chromium/cc/resources/resource_pool.cc b/chromium/cc/resources/resource_pool.cc
index e854ca403b6..9b22734ca4a 100644
--- a/chromium/cc/resources/resource_pool.cc
+++ b/chromium/cc/resources/resource_pool.cc
@@ -8,7 +8,9 @@
#include <stdint.h>
#include <algorithm>
+#include <limits>
#include <memory>
+#include <string>
#include <utility>
#include "base/atomic_sequence_num.h"
@@ -301,7 +303,7 @@ void ResourcePool::OnResourceReleased(size_t unique_id,
return;
}
- resource->set_resource_id(0);
+ resource->set_resource_id(viz::kInvalidResourceId);
if (context_provider_)
resource->gpu_backing()->returned_sync_token = sync_token;
DidFinishUsingResource(std::move(*busy_it));
@@ -320,7 +322,7 @@ bool ResourcePool::PrepareForExport(const InUsePoolResource& in_use_resource) {
// This can happen if we failed to allocate a GpuMemoryBuffer. Avoid
// sending an invalid resource to the parent in that case, and avoid
// caching/reusing the resource.
- resource->set_resource_id(0);
+ resource->set_resource_id(viz::kInvalidResourceId);
resource->mark_avoid_reuse();
return false;
}
diff --git a/chromium/cc/resources/resource_pool.h b/chromium/cc/resources/resource_pool.h
index 7d30ea14ed3..c275aa0d738 100644
--- a/chromium/cc/resources/resource_pool.h
+++ b/chromium/cc/resources/resource_pool.h
@@ -10,6 +10,7 @@
#include <map>
#include <memory>
+#include <utility>
#include "base/containers/circular_deque.h"
#include "base/memory/memory_pressure_listener.h"
@@ -336,7 +337,7 @@ class CC_EXPORT ResourcePool : public base::trace_event::MemoryDumpProvider {
bool avoid_reuse_ = false;
// An id used to name the backing for transfer to the display compositor.
- viz::ResourceId resource_id_ = 0;
+ viz::ResourceId resource_id_ = viz::kInvalidResourceId;
// The backing for gpu resources. Initially null for resources given
// out by ResourcePool, to be filled in by the client. Is destroyed on the
diff --git a/chromium/cc/resources/ui_resource_bitmap.cc b/chromium/cc/resources/ui_resource_bitmap.cc
index 974706def78..f63f5e38d7f 100644
--- a/chromium/cc/resources/ui_resource_bitmap.cc
+++ b/chromium/cc/resources/ui_resource_bitmap.cc
@@ -11,6 +11,7 @@
#include "base/check_op.h"
#include "base/notreached.h"
#include "base/numerics/checked_math.h"
+#include "third_party/skia/include/core/SkImage.h"
#include "third_party/skia/include/core/SkImageInfo.h"
#include "third_party/skia/include/core/SkMallocPixelRef.h"
#include "third_party/skia/include/core/SkPixelRef.h"
@@ -55,7 +56,7 @@ void UIResourceBitmap::DrawToCanvas(SkCanvas* canvas, SkPaint* paint) {
SkBitmap bitmap;
bitmap.setInfo(info_, pixel_ref_.get()->rowBytes());
bitmap.setPixelRef(pixel_ref_, 0, 0);
- canvas->drawBitmap(bitmap, 0, 0, paint);
+ canvas->drawImage(bitmap.asImage(), 0, 0, SkSamplingOptions(), paint);
canvas->flush();
}
diff --git a/chromium/cc/scheduler/begin_frame_tracker.cc b/chromium/cc/scheduler/begin_frame_tracker.cc
index 0480a2c24b2..2b8b164650d 100644
--- a/chromium/cc/scheduler/begin_frame_tracker.cc
+++ b/chromium/cc/scheduler/begin_frame_tracker.cc
@@ -18,9 +18,11 @@ BeginFrameTracker::~BeginFrameTracker() = default;
void BeginFrameTracker::Start(const viz::BeginFrameArgs& new_args) {
// Trace the frame time being passed between BeginFrameTrackers.
- TRACE_EVENT_FLOW_STEP0(
- TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler.frames"), "BeginFrameArgs",
- new_args.frame_time.since_origin().InMicroseconds(), location_string_);
+ TRACE_EVENT_WITH_FLOW1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler.frames"),
+ "BeginFrameArgs",
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
+ new_args.frame_time.since_origin().InMicroseconds(),
+ "location", location_string_);
// Trace this specific begin frame tracker Start/Finish times.
TRACE_EVENT_COPY_ASYNC_BEGIN2(
diff --git a/chromium/cc/scheduler/scheduler.cc b/chromium/cc/scheduler/scheduler.cc
index 8f51ef9b467..bacb2272f72 100644
--- a/chromium/cc/scheduler/scheduler.cc
+++ b/chromium/cc/scheduler/scheduler.cc
@@ -163,7 +163,6 @@ void Scheduler::DidSubmitCompositorFrame(uint32_t frame_token,
void Scheduler::DidReceiveCompositorFrameAck() {
DCHECK_GT(state_machine_.pending_submit_frames(), 0);
- compositor_timing_history_->DidReceiveCompositorFrameAck();
state_machine_.DidReceiveCompositorFrameAck();
ProcessScheduledActions();
}
@@ -225,7 +224,6 @@ void Scheduler::DidCreateAndInitializeLayerTreeFrameSink() {
DCHECK(!observing_begin_frame_source_);
DCHECK(begin_impl_frame_deadline_task_.IsCancelled());
state_machine_.DidCreateAndInitializeLayerTreeFrameSink();
- compositor_timing_history_->DidCreateAndInitializeLayerTreeFrameSink();
UpdateCompositorTimingHistoryRecordingEnabled();
ProcessScheduledActions();
}
@@ -356,9 +354,9 @@ bool Scheduler::OnBeginFrameDerivedImpl(const viz::BeginFrameArgs& args) {
}
// Trace this begin frame time through the Chrome stack
- TRACE_EVENT_FLOW_BEGIN0(
- TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler.frames"),
- "viz::BeginFrameArgs", args.frame_time.since_origin().InMicroseconds());
+ TRACE_EVENT_WITH_FLOW0(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler.frames"),
+ "viz::BeginFrameArgs", TRACE_EVENT_FLAG_FLOW_OUT,
+ args.frame_time.since_origin().InMicroseconds());
if (settings_.using_synchronous_renderer_compositor) {
BeginImplFrameSynchronous(args);
@@ -600,10 +598,11 @@ void Scheduler::FinishImplFrame() {
// ack for any pending begin frame if we are going idle after this. This
// ensures that the acks are sent in order.
if (!state_machine_.did_submit_in_last_frame()) {
+ bool has_pending_tree = state_machine_.has_pending_tree();
bool is_waiting_on_main = state_machine_.begin_main_frame_state() !=
SchedulerStateMachine::BeginMainFrameState::IDLE;
SendDidNotProduceFrame(begin_impl_frame_tracker_.Current(),
- is_waiting_on_main
+ is_waiting_on_main || has_pending_tree
? FrameSkippedReason::kWaitingOnMain
: FrameSkippedReason::kNoDamage);
}
diff --git a/chromium/cc/scheduler/scheduler_unittest.cc b/chromium/cc/scheduler/scheduler_unittest.cc
index b6755ae97e4..c7647b28a06 100644
--- a/chromium/cc/scheduler/scheduler_unittest.cc
+++ b/chromium/cc/scheduler/scheduler_unittest.cc
@@ -3896,7 +3896,9 @@ TEST_F(SchedulerTest, BeginFrameAckForFinishedImplFrame) {
has_damage = false;
EXPECT_EQ(viz::BeginFrameAck(args, has_damage),
client_->last_begin_frame_ack());
- EXPECT_EQ(FrameSkippedReason::kNoDamage,
+ // The pending tree is not activated yet so the frame is still waiting on
+ // Main thread update
+ EXPECT_EQ(FrameSkippedReason::kWaitingOnMain,
client_->last_frame_skipped_reason());
}
diff --git a/chromium/cc/tiles/gpu_image_decode_cache.cc b/chromium/cc/tiles/gpu_image_decode_cache.cc
index 016a7c4ba31..37a6489c1c0 100644
--- a/chromium/cc/tiles/gpu_image_decode_cache.cc
+++ b/chromium/cc/tiles/gpu_image_decode_cache.cc
@@ -105,31 +105,6 @@ SkFilterQuality CalculateDesiredFilterQuality(const DrawImage& draw_image) {
return std::min(kMedium_SkFilterQuality, draw_image.filter_quality());
}
-// Calculate the mip level to upload-scale the image to before uploading. We use
-// mip levels rather than exact scales to increase re-use of scaled images.
-int CalculateUploadScaleMipLevel(const DrawImage& draw_image,
- bool enable_clipped_image_scaling = false) {
- // Images which are being clipped will have color-bleeding if scaled.
- // TODO(ericrk): Investigate uploading clipped images to handle this case and
- // provide further optimization. crbug.com/620899
- const bool is_clipped = draw_image.src_rect() !=
- SkIRect::MakeWH(draw_image.paint_image().width(),
- draw_image.paint_image().height());
- if (is_clipped && !enable_clipped_image_scaling)
- return 0;
-
- gfx::Size base_size(draw_image.paint_image().width(),
- draw_image.paint_image().height());
- // Ceil our scaled size so that the mip map generated is guaranteed to be
- // larger. Take the abs of the scale, as mipmap functions don't handle
- // (and aren't impacted by) negative image dimensions.
- gfx::Size scaled_size =
- gfx::ScaleToCeiledSize(base_size, std::abs(draw_image.scale().width()),
- std::abs(draw_image.scale().height()));
-
- return MipMapUtil::GetLevelForSize(base_size, scaled_size);
-}
-
// Calculates the scale factor which can be used to scale an image to a given
// mip level.
SkSize CalculateScaleFactorForMipLevel(const DrawImage& draw_image,
@@ -326,7 +301,12 @@ bool DrawAndScaleImage(
: supported_size;
decode_info = info.makeWH(decode_size.width(), decode_size.height());
}
- SkFilterQuality filter_quality = CalculateDesiredFilterQuality(draw_image);
+
+ const SkFilterQuality filter_quality =
+ CalculateDesiredFilterQuality(draw_image);
+ const SkSamplingOptions sampling(filter_quality,
+ SkSamplingOptions::kMedium_asMipmapLinear);
+
bool decode_to_f16_using_n32_intermediate =
decode_info.colorType() == kRGBA_F16_SkColorType &&
!ImageDecodeCacheUtils::CanResizeF16Image(filter_quality);
@@ -383,12 +363,12 @@ bool DrawAndScaleImage(
v_info_scaled.minRowBytes());
const bool all_planes_scaled_successfully =
- unscaled_yuva_pixmaps.plane(0).scalePixels(*pixmap_y, filter_quality) &&
- unscaled_yuva_pixmaps.plane(1).scalePixels(*pixmap_u, filter_quality) &&
- unscaled_yuva_pixmaps.plane(2).scalePixels(*pixmap_v, filter_quality);
+ unscaled_yuva_pixmaps.plane(0).scalePixels(*pixmap_y, sampling) &&
+ unscaled_yuva_pixmaps.plane(1).scalePixels(*pixmap_u, sampling) &&
+ unscaled_yuva_pixmaps.plane(2).scalePixels(*pixmap_v, sampling);
return all_planes_scaled_successfully;
}
- return decode_pixmap.scalePixels(pixmap, filter_quality);
+ return decode_pixmap.scalePixels(pixmap, sampling);
}
// Takes ownership of the backing texture of an SkImage. This allows us to
@@ -473,57 +453,14 @@ sk_sp<SkImage> MakeTextureImage(viz::RasterContextProvider* context,
return uploaded_image;
}
-size_t GetUploadedTextureSizeFromSkImage(const sk_sp<SkImage>& plane,
- const GrMipMapped mipped) {
- const size_t plane_size = GrDirectContext::ComputeImageSize(plane, mipped);
- return plane_size;
-}
-
-// Preserves the division of channels into planes and channel order within
-// planes but removes chroma subsampling. If there is no such config this will
-// return SkYUVAInfo::PlanarConfig::kUnknown.
-SkYUVAInfo::PlanarConfig ConvertPlanarConfigTo444(
- SkYUVAInfo::PlanarConfig config) {
- switch (config) {
- case SkYUVAInfo::PlanarConfig::kY_U_V_444:
- case SkYUVAInfo::PlanarConfig::kY_U_V_422:
- case SkYUVAInfo::PlanarConfig::kY_U_V_420:
- case SkYUVAInfo::PlanarConfig::kY_U_V_440:
- case SkYUVAInfo::PlanarConfig::kY_U_V_411:
- case SkYUVAInfo::PlanarConfig::kY_U_V_410:
- return SkYUVAInfo::PlanarConfig::kY_U_V_444;
-
- case SkYUVAInfo::PlanarConfig::kYUV_444:
- return SkYUVAInfo::PlanarConfig::kYUV_444;
- case SkYUVAInfo::PlanarConfig::kUYV_444:
- return SkYUVAInfo::PlanarConfig::kUYV_444;
- case SkYUVAInfo::PlanarConfig::kYUVA_4444:
- return SkYUVAInfo::PlanarConfig::kYUVA_4444;
- case SkYUVAInfo::PlanarConfig::kUYVA_4444:
- return SkYUVAInfo::PlanarConfig::kUYVA_4444;
-
- // There are planar configs with no 444[4] equivalent, none of which are
- // used by GpuImageDecoderCache currently. For example, there is kY_UV_420
- // but no kY_UV_444. Skia could easily have add the equivalents if required.
- default:
- NOTREACHED();
- return SkYUVAInfo::PlanarConfig::kUnknown;
- }
-}
-
} // namespace
-// static
-GpuImageDecodeCache::InUseCacheKey
-GpuImageDecodeCache::InUseCacheKey::FromDrawImage(const DrawImage& draw_image) {
- return InUseCacheKey(draw_image);
-}
-
// Extract the information to uniquely identify a DrawImage for the purposes of
// the |in_use_cache_|.
-GpuImageDecodeCache::InUseCacheKey::InUseCacheKey(const DrawImage& draw_image)
+GpuImageDecodeCache::InUseCacheKey::InUseCacheKey(const DrawImage& draw_image,
+ int mip_level)
: frame_key(draw_image.frame_key()),
- upload_scale_mip_level(CalculateUploadScaleMipLevel(draw_image)),
+ upload_scale_mip_level(mip_level),
filter_quality(CalculateDesiredFilterQuality(draw_image)),
target_color_space(draw_image.target_color_space()) {}
@@ -906,10 +843,7 @@ GpuImageDecodeCache::ImageData::ImageData(
bool is_bitmap_backed,
bool can_do_hardware_accelerated_decode,
bool do_hardware_accelerated_decode,
- bool is_yuv_format,
- SkYUVColorSpace yuv_cs,
- SkYUVAPixmapInfo::PlanarConfig yuv_config,
- SkYUVAPixmapInfo::DataType yuv_dt)
+ base::Optional<SkYUVAPixmapInfo> yuva_info)
: paint_image_id(paint_image_id),
mode(mode),
size(size),
@@ -918,17 +852,14 @@ GpuImageDecodeCache::ImageData::ImageData(
upload_scale_mip_level(upload_scale_mip_level),
needs_mips(needs_mips),
is_bitmap_backed(is_bitmap_backed),
- is_yuv(is_yuv_format),
+ yuva_pixmap_info(yuva_info),
decode(is_bitmap_backed,
can_do_hardware_accelerated_decode,
do_hardware_accelerated_decode) {
- // Only fill out the base::Optional |yuv_color_space| if doing YUV decoding.
- // Otherwise it was filled out with a default "identity" value by the decoder.
- if (is_yuv) {
- DCHECK_LE(yuv_cs, SkYUVColorSpace::kLastEnum_SkYUVColorSpace);
- yuv_color_space = yuv_cs;
- yuv_planar_config = yuv_config;
- yuv_data_type = yuv_dt;
+ if (yuva_pixmap_info.has_value()) {
+ // This is the only plane config supported currently.
+ DCHECK_EQ(yuva_pixmap_info->yuvaInfo().planeConfig(),
+ SkYUVAInfo::PlaneConfig::kY_U_V);
}
}
@@ -955,7 +886,7 @@ bool GpuImageDecodeCache::ImageData::HasUploadedData() const {
if (upload.image()) {
// TODO(915968): Be smarter about being able to re-upload planes
// selectively if only some get deleted from under us.
- DCHECK(!is_yuv || upload.has_yuv_planes());
+ DCHECK(!yuva_pixmap_info.has_value() || upload.has_yuv_planes());
return true;
}
return false;
@@ -1054,7 +985,7 @@ GpuImageDecodeCache::GpuImageDecodeCache(
TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"GpuImageDecodeCache::DarkModeFilter", "dark_mode_filter",
- dark_mode_filter_);
+ static_cast<void*>(dark_mode_filter_));
}
GpuImageDecodeCache::~GpuImageDecodeCache() {
@@ -1099,7 +1030,7 @@ ImageDecodeCache::TaskResult GpuImageDecodeCache::GetTaskForImageAndRefInternal(
}
base::AutoLock lock(lock_);
- const InUseCacheKey cache_key = InUseCacheKey::FromDrawImage(draw_image);
+ const InUseCacheKey cache_key = InUseCacheKeyFromDrawImage(draw_image);
ImageData* image_data = GetImageDataForDrawImage(draw_image, cache_key);
scoped_refptr<ImageData> new_data;
if (!image_data) {
@@ -1186,7 +1117,7 @@ void GpuImageDecodeCache::UnrefImage(const DrawImage& draw_image) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"GpuImageDecodeCache::UnrefImage");
base::AutoLock lock(lock_);
- UnrefImageInternal(draw_image, InUseCacheKey::FromDrawImage(draw_image));
+ UnrefImageInternal(draw_image, InUseCacheKeyFromDrawImage(draw_image));
}
bool GpuImageDecodeCache::UseCacheForDrawImage(
@@ -1211,7 +1142,7 @@ DecodedDrawImage GpuImageDecodeCache::GetDecodedImageForDraw(
return DecodedDrawImage();
base::AutoLock lock(lock_);
- const InUseCacheKey cache_key = InUseCacheKey::FromDrawImage(draw_image);
+ const InUseCacheKey cache_key = InUseCacheKeyFromDrawImage(draw_image);
ImageData* image_data = GetImageDataForDrawImage(draw_image, cache_key);
if (!image_data) {
// We didn't find the image, create a new entry.
@@ -1255,7 +1186,8 @@ DecodedDrawImage GpuImageDecodeCache::GetDecodedImageForDraw(
draw_image, image_data->upload_scale_mip_level);
DecodedDrawImage decoded_draw_image(
id, std::move(dark_mode_color_filter), SkSize(), scale_factor,
- CalculateDesiredFilterQuality(draw_image), image_data->needs_mips);
+ CalculateDesiredFilterQuality(draw_image), image_data->needs_mips,
+ image_data->is_budgeted);
return decoded_draw_image;
} else {
DCHECK(!use_transfer_cache_);
@@ -1268,7 +1200,8 @@ DecodedDrawImage GpuImageDecodeCache::GetDecodedImageForDraw(
draw_image, image_data->upload_scale_mip_level);
DecodedDrawImage decoded_draw_image(
std::move(image), std::move(dark_mode_color_filter), SkSize(),
- scale_factor, CalculateDesiredFilterQuality(draw_image));
+ scale_factor, CalculateDesiredFilterQuality(draw_image),
+ image_data->is_budgeted);
return decoded_draw_image;
}
}
@@ -1291,7 +1224,7 @@ void GpuImageDecodeCache::DrawWithImageFinished(
return;
base::AutoLock lock(lock_);
- UnrefImageInternal(draw_image, InUseCacheKey::FromDrawImage(draw_image));
+ UnrefImageInternal(draw_image, InUseCacheKeyFromDrawImage(draw_image));
// We are mid-draw and holding the context lock, ensure we clean up any
// textures (especially at-raster), which may have just been marked for
@@ -1440,7 +1373,7 @@ void GpuImageDecodeCache::MemoryDumpYUVImage(
const std::string& dump_base_name,
size_t locked_size) const {
using base::trace_event::MemoryAllocatorDump;
- DCHECK(image_data->is_yuv);
+ DCHECK(image_data->yuva_pixmap_info.has_value());
DCHECK(image_data->upload.has_yuv_planes());
struct PlaneMemoryDumpInfo {
@@ -1448,18 +1381,13 @@ void GpuImageDecodeCache::MemoryDumpYUVImage(
GrGLuint gl_id;
};
std::vector<PlaneMemoryDumpInfo> plane_dump_infos;
- const GrMipMapped mipped =
- image_data->needs_mips ? GrMipMapped::kYes : GrMipMapped::kNo;
// TODO(crbug.com/910276): Also include alpha plane if applicable.
- plane_dump_infos.push_back(
- {GetUploadedTextureSizeFromSkImage(image_data->upload.y_image(), mipped),
- image_data->upload.gl_y_id()});
- plane_dump_infos.push_back(
- {GetUploadedTextureSizeFromSkImage(image_data->upload.u_image(), mipped),
- image_data->upload.gl_u_id()});
- plane_dump_infos.push_back(
- {GetUploadedTextureSizeFromSkImage(image_data->upload.v_image(), mipped),
- image_data->upload.gl_v_id()});
+ plane_dump_infos.push_back({image_data->upload.y_image()->textureSize(),
+ image_data->upload.gl_y_id()});
+ plane_dump_infos.push_back({image_data->upload.u_image()->textureSize(),
+ image_data->upload.gl_u_id()});
+ plane_dump_infos.push_back({image_data->upload.v_image()->textureSize(),
+ image_data->upload.gl_v_id()});
for (size_t i = 0u; i < plane_dump_infos.size(); ++i) {
auto plane_dump_info = plane_dump_infos.at(i);
@@ -1523,7 +1451,7 @@ bool GpuImageDecodeCache::OnMemoryDump(
auto* context_support = context_->ContextSupport();
// If the discardable system has deleted this out from under us, log a
// size of 0 to match software discardable.
- if (image_data->is_yuv &&
+ if (image_data->yuva_pixmap_info.has_value() &&
context_support->ThreadsafeDiscardableTextureIsDeletedForTracing(
image_data->upload.gl_y_id()) &&
context_support->ThreadsafeDiscardableTextureIsDeletedForTracing(
@@ -1542,7 +1470,7 @@ bool GpuImageDecodeCache::OnMemoryDump(
reinterpret_cast<uintptr_t>(this), image_id);
size_t locked_size =
image_data->upload.is_locked() ? discardable_size : 0u;
- if (image_data->is_yuv) {
+ if (image_data->yuva_pixmap_info.has_value()) {
MemoryDumpYUVImage(pmd, image_data, gpu_dump_base_name, locked_size);
} else {
AddTextureDump(pmd, gpu_dump_base_name, discardable_size,
@@ -1560,7 +1488,7 @@ void GpuImageDecodeCache::DecodeImageInTask(const DrawImage& draw_image,
"GpuImageDecodeCache::DecodeImage");
base::AutoLock lock(lock_);
ImageData* image_data = GetImageDataForDrawImage(
- draw_image, InUseCacheKey::FromDrawImage(draw_image));
+ draw_image, InUseCacheKeyFromDrawImage(draw_image));
DCHECK(image_data);
DCHECK(image_data->is_budgeted) << "Must budget an image for pre-decoding";
DecodeImageAndGenerateDarkModeFilterIfNecessary(draw_image, image_data,
@@ -1580,7 +1508,7 @@ void GpuImageDecodeCache::UploadImageInTask(const DrawImage& draw_image) {
gr_context_access.emplace(context_);
base::AutoLock lock(lock_);
- auto cache_key = InUseCacheKey::FromDrawImage(draw_image);
+ auto cache_key = InUseCacheKeyFromDrawImage(draw_image);
ImageData* image_data = GetImageDataForDrawImage(draw_image, cache_key);
DCHECK(image_data);
DCHECK(image_data->is_budgeted) << "Must budget an image for pre-decoding";
@@ -1597,7 +1525,7 @@ void GpuImageDecodeCache::OnImageDecodeTaskCompleted(
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"GpuImageDecodeCache::OnImageDecodeTaskCompleted");
base::AutoLock lock(lock_);
- auto cache_key = InUseCacheKey::FromDrawImage(draw_image);
+ auto cache_key = InUseCacheKeyFromDrawImage(draw_image);
// Decode task is complete, remove our reference to it.
ImageData* image_data = GetImageDataForDrawImage(draw_image, cache_key);
DCHECK(image_data);
@@ -1621,7 +1549,7 @@ void GpuImageDecodeCache::OnImageUploadTaskCompleted(
"GpuImageDecodeCache::OnImageUploadTaskCompleted");
base::AutoLock lock(lock_);
// Upload task is complete, remove our reference to it.
- InUseCacheKey cache_key = InUseCacheKey::FromDrawImage(draw_image);
+ InUseCacheKey cache_key = InUseCacheKeyFromDrawImage(draw_image);
ImageData* image_data = GetImageDataForDrawImage(draw_image, cache_key);
DCHECK(image_data);
DCHECK(image_data->upload.task);
@@ -1634,6 +1562,37 @@ void GpuImageDecodeCache::OnImageUploadTaskCompleted(
UnrefImageInternal(draw_image, cache_key);
}
+int GpuImageDecodeCache::CalculateUploadScaleMipLevel(
+ const DrawImage& draw_image) const {
+ // Images which are being clipped will have color-bleeding if scaled.
+ // TODO(ericrk): Investigate uploading clipped images to handle this case and
+ // provide further optimization. crbug.com/620899
+ if (!enable_clipped_image_scaling_) {
+ const bool is_clipped = draw_image.src_rect() !=
+ SkIRect::MakeWH(draw_image.paint_image().width(),
+ draw_image.paint_image().height());
+ if (is_clipped)
+ return 0;
+ }
+
+ gfx::Size base_size(draw_image.paint_image().width(),
+ draw_image.paint_image().height());
+ // Ceil our scaled size so that the mip map generated is guaranteed to be
+ // larger. Take the abs of the scale, as mipmap functions don't handle
+ // (and aren't impacted by) negative image dimensions.
+ gfx::Size scaled_size =
+ gfx::ScaleToCeiledSize(base_size, std::abs(draw_image.scale().width()),
+ std::abs(draw_image.scale().height()));
+
+ return MipMapUtil::GetLevelForSize(base_size, scaled_size);
+}
+
+GpuImageDecodeCache::InUseCacheKey
+GpuImageDecodeCache::InUseCacheKeyFromDrawImage(
+ const DrawImage& draw_image) const {
+ return InUseCacheKey(draw_image, CalculateUploadScaleMipLevel(draw_image));
+}
+
// Checks if an image decode needs a decode task and returns it.
scoped_refptr<TileTask> GpuImageDecodeCache::GetImageDecodeTaskAndRef(
const DrawImage& draw_image,
@@ -1643,7 +1602,7 @@ scoped_refptr<TileTask> GpuImageDecodeCache::GetImageDecodeTaskAndRef(
"GpuImageDecodeCache::GetImageDecodeTaskAndRef");
lock_.AssertAcquired();
- auto cache_key = InUseCacheKey::FromDrawImage(draw_image);
+ auto cache_key = InUseCacheKeyFromDrawImage(draw_image);
// This ref is kept alive while an upload task may need this decode. We
// release this ref in UploadTaskCompleted.
@@ -1930,7 +1889,7 @@ bool GpuImageDecodeCache::NeedsDarkModeFilter(const DrawImage& draw_image,
DCHECK(dark_mode_filter_);
// TODO(prashant.n): RSDM - Add support for YUV decoded data.
- if (image_data->is_yuv)
+ if (image_data->yuva_pixmap_info.has_value())
return false;
// Dark mode filter is already generated and cached.
@@ -1986,7 +1945,7 @@ void GpuImageDecodeCache::DecodeImageIfNecessary(
if (image_data->is_bitmap_backed) {
DCHECK(!draw_image.paint_image().IsLazyGenerated());
- if (image_data->is_yuv) {
+ if (image_data->yuva_pixmap_info.has_value()) {
DLOG(ERROR) << "YUV + Bitmap is unknown and unimplemented!";
NOTREACHED();
} else {
@@ -2028,15 +1987,15 @@ void GpuImageDecodeCache::DecodeImageIfNecessary(
// Set |pixmap| to the desired colorspace to decode into.
pixmap.setColorSpace(color_space);
- if (image_data->is_yuv) {
+ if (image_data->yuva_pixmap_info.has_value()) {
DVLOG(3) << "GpuImageDecodeCache wants to do YUV decoding/rendering";
SkPixmap pixmap_y;
SkPixmap pixmap_u;
SkPixmap pixmap_v;
- if (!DrawAndScaleImage(draw_image, &pixmap, generator_client_id_,
- image_data->is_yuv, yuva_supported_data_types_,
- image_data->yuv_data_type.value(), &pixmap_y,
- &pixmap_u, &pixmap_v)) {
+ if (!DrawAndScaleImage(draw_image, &pixmap, generator_client_id_, true,
+ yuva_supported_data_types_,
+ image_data->yuva_pixmap_info->dataType(),
+ &pixmap_y, &pixmap_u, &pixmap_v)) {
DLOG(ERROR) << "DrawAndScaleImage failed.";
backing_memory->Unlock();
backing_memory.reset();
@@ -2046,8 +2005,8 @@ void GpuImageDecodeCache::DecodeImageIfNecessary(
image_v = SkImage::MakeFromRaster(pixmap_v, release_proc, nullptr);
}
} else { // RGBX decoding is the default path.
- if (!DrawAndScaleImage(draw_image, &pixmap, generator_client_id_,
- image_data->is_yuv, yuva_supported_data_types_)) {
+ if (!DrawAndScaleImage(draw_image, &pixmap, generator_client_id_, false,
+ yuva_supported_data_types_)) {
DLOG(ERROR) << "DrawAndScaleImage failed.";
backing_memory->Unlock();
backing_memory.reset();
@@ -2058,8 +2017,8 @@ void GpuImageDecodeCache::DecodeImageIfNecessary(
}
if (image_data->decode.data()) {
- // An at-raster task decoded this before us. Ingore our decode.
- if (image_data->is_yuv) {
+ // An at-raster task decoded this before us. Ignore our decode.
+ if (image_data->yuva_pixmap_info.has_value()) {
DCHECK(image_data->decode.y_image());
DCHECK(image_data->decode.u_image());
DCHECK(image_data->decode.v_image());
@@ -2079,7 +2038,7 @@ void GpuImageDecodeCache::DecodeImageIfNecessary(
return;
}
- if (image_data->is_yuv) {
+ if (image_data->yuva_pixmap_info.has_value()) {
image_data->decode.SetLockedData(
std::move(backing_memory), std::move(image_y), std::move(image_u),
std::move(image_v), task_type == TaskType::kOutOfRaster);
@@ -2216,19 +2175,19 @@ void GpuImageDecodeCache::UploadImageIfNecessary(const DrawImage& draw_image,
}
// Non-hardware-accelerated path.
- if (image_data->is_yuv) {
- DCHECK(image_data->yuv_color_space);
- SkPixmap y_pixmap;
- SkPixmap u_pixmap;
- SkPixmap v_pixmap;
- if (!image_data->decode.y_image()->peekPixels(&y_pixmap) ||
- !image_data->decode.u_image()->peekPixels(&u_pixmap) ||
- !image_data->decode.v_image()->peekPixels(&v_pixmap)) {
+ if (image_data->yuva_pixmap_info.has_value()) {
+ SkPixmap yuv_pixmaps[3];
+ if (!image_data->decode.y_image()->peekPixels(&yuv_pixmaps[0]) ||
+ !image_data->decode.u_image()->peekPixels(&yuv_pixmaps[1]) ||
+ !image_data->decode.v_image()->peekPixels(&yuv_pixmaps[2])) {
return;
}
ClientImageTransferCacheEntry image_entry(
- &y_pixmap, &u_pixmap, &v_pixmap, decoded_target_colorspace.get(),
- image_data->yuv_color_space.value(), image_data->needs_mips);
+ yuv_pixmaps, image_data->yuva_pixmap_info->yuvaInfo().planeConfig(),
+ image_data->yuva_pixmap_info->yuvaInfo().subsampling(),
+ decoded_target_colorspace.get(),
+ image_data->yuva_pixmap_info->yuvaInfo().yuvColorSpace(),
+ image_data->needs_mips);
InsertTransferCacheEntry(image_entry, image_data);
} else {
SkPixmap pixmap;
@@ -2254,8 +2213,7 @@ void GpuImageDecodeCache::UploadImageIfNecessary(const DrawImage& draw_image,
GrMipMapped image_needs_mips =
image_data->needs_mips ? GrMipMapped::kYes : GrMipMapped::kNo;
- if (image_data->is_yuv) {
- DCHECK(image_data->yuv_color_space.has_value());
+ if (image_data->yuva_pixmap_info.has_value()) {
// Grab a reference to our decoded image. For the kCpu path, we will use
// this directly as our "uploaded" data.
sk_sp<SkImage> uploaded_y_image = image_data->decode.y_image();
@@ -2282,8 +2240,9 @@ void GpuImageDecodeCache::UploadImageIfNecessary(const DrawImage& draw_image,
uploaded_image = CreateImageFromYUVATexturesInternal(
uploaded_y_image.get(), uploaded_u_image.get(),
uploaded_v_image.get(), image_width, image_height,
- image_data->yuv_planar_config.value(),
- image_data->yuv_color_space.value(), color_space,
+ image_data->yuva_pixmap_info->yuvaInfo().planeConfig(),
+ image_data->yuva_pixmap_info->yuvaInfo().subsampling(),
+ image_data->yuva_pixmap_info->yuvaInfo().yuvColorSpace(), color_space,
decoded_target_colorspace);
}
@@ -2319,7 +2278,8 @@ void GpuImageDecodeCache::UploadImageIfNecessary(const DrawImage& draw_image,
uploaded_v_image = TakeOwnershipOfSkImageBacking(
context_->GrContext(), std::move(uploaded_v_image));
- image_data->upload.SetImage(std::move(uploaded_image), image_data->is_yuv);
+ image_data->upload.SetImage(std::move(uploaded_image),
+ image_data->yuva_pixmap_info.has_value());
image_data->upload.SetYuvImage(std::move(uploaded_y_image),
std::move(uploaded_u_image),
std::move(uploaded_v_image));
@@ -2478,36 +2438,33 @@ GpuImageDecodeCache::CreateImageData(const DrawImage& draw_image,
mode != DecodedDataMode::kCpu &&
!image_larger_than_max_texture;
- SkYUVAInfo::PlanarConfig yuv_planar_config =
- SkYUVAInfo::PlanarConfig::kUnknown;
- // TODO(crbug.com/910276): Change after alpha support.
+ base::Optional<SkYUVAPixmapInfo> optional_yuva_pixmap_info;
if (is_yuv) {
+ DCHECK(yuva_pixmap_info.isValid());
if (upload_scale_mip_level > 0) {
// Scaled decode. We always promote to 4:4:4 when scaling YUV to avoid
- // blurriness. See comment in DrawAndScaleImage() for details.
- const base::CheckedNumeric<size_t> y_plane_size =
- image_info.makeColorType(yuva_pixmap_info.planeInfo(0).colorType())
- .computeMinByteSize();
- DCHECK(!SkImageInfo::ByteSizeOverflowed(y_plane_size.ValueOrDie()));
- yuv_planar_config =
- ConvertPlanarConfigTo444(yuva_pixmap_info.yuvaInfo().planarConfig());
- DCHECK_NE(yuv_planar_config, SkYUVAInfo::PlanarConfig::kUnknown);
- data_size = (3 * y_plane_size).ValueOrDie();
+ // blurriness. See comment in DrawAndScaleImage() for details 0
+ SkYUVAInfo yuva_info = yuva_pixmap_info.yuvaInfo().makeSubsampling(
+ SkYUVAInfo::Subsampling::k444);
+ size_t row_bytes[SkYUVAInfo::kMaxPlanes] = {};
+ for (int i = 0; i < yuva_info.numPlanes(); ++i) {
+ row_bytes[i] = yuva_pixmap_info.rowBytes(0);
+ }
+ optional_yuva_pixmap_info =
+ SkYUVAPixmapInfo(yuva_info, yuva_pixmap_info.dataType(), row_bytes);
} else {
// Original size decode.
- yuv_planar_config = yuva_pixmap_info.yuvaInfo().planarConfig();
- data_size = yuva_pixmap_info.computeTotalBytes();
- DCHECK(!SkImageInfo::ByteSizeOverflowed(data_size));
+ optional_yuva_pixmap_info = yuva_pixmap_info;
}
+ data_size = optional_yuva_pixmap_info->computeTotalBytes();
+ DCHECK(!SkImageInfo::ByteSizeOverflowed(data_size));
}
-
return base::WrapRefCounted(new ImageData(
draw_image.paint_image().stable_id(), mode, data_size,
draw_image.target_color_space(),
CalculateDesiredFilterQuality(draw_image), upload_scale_mip_level,
needs_mips, is_bitmap_backed, can_do_hardware_accelerated_decode,
- do_hardware_accelerated_decode, is_yuv, yuva_pixmap_info.yuvColorSpace(),
- yuv_planar_config, yuva_pixmap_info.dataType()));
+ do_hardware_accelerated_decode, optional_yuva_pixmap_info));
}
void GpuImageDecodeCache::WillAddCacheEntry(const DrawImage& draw_image) {
@@ -2564,7 +2521,7 @@ void GpuImageDecodeCache::DeleteImage(ImageData* image_data) {
if (image_data->HasUploadedData()) {
DCHECK(!image_data->upload.is_locked());
if (image_data->mode == DecodedDataMode::kGpu) {
- if (image_data->is_yuv) {
+ if (image_data->yuva_pixmap_info.has_value()) {
images_pending_deletion_.push_back(image_data->upload.y_image());
images_pending_deletion_.push_back(image_data->upload.u_image());
images_pending_deletion_.push_back(image_data->upload.v_image());
@@ -2582,7 +2539,7 @@ void GpuImageDecodeCache::DeleteImage(ImageData* image_data) {
void GpuImageDecodeCache::UnlockImage(ImageData* image_data) {
DCHECK(image_data->HasUploadedData());
if (image_data->mode == DecodedDataMode::kGpu) {
- if (image_data->is_yuv) {
+ if (image_data->yuva_pixmap_info.has_value()) {
images_pending_unlock_.push_back(image_data->upload.y_image().get());
images_pending_unlock_.push_back(image_data->upload.u_image().get());
images_pending_unlock_.push_back(image_data->upload.v_image().get());
@@ -2600,7 +2557,7 @@ void GpuImageDecodeCache::UnlockImage(ImageData* image_data) {
// it is guarenteed to have no-refs.
auto unmipped_image = image_data->upload.take_unmipped_image();
if (unmipped_image) {
- if (image_data->is_yuv) {
+ if (image_data->yuva_pixmap_info.has_value()) {
auto unmipped_y_image = image_data->upload.take_unmipped_y_image();
auto unmipped_u_image = image_data->upload.take_unmipped_u_image();
auto unmipped_v_image = image_data->upload.take_unmipped_v_image();
@@ -2736,7 +2693,7 @@ bool GpuImageDecodeCache::TryLockImage(HaveContextLock have_context_lock,
// If |have_context_lock|, we can immediately lock the image and send
// the lock command to the GPU process.
// TODO(crbug.com/914622): Add Chrome GL extension to upload texture array.
- if (data->is_yuv &&
+ if (data->yuva_pixmap_info.has_value() &&
ri->LockDiscardableTextureCHROMIUM(data->upload.gl_y_id()) &&
ri->LockDiscardableTextureCHROMIUM(data->upload.gl_u_id()) &&
ri->LockDiscardableTextureCHROMIUM(data->upload.gl_v_id())) {
@@ -2744,7 +2701,7 @@ bool GpuImageDecodeCache::TryLockImage(HaveContextLock have_context_lock,
DCHECK(data->mode == DecodedDataMode::kGpu);
data->upload.OnLock();
return true;
- } else if (!(data->is_yuv) &&
+ } else if (!data->yuva_pixmap_info.has_value() &&
ri->LockDiscardableTextureCHROMIUM(data->upload.gl_id())) {
DCHECK(!use_transfer_cache_);
DCHECK(data->mode == DecodedDataMode::kGpu);
@@ -2762,7 +2719,7 @@ bool GpuImageDecodeCache::TryLockImage(HaveContextLock have_context_lock,
// UploadImageIfNecessary, which is guaranteed to run before the texture
// is used.
auto* context_support = context_->ContextSupport();
- if (data->is_yuv &&
+ if (data->yuva_pixmap_info.has_value() &&
context_support->ThreadSafeShallowLockDiscardableTexture(
data->upload.gl_y_id()) &&
context_support->ThreadSafeShallowLockDiscardableTexture(
@@ -2776,7 +2733,7 @@ bool GpuImageDecodeCache::TryLockImage(HaveContextLock have_context_lock,
images_pending_complete_lock_.push_back(data->upload.u_image().get());
images_pending_complete_lock_.push_back(data->upload.v_image().get());
return true;
- } else if (!(data->is_yuv) &&
+ } else if (!data->yuva_pixmap_info.has_value() &&
context_support->ThreadSafeShallowLockDiscardableTexture(
data->upload.gl_id())) {
DCHECK(!use_transfer_cache_);
@@ -2827,9 +2784,8 @@ GpuImageDecodeCache::ImageData* GpuImageDecodeCache::GetImageDataForDrawImage(
bool GpuImageDecodeCache::IsCompatible(const ImageData* image_data,
const DrawImage& draw_image) const {
bool is_scaled = image_data->upload_scale_mip_level != 0;
- bool scale_is_compatible =
- CalculateUploadScaleMipLevel(draw_image, enable_clipped_image_scaling_) >=
- image_data->upload_scale_mip_level;
+ bool scale_is_compatible = CalculateUploadScaleMipLevel(draw_image) >=
+ image_data->upload_scale_mip_level;
bool quality_is_compatible =
CalculateDesiredFilterQuality(draw_image) <= image_data->quality;
bool color_is_compatible =
@@ -2868,7 +2824,7 @@ bool GpuImageDecodeCache::DiscardableIsLockedForTesting(
bool GpuImageDecodeCache::IsInInUseCacheForTesting(
const DrawImage& image) const {
- auto found = in_use_cache_.find(InUseCacheKey::FromDrawImage(image));
+ auto found = in_use_cache_.find(InUseCacheKeyFromDrawImage(image));
return found != in_use_cache_.end();
}
@@ -2884,7 +2840,7 @@ sk_sp<SkImage> GpuImageDecodeCache::GetSWImageDecodeForTesting(
auto found = persistent_cache_.Peek(image.frame_key());
DCHECK(found != persistent_cache_.end());
ImageData* image_data = found->second.get();
- DCHECK(!image_data->is_yuv);
+ DCHECK(!image_data->yuva_pixmap_info.has_value());
return image_data->decode.ImageForTesting();
}
@@ -2896,8 +2852,8 @@ sk_sp<SkImage> GpuImageDecodeCache::GetUploadedPlaneForTesting(
YUVIndex index) {
base::AutoLock lock(lock_);
ImageData* image_data = GetImageDataForDrawImage(
- draw_image, InUseCacheKey::FromDrawImage(draw_image));
- if (!image_data->is_yuv)
+ draw_image, InUseCacheKeyFromDrawImage(draw_image));
+ if (!image_data->yuva_pixmap_info.has_value())
return nullptr;
switch (index) {
case YUVIndex::kY:
@@ -2915,7 +2871,7 @@ size_t GpuImageDecodeCache::GetDarkModeImageCacheSizeForTesting(
const DrawImage& draw_image) {
base::AutoLock lock(lock_);
ImageData* image_data = GetImageDataForDrawImage(
- draw_image, InUseCacheKey::FromDrawImage(draw_image));
+ draw_image, InUseCacheKeyFromDrawImage(draw_image));
return image_data ? image_data->decode.dark_mode_color_filter_cache.size()
: 0u;
}
@@ -2924,7 +2880,7 @@ bool GpuImageDecodeCache::NeedsDarkModeFilterForTesting(
const DrawImage& draw_image) {
base::AutoLock lock(lock_);
ImageData* image_data = GetImageDataForDrawImage(
- draw_image, InUseCacheKey::FromDrawImage(draw_image));
+ draw_image, InUseCacheKeyFromDrawImage(draw_image));
return NeedsDarkModeFilter(draw_image, image_data);
}
@@ -2995,15 +2951,16 @@ sk_sp<SkImage> GpuImageDecodeCache::CreateImageFromYUVATexturesInternal(
const SkImage* uploaded_v_image,
const size_t image_width,
const size_t image_height,
- const SkYUVAInfo::PlanarConfig yuva_planar_config,
+ const SkYUVAInfo::PlaneConfig yuva_plane_config,
+ const SkYUVAInfo::Subsampling yuva_subsampling,
const SkYUVColorSpace yuv_color_space,
sk_sp<SkColorSpace> target_color_space,
sk_sp<SkColorSpace> decoded_color_space) const {
DCHECK(uploaded_y_image);
DCHECK(uploaded_u_image);
DCHECK(uploaded_v_image);
- SkYUVAInfo yuva_info({image_width, image_height}, yuva_planar_config,
- yuv_color_space);
+ SkYUVAInfo yuva_info({image_width, image_height}, yuva_plane_config,
+ yuva_subsampling, yuv_color_space);
GrBackendTexture yuv_textures[3]{};
yuv_textures[0] = uploaded_y_image->getBackendTexture(false);
yuv_textures[1] = uploaded_u_image->getBackendTexture(false);
@@ -3047,7 +3004,7 @@ void GpuImageDecodeCache::UpdateMipsIfNeeded(const DrawImage& draw_image,
image_data->mode != DecodedDataMode::kGpu)
return;
- if (image_data->is_yuv) {
+ if (image_data->yuva_pixmap_info.has_value()) {
// Need to generate mips. Take a reference on the planes we're about to
// delete, delaying deletion.
// TODO(crbug.com/910276): Change after alpha support.
@@ -3106,14 +3063,14 @@ void GpuImageDecodeCache::UpdateMipsIfNeeded(const DrawImage& draw_image,
NeedsColorSpaceAdjustedForUpload(draw_image)
? ColorSpaceForImageUpload(draw_image)
: ColorSpaceForImageDecode(draw_image, image_data->mode);
- DCHECK(image_data->yuv_color_space.has_value());
sk_sp<SkImage> yuv_image_with_mips_owned =
CreateImageFromYUVATexturesInternal(
image_y_with_mips_owned.get(), image_u_with_mips_owned.get(),
image_v_with_mips_owned.get(), width, height,
- image_data->yuv_planar_config.value(),
- image_data->yuv_color_space.value(), color_space,
- upload_color_space);
+ image_data->yuva_pixmap_info->yuvaInfo().planeConfig(),
+ image_data->yuva_pixmap_info->yuvaInfo().subsampling(),
+ image_data->yuva_pixmap_info->yuvaInfo().yuvColorSpace(),
+ color_space, upload_color_space);
// In case of lost context
if (!yuv_image_with_mips_owned) {
DLOG(WARNING) << "TODO(crbug.com/740737): Context was lost. Early out.";
diff --git a/chromium/cc/tiles/gpu_image_decode_cache.h b/chromium/cc/tiles/gpu_image_decode_cache.h
index ec28a20dd9a..3acfc4dc7e2 100644
--- a/chromium/cc/tiles/gpu_image_decode_cache.h
+++ b/chromium/cc/tiles/gpu_image_decode_cache.h
@@ -520,10 +520,7 @@ class CC_EXPORT GpuImageDecodeCache
bool is_bitmap_backed,
bool can_do_hardware_accelerated_decode,
bool do_hardware_accelerated_decode,
- bool is_yuv_format,
- SkYUVColorSpace yuv_cs,
- SkYUVAInfo::PlanarConfig yuv_config,
- SkYUVAPixmapInfo::DataType yuv_dt);
+ base::Optional<SkYUVAPixmapInfo> yuva_pixmap_info);
bool IsGpuOrTransferCache() const;
bool HasUploadedData() const;
@@ -537,11 +534,8 @@ class CC_EXPORT GpuImageDecodeCache
int upload_scale_mip_level;
bool needs_mips = false;
bool is_bitmap_backed;
- bool is_yuv;
bool is_budgeted = false;
- base::Optional<SkYUVColorSpace> yuv_color_space;
- base::Optional<SkYUVAInfo::PlanarConfig> yuv_planar_config;
- base::Optional<SkYUVAPixmapInfo::DataType> yuv_data_type;
+ base::Optional<SkYUVAPixmapInfo> yuva_pixmap_info;
// If true, this image is no longer in our |persistent_cache_| and will be
// deleted as soon as its ref count reaches zero.
@@ -571,12 +565,12 @@ class CC_EXPORT GpuImageDecodeCache
// the |in_use_cache_|.
struct InUseCacheKeyHash;
struct InUseCacheKey {
- static InUseCacheKey FromDrawImage(const DrawImage& draw_image);
+ InUseCacheKey(const DrawImage& draw_image, int mip_level);
+
bool operator==(const InUseCacheKey& other) const;
private:
friend struct GpuImageDecodeCache::InUseCacheKeyHash;
- explicit InUseCacheKey(const DrawImage& draw_image);
PaintImage::FrameKey frame_key;
int upload_scale_mip_level;
@@ -591,6 +585,13 @@ class CC_EXPORT GpuImageDecodeCache
// functions also require the |context_| lock. These are indicated by
// additional comments.
+ // Calculate the mip level to upload-scale the image to before uploading. We
+ // use mip levels rather than exact scales to increase re-use of scaled
+ // images.
+ int CalculateUploadScaleMipLevel(const DrawImage& draw_image) const;
+
+ InUseCacheKey InUseCacheKeyFromDrawImage(const DrawImage& draw_image) const;
+
// Similar to GetTaskForImageAndRef, but gets the dependent decode task
// rather than the upload task, if necessary.
scoped_refptr<TileTask> GetImageDecodeTaskAndRef(
@@ -642,7 +643,8 @@ class CC_EXPORT GpuImageDecodeCache
const SkImage* uploaded_v_image,
const size_t image_width,
const size_t image_height,
- const SkYUVAInfo::PlanarConfig yuva_planar_config,
+ const SkYUVAInfo::PlaneConfig yuva_plane_config,
+ const SkYUVAInfo::Subsampling yuva_subsampling,
const SkYUVColorSpace yuva_color_space,
sk_sp<SkColorSpace> target_color_space,
sk_sp<SkColorSpace> decoded_color_space) const;
diff --git a/chromium/cc/tiles/gpu_image_decode_cache_perftest.cc b/chromium/cc/tiles/gpu_image_decode_cache_perftest.cc
index 20725f8c49a..a2c6d6833ab 100644
--- a/chromium/cc/tiles/gpu_image_decode_cache_perftest.cc
+++ b/chromium/cc/tiles/gpu_image_decode_cache_perftest.cc
@@ -154,11 +154,11 @@ TEST_P(GpuImageDecodeCachePerfTestNoSw, DecodeWithMips) {
DecodedDrawImage decoded_image = cache_->GetDecodedImageForDraw(image);
if (GetParam() == TestMode::kGpu) {
- SkPaint paint;
- paint.setFilterQuality(kMedium_SkFilterQuality);
- surface->getCanvas()->drawImageRect(decoded_image.image().get(),
- SkRect::MakeWH(1024, 2048),
- SkRect::MakeWH(614, 1229), &paint);
+ SkSamplingOptions sampling(SkFilterMode::kLinear, SkMipmapMode::kLinear);
+ surface->getCanvas()->drawImageRect(
+ decoded_image.image().get(), SkRect::MakeWH(1024, 2048),
+ SkRect::MakeWH(614, 1229), sampling, nullptr,
+ SkCanvas::kStrict_SrcRectConstraint);
surface->flushAndSubmit();
}
diff --git a/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc b/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc
index 79ebeeeade8..bbdcfc15716 100644
--- a/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc
+++ b/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc
@@ -583,7 +583,7 @@ class GpuImageDecodeCacheTest
DecodedDrawImage new_draw_image(
image_entry->image(), draw_image.dark_mode_color_filter(),
draw_image.src_rect_offset(), draw_image.scale_adjustment(),
- draw_image.filter_quality());
+ draw_image.filter_quality(), draw_image.is_budgeted());
return new_draw_image;
}
@@ -1149,6 +1149,7 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDraw) {
EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
EXPECT_TRUE(decoded_draw_image.image());
EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
+ EXPECT_TRUE(decoded_draw_image.is_budgeted());
EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
cache->DrawWithImageFinished(draw_image, decoded_draw_image);
@@ -1194,6 +1195,7 @@ TEST_P(GpuImageDecodeCacheTest, GetHdrDecodedImageForDrawToHdr) {
EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
EXPECT_TRUE(decoded_draw_image.image());
EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
+ EXPECT_TRUE(decoded_draw_image.is_budgeted());
EXPECT_EQ(decoded_draw_image.image()->colorType(), kRGBA_F16_SkColorType);
auto cs = gfx::ColorSpace(*decoded_draw_image.image()->colorSpace());
@@ -1244,6 +1246,7 @@ TEST_P(GpuImageDecodeCacheTest, GetHdrDecodedImageForDrawToSdr) {
EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
EXPECT_TRUE(decoded_draw_image.image());
EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
+ EXPECT_TRUE(decoded_draw_image.is_budgeted());
EXPECT_NE(decoded_draw_image.image()->colorType(), kRGBA_F16_SkColorType);
EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
@@ -1271,6 +1274,7 @@ TEST_P(GpuImageDecodeCacheTest, GetLargeDecodedImageForDraw) {
DecodedDrawImage decoded_draw_image =
EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
EXPECT_TRUE(decoded_draw_image.image());
+ EXPECT_TRUE(decoded_draw_image.is_budgeted());
EXPECT_FALSE(decoded_draw_image.image()->isTextureBacked());
EXPECT_TRUE_IF_NOT_USING_TRANSFER_CACHE(
cache->DiscardableIsLockedForTesting(draw_image));
@@ -1299,7 +1303,9 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawAtRasterDecode) {
DecodedDrawImage decoded_draw_image =
EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
EXPECT_TRUE(decoded_draw_image.image());
+ EXPECT_FALSE(decoded_draw_image.is_budgeted());
EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
+ EXPECT_FALSE(decoded_draw_image.is_budgeted());
EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
cache->DrawWithImageFinished(draw_image, decoded_draw_image);
@@ -1338,6 +1344,7 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawLargerScale) {
viz::ContextProvider::ScopedContextLock context_lock(context_provider());
DecodedDrawImage decoded_draw_image =
EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
+ EXPECT_TRUE(decoded_draw_image.is_budgeted());
EXPECT_TRUE(decoded_draw_image.image());
EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
@@ -1345,6 +1352,7 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawLargerScale) {
DecodedDrawImage larger_decoded_draw_image =
EnsureImageBacked(cache->GetDecodedImageForDraw(larger_draw_image));
EXPECT_TRUE(larger_decoded_draw_image.image());
+ EXPECT_TRUE(larger_decoded_draw_image.is_budgeted());
EXPECT_TRUE(larger_decoded_draw_image.image()->isTextureBacked());
EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
@@ -1384,6 +1392,7 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawHigherQuality) {
DecodedDrawImage decoded_draw_image =
EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
EXPECT_TRUE(decoded_draw_image.image());
+ EXPECT_TRUE(decoded_draw_image.is_budgeted());
EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
@@ -1421,6 +1430,7 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawNegative) {
DecodedDrawImage decoded_draw_image =
EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
EXPECT_TRUE(decoded_draw_image.image());
+ EXPECT_TRUE(decoded_draw_image.is_budgeted());
const int expected_width =
image.width() * std::abs(draw_image.scale().width());
const int expected_height =
@@ -1455,6 +1465,7 @@ TEST_P(GpuImageDecodeCacheTest, GetLargeScaledDecodedImageForDraw) {
DecodedDrawImage decoded_draw_image =
EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
EXPECT_TRUE(decoded_draw_image.image());
+ EXPECT_TRUE(decoded_draw_image.is_budgeted());
// The mip level scale should never go below 0 in any dimension.
EXPECT_EQ(GetLargeImageSize().width(), decoded_draw_image.image()->width());
EXPECT_EQ(GetLargeImageSize().height(), decoded_draw_image.image()->height());
@@ -1490,6 +1501,7 @@ TEST_P(GpuImageDecodeCacheTest, AtRasterUsedDirectlyIfSpaceAllows) {
EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
EXPECT_TRUE(decoded_draw_image.image());
EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
+ EXPECT_FALSE(decoded_draw_image.is_budgeted());
EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
cache->DrawWithImageFinished(draw_image, decoded_draw_image);
@@ -1522,10 +1534,12 @@ TEST_P(GpuImageDecodeCacheTest,
EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
EXPECT_TRUE(decoded_draw_image.image());
EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
+ EXPECT_FALSE(decoded_draw_image.is_budgeted());
EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
DecodedDrawImage another_decoded_draw_image =
EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
+ EXPECT_FALSE(another_decoded_draw_image.is_budgeted());
EXPECT_EQ(decoded_draw_image.image()->uniqueID(),
another_decoded_draw_image.image()->uniqueID());
@@ -1551,6 +1565,7 @@ TEST_P(GpuImageDecodeCacheTest,
DecodedDrawImage decoded_draw_image =
EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
EXPECT_TRUE(decoded_draw_image.image());
+ EXPECT_FALSE(decoded_draw_image.is_budgeted());
EXPECT_FALSE(decoded_draw_image.image()->isTextureBacked());
EXPECT_TRUE_IF_NOT_USING_TRANSFER_CACHE(
cache->DiscardableIsLockedForTesting(draw_image));
@@ -1561,6 +1576,7 @@ TEST_P(GpuImageDecodeCacheTest,
DecodedDrawImage second_decoded_draw_image =
EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
EXPECT_TRUE(second_decoded_draw_image.image());
+ EXPECT_FALSE(decoded_draw_image.is_budgeted());
EXPECT_FALSE(second_decoded_draw_image.image()->isTextureBacked());
EXPECT_TRUE_IF_NOT_USING_TRANSFER_CACHE(
cache->DiscardableIsLockedForTesting(draw_image));
@@ -2244,6 +2260,7 @@ TEST_P(GpuImageDecodeCacheTest, AlreadyBudgetedImagesAreNotAtRaster) {
viz::ContextProvider::ScopedContextLock context_lock(context_provider());
DecodedDrawImage decoded_draw_image =
EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
+ EXPECT_TRUE(decoded_draw_image.is_budgeted());
cache->DrawWithImageFinished(draw_image, decoded_draw_image);
cache->UnrefImage(draw_image);
cache->UnrefImage(draw_image);
@@ -2267,6 +2284,7 @@ TEST_P(GpuImageDecodeCacheTest, ImageBudgetingByCount) {
DecodedDrawImage decoded_draw_image =
EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
EXPECT_TRUE(decoded_draw_image.image());
+ EXPECT_TRUE(decoded_draw_image.is_budgeted());
// Try another image, it shouldn't be budgeted and should be at-raster.
PaintImage second_paint_image =
@@ -2282,6 +2300,7 @@ TEST_P(GpuImageDecodeCacheTest, ImageBudgetingByCount) {
DecodedDrawImage second_decoded_draw_image =
EnsureImageBacked(cache->GetDecodedImageForDraw(second_draw_image));
EXPECT_TRUE(second_decoded_draw_image.image());
+ EXPECT_FALSE(second_decoded_draw_image.is_budgeted());
cache->DrawWithImageFinished(draw_image, decoded_draw_image);
cache->DrawWithImageFinished(second_draw_image, second_decoded_draw_image);
@@ -2307,6 +2326,7 @@ TEST_P(GpuImageDecodeCacheTest, ImageBudgetingBySize) {
DecodedDrawImage decoded_draw_image =
EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
EXPECT_TRUE(decoded_draw_image.image());
+ EXPECT_TRUE(decoded_draw_image.is_budgeted());
// Try another image, it shouldn't be budgeted and should be at-raster.
PaintImage test_paint_image = CreatePaintImageInternal(test_image_size);
@@ -2321,6 +2341,7 @@ TEST_P(GpuImageDecodeCacheTest, ImageBudgetingBySize) {
DecodedDrawImage second_decoded_draw_image =
EnsureImageBacked(cache->GetDecodedImageForDraw(second_draw_image));
EXPECT_TRUE(second_decoded_draw_image.image());
+ EXPECT_FALSE(second_decoded_draw_image.is_budgeted());
cache->DrawWithImageFinished(draw_image, decoded_draw_image);
cache->DrawWithImageFinished(second_draw_image, second_decoded_draw_image);
@@ -2438,6 +2459,7 @@ TEST_P(GpuImageDecodeCacheTest, NonLazyImageUploadNoScale) {
DecodedDrawImage decoded_draw_image =
EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
EXPECT_TRUE(decoded_draw_image.image());
+ EXPECT_TRUE(decoded_draw_image.is_budgeted());
cache->DrawWithImageFinished(draw_image, decoded_draw_image);
// For non-lazy images used at the original scale, no cpu component should be
// cached
@@ -2500,6 +2522,7 @@ TEST_P(GpuImageDecodeCacheTest, NonLazyImageLargeImageColorConverted) {
DecodedDrawImage decoded_draw_image =
EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
EXPECT_TRUE(decoded_draw_image.image());
+ EXPECT_TRUE(decoded_draw_image.is_budgeted());
cache->DrawWithImageFinished(draw_image, decoded_draw_image);
// For non-lazy images color converted during scaling, cpu component should be
// cached.
@@ -2525,6 +2548,7 @@ TEST_P(GpuImageDecodeCacheTest, NonLazyImageUploadDownscaled) {
DecodedDrawImage decoded_draw_image =
EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
EXPECT_TRUE(decoded_draw_image.image());
+ EXPECT_TRUE(decoded_draw_image.is_budgeted());
cache->DrawWithImageFinished(draw_image, decoded_draw_image);
}
@@ -3385,6 +3409,7 @@ TEST_P(GpuImageDecodeCacheTest, GetBorderlineLargeDecodedImageForDraw) {
EnsureImageBacked(cache->GetDecodedImageForDraw(draw_image));
EXPECT_TRUE(decoded_draw_image.image());
EXPECT_TRUE(decoded_draw_image.image()->isTextureBacked());
+ EXPECT_TRUE(decoded_draw_image.is_budgeted());
EXPECT_FALSE(cache->DiscardableIsLockedForTesting(draw_image));
cache->DrawWithImageFinished(draw_image, decoded_draw_image);
diff --git a/chromium/cc/tiles/image_decode_cache_utils.cc b/chromium/cc/tiles/image_decode_cache_utils.cc
index fb0e1bc04ca..8dbd6b32d45 100644
--- a/chromium/cc/tiles/image_decode_cache_utils.cc
+++ b/chromium/cc/tiles/image_decode_cache_utils.cc
@@ -41,7 +41,10 @@ bool ImageDecodeCacheUtils::ScaleToHalfFloatPixmapUsingN32Intermediate(
n32_pixmap.info().makeWH(scaled_pixmap->width(), scaled_pixmap->height());
if (!n32_resized_bitmap.tryAllocPixels(n32_resize_info))
return false;
- if (!n32_pixmap.scalePixels(n32_resized_bitmap.pixmap(), filter_quality))
+ if (!n32_pixmap.scalePixels(
+ n32_resized_bitmap.pixmap(),
+ SkSamplingOptions(filter_quality,
+ SkSamplingOptions::kMedium_asMipmapLinear)))
return false;
// Convert back to f16 and return
return n32_resized_bitmap.readPixels(*scaled_pixmap, 0, 0);
diff --git a/chromium/cc/tiles/picture_layer_tiling.cc b/chromium/cc/tiles/picture_layer_tiling.cc
index 25c0e84378a..d0c83d660b7 100644
--- a/chromium/cc/tiles/picture_layer_tiling.cc
+++ b/chromium/cc/tiles/picture_layer_tiling.cc
@@ -83,7 +83,7 @@ Tile* PictureLayerTiling::CreateTile(const Tile::CreateInfo& info) {
TileMapKey key(i, j);
DCHECK(tiles_.find(key) == tiles_.end());
- if (!raster_source_->CoversRect(info.enclosing_layer_rect, *client_))
+ if (!raster_source_->IntersectsRect(info.enclosing_layer_rect, *client_))
return nullptr;
all_tiles_done_ = false;
@@ -355,8 +355,8 @@ bool PictureLayerTiling::ShouldCreateTileAt(
// If the active tree can't create a tile, because of its raster source, then
// the pending tree should create one.
- if (!active_twin->raster_source()->CoversRect(info.enclosing_layer_rect,
- *active_twin->client()))
+ if (!active_twin->raster_source()->IntersectsRect(info.enclosing_layer_rect,
+ *active_twin->client()))
return true;
const Region* layer_invalidation = client_->GetPendingInvalidation();
@@ -879,7 +879,8 @@ PrioritizedTile PictureLayerTiling::MakePrioritizedTile(
Tile* tile,
PriorityRectType priority_rect_type) const {
DCHECK(tile);
- DCHECK(raster_source()->CoversRect(tile->enclosing_layer_rect(), *client_))
+ DCHECK(
+ raster_source()->IntersectsRect(tile->enclosing_layer_rect(), *client_))
<< "Recording rect: "
<< EnclosingLayerRectFromContentsRect(tile->content_rect()).ToString();
diff --git a/chromium/cc/tiles/picture_layer_tiling_set.cc b/chromium/cc/tiles/picture_layer_tiling_set.cc
index aec6390cc19..f958c316e26 100644
--- a/chromium/cc/tiles/picture_layer_tiling_set.cc
+++ b/chromium/cc/tiles/picture_layer_tiling_set.cc
@@ -13,6 +13,7 @@
#include <utility>
#include <vector>
+#include "base/containers/contains.h"
#include "base/memory/ptr_util.h"
#include "base/stl_util.h"
#include "base/trace_event/trace_event.h"
diff --git a/chromium/cc/tiles/software_image_decode_cache.cc b/chromium/cc/tiles/software_image_decode_cache.cc
index 7ae825ab67a..d7e6678eead 100644
--- a/chromium/cc/tiles/software_image_decode_cache.cc
+++ b/chromium/cc/tiles/software_image_decode_cache.cc
@@ -565,9 +565,10 @@ DecodedDrawImage SoftwareImageDecodeCache::GetDecodedImageForDrawInternal(
if (!decoded_image)
return DecodedDrawImage();
- auto decoded_draw_image = DecodedDrawImage(
- std::move(decoded_image), nullptr, cache_entry->src_rect_offset(),
- GetScaleAdjustment(key), GetDecodedFilterQuality(key));
+ auto decoded_draw_image =
+ DecodedDrawImage(std::move(decoded_image), nullptr,
+ cache_entry->src_rect_offset(), GetScaleAdjustment(key),
+ GetDecodedFilterQuality(key), cache_entry->is_budgeted);
return decoded_draw_image;
}
diff --git a/chromium/cc/tiles/software_image_decode_cache_utils.cc b/chromium/cc/tiles/software_image_decode_cache_utils.cc
index 9f04ed5ff32..93598178fd7 100644
--- a/chromium/cc/tiles/software_image_decode_cache_utils.cc
+++ b/chromium/cc/tiles/software_image_decode_cache_utils.cc
@@ -154,7 +154,10 @@ SoftwareImageDecodeCacheUtils::GenerateCacheEntryFromCandidate(
result = ImageDecodeCacheUtils::ScaleToHalfFloatPixmapUsingN32Intermediate(
decoded_pixmap, &target_pixmap, filter_quality);
} else {
- result = decoded_pixmap.scalePixels(target_pixmap, filter_quality);
+ result = decoded_pixmap.scalePixels(
+ target_pixmap,
+ SkSamplingOptions(filter_quality,
+ SkSamplingOptions::kMedium_asMipmapLinear));
}
DCHECK(result) << key.ToString();
diff --git a/chromium/cc/tiles/tile_manager.cc b/chromium/cc/tiles/tile_manager.cc
index c6c7cd5bd79..474ac906a21 100644
--- a/chromium/cc/tiles/tile_manager.cc
+++ b/chromium/cc/tiles/tile_manager.cc
@@ -338,18 +338,21 @@ class DidFinishRunningAllTilesTask : public TileTask {
public:
using CompletionCb = base::OnceCallback<void(bool has_pending_queries)>;
DidFinishRunningAllTilesTask(base::SequencedTaskRunner* task_runner,
- RasterBufferProvider* raster_buffer_provider,
+ RasterQueryQueue* pending_raster_queries,
CompletionCb completion_cb)
: TileTask(TileTask::SupportsConcurrentExecution::kNo,
TileTask::SupportsBackgroundThreadPriority::kYes),
task_runner_(task_runner),
- raster_buffer_provider_(raster_buffer_provider),
+ pending_raster_queries_(pending_raster_queries),
completion_cb_(std::move(completion_cb)) {}
void RunOnWorkerThread() override {
TRACE_EVENT0("cc", "TaskSetFinishedTaskImpl::RunOnWorkerThread");
- bool has_pending_queries =
- raster_buffer_provider_->CheckRasterFinishedQueries();
+ bool has_pending_queries = false;
+ if (pending_raster_queries_) {
+ has_pending_queries =
+ pending_raster_queries_->CheckRasterFinishedQueries();
+ }
task_runner_->PostTask(FROM_HERE, base::BindOnce(std::move(completion_cb_),
has_pending_queries));
}
@@ -361,7 +364,7 @@ class DidFinishRunningAllTilesTask : public TileTask {
private:
base::SequencedTaskRunner* task_runner_;
- RasterBufferProvider* raster_buffer_provider_;
+ RasterQueryQueue* pending_raster_queries_;
CompletionCb completion_cb_;
};
@@ -465,12 +468,14 @@ void TileManager::SetResources(ResourcePool* resource_pool,
TaskGraphRunner* task_graph_runner,
RasterBufferProvider* raster_buffer_provider,
bool use_gpu_rasterization,
- bool use_oop_rasterization) {
+ bool use_oop_rasterization,
+ RasterQueryQueue* pending_raster_queries) {
DCHECK(!tile_task_manager_);
DCHECK(task_graph_runner);
use_gpu_rasterization_ = use_gpu_rasterization;
use_oop_rasterization_ = use_oop_rasterization;
+ pending_raster_queries_ = pending_raster_queries;
resource_pool_ = resource_pool;
image_controller_.SetImageDecodeCache(image_decode_cache);
tile_task_manager_ = TileTaskManagerImpl::Create(task_graph_runner);
@@ -1020,7 +1025,7 @@ void TileManager::ScheduleTasks(PrioritizedWorkToSchedule work_to_schedule) {
task_set_finished_weak_ptr_factory_.GetWeakPtr());
scoped_refptr<TileTask> all_done_task =
base::MakeRefCounted<DidFinishRunningAllTilesTask>(
- task_runner_, raster_buffer_provider_, std::move(all_done_cb));
+ task_runner_, pending_raster_queries_, std::move(all_done_cb));
// Build a new task queue containing all task currently needed. Tasks
// are added in order of priority, highest priority task first.
@@ -1477,7 +1482,11 @@ void TileManager::CheckRasterFinishedQueries() {
if (has_scheduled_tile_tasks_ || !signals_.all_tile_tasks_completed)
return;
- has_pending_queries_ = raster_buffer_provider_->CheckRasterFinishedQueries();
+ has_pending_queries_ = false;
+ if (pending_raster_queries_) {
+ has_pending_queries_ =
+ pending_raster_queries_->CheckRasterFinishedQueries();
+ }
if (has_pending_queries_)
ScheduleCheckRasterFinishedQueries();
}
diff --git a/chromium/cc/tiles/tile_manager.h b/chromium/cc/tiles/tile_manager.h
index 0495ba0865a..39cf268672a 100644
--- a/chromium/cc/tiles/tile_manager.h
+++ b/chromium/cc/tiles/tile_manager.h
@@ -19,6 +19,7 @@
#include "base/values.h"
#include "cc/base/unique_notifier.h"
#include "cc/raster/raster_buffer_provider.h"
+#include "cc/raster/raster_query_queue.h"
#include "cc/raster/raster_source.h"
#include "cc/resources/memory_history.h"
#include "cc/resources/resource_pool.h"
@@ -180,7 +181,8 @@ class CC_EXPORT TileManager : CheckerImageTrackerClient {
TaskGraphRunner* task_graph_runner,
RasterBufferProvider* raster_buffer_provider,
bool use_gpu_rasterization,
- bool use_oop_rasterization);
+ bool use_oop_rasterization,
+ RasterQueryQueue* pending_raster_queries);
// This causes any completed raster work to finalize, so that tiles get up to
// date draw information.
@@ -260,6 +262,11 @@ class CC_EXPORT TileManager : CheckerImageTrackerClient {
raster_buffer_provider_ = raster_buffer_provider;
}
+ void SetPendingRasterQueriesForTesting(
+ RasterQueryQueue* pending_raster_queries) {
+ pending_raster_queries_ = pending_raster_queries;
+ }
+
std::vector<Tile*> AllTilesForTesting() const {
std::vector<Tile*> tiles;
for (auto& tile_pair : tiles_)
@@ -442,6 +449,7 @@ class CC_EXPORT TileManager : CheckerImageTrackerClient {
const TileManagerSettings tile_manager_settings_;
bool use_gpu_rasterization_;
bool use_oop_rasterization_;
+ RasterQueryQueue* pending_raster_queries_ = nullptr;
std::unordered_map<Tile::Id, Tile*> tiles_;
diff --git a/chromium/cc/tiles/tile_manager_unittest.cc b/chromium/cc/tiles/tile_manager_unittest.cc
index e557b0976c2..b263d53826d 100644
--- a/chromium/cc/tiles/tile_manager_unittest.cc
+++ b/chromium/cc/tiles/tile_manager_unittest.cc
@@ -10,8 +10,8 @@
#include "base/bind.h"
#include "base/callback.h"
#include "base/callback_helpers.h"
+#include "base/containers/contains.h"
#include "base/run_loop.h"
-#include "base/stl_util.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "cc/layers/recording_source.h"
@@ -26,6 +26,7 @@
#include "cc/test/fake_paint_image_generator.h"
#include "cc/test/fake_picture_layer_impl.h"
#include "cc/test/fake_picture_layer_tiling_client.h"
+#include "cc/test/fake_raster_query_queue.h"
#include "cc/test/fake_raster_source.h"
#include "cc/test/fake_recording_source.h"
#include "cc/test/fake_tile_manager.h"
@@ -3520,23 +3521,31 @@ TEST_F(HdrImageTileManagerTest, DecodeHdrImagesToSdrP3) {
class TileManagerCheckRasterQueriesTest : public TileManagerTest {
public:
+ TileManagerCheckRasterQueriesTest()
+ : pending_raster_queries_(viz::TestContextProvider::CreateWorker().get(),
+ /*oop_rasterization_enabled=*/false) {}
~TileManagerCheckRasterQueriesTest() override {
// Ensure that the host impl doesn't outlive |raster_buffer_provider_|.
TakeHostImpl();
}
void SetUp() override {
TileManagerTest::SetUp();
- host_impl()->tile_manager()->SetRasterBufferProviderForTesting(
- &raster_buffer_provider_);
+ host_impl()->tile_manager()->SetPendingRasterQueriesForTesting(
+ &pending_raster_queries_);
}
protected:
- class MockRasterBufferProvider : public FakeRasterBufferProviderImpl {
+ class MockRasterQueryQueue : public FakeRasterQueryQueue {
public:
+ MockRasterQueryQueue(
+ viz::RasterContextProvider* const worker_context_provider,
+ bool oop_rasterization_enabled)
+ : FakeRasterQueryQueue(worker_context_provider,
+ oop_rasterization_enabled) {}
MOCK_METHOD0(CheckRasterFinishedQueries, bool());
};
- MockRasterBufferProvider raster_buffer_provider_;
+ MockRasterQueryQueue pending_raster_queries_;
};
TEST_F(TileManagerCheckRasterQueriesTest,
@@ -3545,7 +3554,7 @@ TEST_F(TileManagerCheckRasterQueriesTest,
EXPECT_FALSE(host_impl()->tile_manager()->HasScheduledTileTasksForTesting());
EXPECT_CALL(MockHostImpl(), NotifyAllTileTasksCompleted())
.WillOnce(testing::Invoke([&run_loop]() { run_loop.Quit(); }));
- EXPECT_CALL(raster_buffer_provider_, CheckRasterFinishedQueries()).Times(1);
+ EXPECT_CALL(pending_raster_queries_, CheckRasterFinishedQueries()).Times(1);
host_impl()->tile_manager()->PrepareTiles(host_impl()->global_tile_state());
EXPECT_TRUE(host_impl()->tile_manager()->HasScheduledTileTasksForTesting());
run_loop.Run();
diff --git a/chromium/cc/trees/animated_paint_worklet_tracker.cc b/chromium/cc/trees/animated_paint_worklet_tracker.cc
index 36b6d18f8a8..b312c24180d 100644
--- a/chromium/cc/trees/animated_paint_worklet_tracker.cc
+++ b/chromium/cc/trees/animated_paint_worklet_tracker.cc
@@ -4,6 +4,10 @@
#include "cc/trees/animated_paint_worklet_tracker.h"
+#include <string>
+#include <utility>
+#include <vector>
+
#include "cc/layers/picture_layer_impl.h"
namespace cc {
@@ -25,25 +29,22 @@ AnimatedPaintWorkletTracker::PropertyState::PropertyState(
AnimatedPaintWorkletTracker::PropertyState::~PropertyState() = default;
void AnimatedPaintWorkletTracker::OnCustomPropertyMutated(
- ElementId element_id,
- const std::string& custom_property_name,
- PaintWorkletInput::PropertyValue custom_property_value) {
- // This function is called to update custom property value only.
- DCHECK(!custom_property_name.empty());
- PaintWorkletInput::PropertyKey key{custom_property_name, element_id};
- auto iter = input_properties_.find(key);
+ PaintWorkletInput::PropertyKey property_key,
+ PaintWorkletInput::PropertyValue property_value) {
+ auto iter = input_properties_.find(property_key);
// OnCustomPropertyMutated is called for all composited custom property
- // animations, but there may not be a matching PaintWorklet, and thus no entry
+ // animations and some types of native properties that uses the paint worklet
+ // infra, but there may not be a matching PaintWorklet, and thus no entry
// in |input_properties_|.
// TODO(xidachen): Only create composited custom property animations if they
// affect paint worklet.
if (iter == input_properties_.end())
return;
- iter->second.animation_value = std::move(custom_property_value);
+ iter->second.animation_value = std::move(property_value);
// Keep track of which input properties have been changed so that the
// associated PaintWorklets can be invalidated before activating the pending
// tree.
- input_properties_animated_on_impl_.insert(key);
+ input_properties_animated_on_impl_.insert(property_key);
}
bool AnimatedPaintWorkletTracker::InvalidatePaintWorkletsOnPendingTree() {
diff --git a/chromium/cc/trees/animated_paint_worklet_tracker.h b/chromium/cc/trees/animated_paint_worklet_tracker.h
index 996a6edc2f6..353daa78e2a 100644
--- a/chromium/cc/trees/animated_paint_worklet_tracker.h
+++ b/chromium/cc/trees/animated_paint_worklet_tracker.h
@@ -6,6 +6,7 @@
#define CC_TREES_ANIMATED_PAINT_WORKLET_TRACKER_H_
#include <memory>
+#include <vector>
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
@@ -46,10 +47,8 @@ class CC_EXPORT AnimatedPaintWorkletTracker {
// Called when the value of a property is changed by the CC animation system.
// Responsible for updating the property value in |input_properties_|, and
// marking any relevant PaintWorkletInputs as needs-invalidation.
- void OnCustomPropertyMutated(
- ElementId element_id,
- const std::string& custom_property_name,
- PaintWorkletInput::PropertyValue custom_property_value);
+ void OnCustomPropertyMutated(PaintWorkletInput::PropertyKey property_key,
+ PaintWorkletInput::PropertyValue property_value);
// Invalidate all the paint worklets that uses the set of dirtied properties.
// Returns whether the set of dirtied properties is empty or not.
bool InvalidatePaintWorkletsOnPendingTree();
diff --git a/chromium/cc/trees/compositor_commit_data.cc b/chromium/cc/trees/compositor_commit_data.cc
index 939ed2d8347..1dd546bb327 100644
--- a/chromium/cc/trees/compositor_commit_data.cc
+++ b/chromium/cc/trees/compositor_commit_data.cc
@@ -8,15 +8,7 @@
namespace cc {
-CompositorCommitData::CompositorCommitData()
- : page_scale_delta(1.f),
- is_pinch_gesture_active(false),
- top_controls_delta(0.f),
- bottom_controls_delta(0.f),
- browser_controls_constraint(BrowserControlsState::kBoth),
- browser_controls_constraint_changed(false),
- scroll_gesture_did_end(false),
- manipulation_info(kManipulationInfoNone) {}
+CompositorCommitData::CompositorCommitData() = default;
CompositorCommitData::~CompositorCommitData() = default;
diff --git a/chromium/cc/trees/compositor_commit_data.h b/chromium/cc/trees/compositor_commit_data.h
index ccee2259983..c55747cad1a 100644
--- a/chromium/cc/trees/compositor_commit_data.h
+++ b/chromium/cc/trees/compositor_commit_data.h
@@ -57,8 +57,9 @@ struct CC_EXPORT CompositorCommitData {
ScrollUpdateInfo inner_viewport_scroll;
std::vector<ScrollUpdateInfo> scrolls;
- float page_scale_delta;
- bool is_pinch_gesture_active;
+ float page_scale_delta = 1.f;
+ bool is_pinch_gesture_active = false;
+ bool is_scroll_active = false;
// Elastic overscroll effect offset delta. This is used only on Mac and shows
// the pixels that the page is rubber-banned/stretched by.
@@ -72,8 +73,8 @@ struct CC_EXPORT CompositorCommitData {
// send overscroll/scrollend DOM events to proper targets whenever needed.
ElementId scroll_latched_element_id;
- float top_controls_delta;
- float bottom_controls_delta;
+ float top_controls_delta = 0.f;
+ float bottom_controls_delta = 0.f;
// Used to communicate scrollbar visibility from Impl thread to Blink.
// Scrollbar input is handled by Blink but the compositor thread animates
@@ -91,12 +92,13 @@ struct CC_EXPORT CompositorCommitData {
std::vector<ScrollbarsUpdateInfo> scrollbars;
std::vector<std::unique_ptr<SwapPromise>> swap_promises;
- BrowserControlsState browser_controls_constraint;
- bool browser_controls_constraint_changed;
+ BrowserControlsState browser_controls_constraint =
+ BrowserControlsState::kBoth;
+ bool browser_controls_constraint_changed = false;
// Set to true when a scroll gesture being handled on the compositor has
// ended.
- bool scroll_gesture_did_end;
+ bool scroll_gesture_did_end = false;
// Tracks whether there is an ongoing compositor-driven animation for a
// scroll.
@@ -104,7 +106,7 @@ struct CC_EXPORT CompositorCommitData {
// Tracks different methods of scrolling (e.g. wheel, touch, precision
// touchpad, etc.).
- ManipulationInfo manipulation_info;
+ ManipulationInfo manipulation_info = kManipulationInfoNone;
};
} // namespace cc
diff --git a/chromium/cc/trees/damage_tracker.cc b/chromium/cc/trees/damage_tracker.cc
index 48499b8b57e..a86bf950bec 100644
--- a/chromium/cc/trees/damage_tracker.cc
+++ b/chromium/cc/trees/damage_tracker.cc
@@ -106,11 +106,6 @@ void DamageTracker::UpdateDamageTracking(LayerTreeImpl* layer_tree_impl) {
render_surface->damage_tracker()->PrepareForUpdate();
}
- // Surfaces with backdrop blur filter that might be potentially optimized with
- // caching, paired with each's surface rect in target space.
- std::vector<std::pair<RenderSurfaceImpl*, gfx::Rect>>
- surfaces_with_backdrop_blur_filter;
-
EffectTree& effect_tree = layer_tree_impl->property_trees()->effect_tree;
int current_target_effect_id = EffectTree::kContentsRootNodeId;
DCHECK(effect_tree.GetRenderSurface(current_target_effect_id));
@@ -131,11 +126,10 @@ void DamageTracker::UpdateDamageTracking(LayerTreeImpl* layer_tree_impl) {
// in draw order.
RenderSurfaceImpl* current_target =
effect_tree.GetRenderSurface(current_target_effect_id);
- current_target->damage_tracker()->ComputeSurfaceDamage(
- current_target, surfaces_with_backdrop_blur_filter);
+ current_target->damage_tracker()->ComputeSurfaceDamage(current_target);
RenderSurfaceImpl* parent_target = current_target->render_target();
parent_target->damage_tracker()->AccumulateDamageFromRenderSurface(
- current_target, surfaces_with_backdrop_blur_filter);
+ current_target);
current_target_effect_id =
effect_tree.Node(current_target_effect_id)->target_id;
}
@@ -156,23 +150,17 @@ void DamageTracker::UpdateDamageTracking(LayerTreeImpl* layer_tree_impl) {
RenderSurfaceImpl* current_target =
effect_tree.GetRenderSurface(current_target_effect_id);
while (true) {
- current_target->damage_tracker()->ComputeSurfaceDamage(
- current_target, surfaces_with_backdrop_blur_filter);
+ current_target->damage_tracker()->ComputeSurfaceDamage(current_target);
if (current_target->EffectTreeIndex() == EffectTree::kContentsRootNodeId)
break;
RenderSurfaceImpl* next_target = current_target->render_target();
next_target->damage_tracker()->AccumulateDamageFromRenderSurface(
- current_target, surfaces_with_backdrop_blur_filter);
+ current_target);
current_target = next_target;
}
-
- DCHECK(surfaces_with_backdrop_blur_filter.empty());
}
-void DamageTracker::ComputeSurfaceDamage(
- RenderSurfaceImpl* render_surface,
- std::vector<std::pair<RenderSurfaceImpl*, gfx::Rect>>&
- surfaces_with_backdrop_blur_filter) {
+void DamageTracker::ComputeSurfaceDamage(RenderSurfaceImpl* render_surface) {
// All damage from contributing layers and surfaces must already have been
// added to damage_for_this_update_ through calls to AccumulateDamageFromLayer
// and AccumulateDamageFromRenderSurface.
@@ -185,6 +173,35 @@ void DamageTracker::ComputeSurfaceDamage(
has_damage_from_contributing_content_ |=
!damage_from_leftover_rects.IsEmpty();
+ gfx::Rect expanded_damage_rect;
+ bool valid = damage_from_leftover_rects.GetAsRect(&expanded_damage_rect);
+ bool expanded = false;
+ // Iterate through the surfaces rendering to the current target back to
+ // front, intersect their surface rects with the damage from leftover rects.
+ // Update surfaces' |intersects_damage_under| flags accordingly and expand the
+ // damage by surface rects for surfaces with pixel-moving backdrop filters
+ // when appropriate.
+ for (auto& contributing_surface : contributing_surfaces_) {
+ RenderSurfaceImpl* surface = contributing_surface.render_surface;
+ bool has_pixel_moving_backdrop_filters =
+ surface->BackdropFilters().HasFilterThatMovesPixels();
+ if (!surface->intersects_damage_under() ||
+ has_pixel_moving_backdrop_filters) {
+ if (!valid || contributing_surface.rect_in_target_space.Intersects(
+ expanded_damage_rect)) {
+ surface->set_intersects_damage_under(true);
+ if (has_pixel_moving_backdrop_filters) {
+ expanded_damage_rect.Union(contributing_surface.rect_in_target_space);
+ expanded = true;
+ }
+ }
+ }
+ }
+ if (expanded)
+ damage_for_this_update_.Union(expanded_damage_rect);
+
+ contributing_surfaces_.clear();
+
if (render_surface->SurfacePropertyChangedOnlyFromDescendant()) {
damage_for_this_update_ = DamageAccumulator();
damage_for_this_update_.Union(render_surface->content_rect());
@@ -208,23 +225,6 @@ void DamageTracker::ComputeSurfaceDamage(
// Damage accumulates until we are notified that we actually did draw on that
// frame.
current_damage_.Union(damage_for_this_update_);
-
- if (!surfaces_with_backdrop_blur_filter.empty()) {
- gfx::Rect leftover_damage_rect;
- bool valid = damage_from_leftover_rects.GetAsRect(&leftover_damage_rect);
- std::vector<std::pair<RenderSurfaceImpl*, gfx::Rect>>::iterator it =
- surfaces_with_backdrop_blur_filter.begin();
- while (it != surfaces_with_backdrop_blur_filter.end()) {
- RenderSurfaceImpl* surface = it->first;
- if (surface->render_target() == render_surface) {
- surface->set_can_use_cached_backdrop_filtered_result(
- !it->second.Intersects(leftover_damage_rect) && valid);
- it = surfaces_with_backdrop_blur_filter.erase(it);
- } else {
- ++it;
- }
- }
- }
}
bool DamageTracker::GetDamageRectIfValid(gfx::Rect* rect) {
@@ -267,6 +267,7 @@ void DamageTracker::PrepareForUpdate() {
mailboxId_++;
damage_for_this_update_ = DamageAccumulator();
has_damage_from_contributing_content_ = false;
+ contributing_surfaces_.clear();
}
DamageTracker::DamageAccumulator DamageTracker::TrackDamageFromLeftoverRects() {
@@ -408,9 +409,7 @@ void DamageTracker::AccumulateDamageFromLayer(LayerImpl* layer) {
}
void DamageTracker::AccumulateDamageFromRenderSurface(
- RenderSurfaceImpl* render_surface,
- std::vector<std::pair<RenderSurfaceImpl*, gfx::Rect>>&
- surfaces_with_backdrop_blur_filter) {
+ RenderSurfaceImpl* render_surface) {
// There are two ways a "descendant surface" can damage regions of the "target
// surface":
// 1. Property change:
@@ -434,6 +433,20 @@ void DamageTracker::AccumulateDamageFromRenderSurface(
gfx::Rect surface_rect_in_target_space =
gfx::ToEnclosingRect(render_surface->DrawableContentRect());
data.Update(surface_rect_in_target_space, mailboxId_);
+ contributing_surfaces_.emplace_back(render_surface,
+ surface_rect_in_target_space);
+
+ // If the render surface has pixel-moving backdrop filters and the surface
+ // rect intersects current accumulated damage, expand the damage by surface
+ // rect.
+ gfx::Rect damage_on_target;
+ bool valid = damage_for_this_update_.GetAsRect(&damage_on_target);
+ bool intersects_damage_under =
+ !valid || damage_on_target.Intersects(surface_rect_in_target_space);
+ if (render_surface->BackdropFilters().HasFilterThatMovesPixels() &&
+ intersects_damage_under) {
+ damage_for_this_update_.Union(surface_rect_in_target_space);
+ }
if (surface_is_new || render_surface->SurfacePropertyChanged()) {
// The entire surface contributes damage.
@@ -441,17 +454,8 @@ void DamageTracker::AccumulateDamageFromRenderSurface(
// The surface's old region is now exposed on the target surface, too.
damage_for_this_update_.Union(old_surface_rect);
- render_surface->set_can_use_cached_backdrop_filtered_result(false);
+ intersects_damage_under = true;
} else {
- // Check if current accumulated damage intersects the render surface.
- gfx::Rect damage_on_target;
- bool valid = damage_for_this_update_.GetAsRect(&damage_on_target);
- if (valid && !damage_on_target.Intersects(surface_rect_in_target_space)) {
- surfaces_with_backdrop_blur_filter.emplace_back(
- std::make_pair(render_surface, surface_rect_in_target_space));
- } else {
- render_surface->set_can_use_cached_backdrop_filtered_result(false);
- }
// Only the surface's damage_rect will damage the target surface.
gfx::Rect damage_rect_in_local_space;
bool is_valid_rect = render_surface->damage_tracker()->GetDamageRectIfValid(
@@ -470,6 +474,7 @@ void DamageTracker::AccumulateDamageFromRenderSurface(
}
}
+ render_surface->set_intersects_damage_under(intersects_damage_under);
// True if any changes from contributing render surface.
has_damage_from_contributing_content_ |= !damage_for_this_update_.IsEmpty();
}
diff --git a/chromium/cc/trees/damage_tracker.h b/chromium/cc/trees/damage_tracker.h
index d5b83bededc..70a8356ce58 100644
--- a/chromium/cc/trees/damage_tracker.h
+++ b/chromium/cc/trees/damage_tracker.h
@@ -5,7 +5,9 @@
#ifndef CC_TREES_DAMAGE_TRACKER_H_
#define CC_TREES_DAMAGE_TRACKER_H_
+#include <algorithm>
#include <memory>
+#include <utility>
#include <vector>
#include "cc/cc_export.h"
@@ -94,14 +96,8 @@ class CC_EXPORT DamageTracker {
// These helper functions are used only during UpdateDamageTracking().
void PrepareForUpdate();
void AccumulateDamageFromLayer(LayerImpl* layer);
- void AccumulateDamageFromRenderSurface(
- RenderSurfaceImpl* render_surface,
- std::vector<std::pair<RenderSurfaceImpl*, gfx::Rect>>&
- surfaces_with_backdrop_blur_filter);
- void ComputeSurfaceDamage(
- RenderSurfaceImpl* render_surface,
- std::vector<std::pair<RenderSurfaceImpl*, gfx::Rect>>&
- surfaces_with_backdrop_blur_filter);
+ void AccumulateDamageFromRenderSurface(RenderSurfaceImpl* render_surface);
+ void ComputeSurfaceDamage(RenderSurfaceImpl* render_surface);
void ExpandDamageInsideRectWithFilters(const gfx::Rect& pre_filter_rect,
const FilterOperations& filters);
@@ -157,6 +153,15 @@ class CC_EXPORT DamageTracker {
// Damage accumulated since the last call to PrepareForUpdate().
DamageAccumulator damage_for_this_update_;
+
+ struct SurfaceWithRect {
+ SurfaceWithRect(RenderSurfaceImpl* rs, const gfx::Rect& rect)
+ : render_surface(rs), rect_in_target_space(rect) {}
+ RenderSurfaceImpl* render_surface;
+ const gfx::Rect rect_in_target_space;
+ };
+
+ std::vector<SurfaceWithRect> contributing_surfaces_;
};
} // namespace cc
diff --git a/chromium/cc/trees/damage_tracker_unittest.cc b/chromium/cc/trees/damage_tracker_unittest.cc
index 4b9213336ec..00fa95b025d 100644
--- a/chromium/cc/trees/damage_tracker_unittest.cc
+++ b/chromium/cc/trees/damage_tracker_unittest.cc
@@ -904,9 +904,8 @@ TEST_F(DamageTrackerTest, VerifyDamageForImageFilter) {
child->SetDrawsContent(true);
FilterOperations filters;
- filters.Append(
- FilterOperation::CreateReferenceFilter(sk_make_sp<BlurPaintFilter>(
- 2, 2, BlurPaintFilter::TileMode::kClampToBlack_TileMode, nullptr)));
+ filters.Append(FilterOperation::CreateReferenceFilter(
+ sk_make_sp<BlurPaintFilter>(2, 2, SkTileMode::kDecal, nullptr)));
// Setting the filter will damage the whole surface.
CreateTransformNode(child).post_translation =
@@ -988,9 +987,8 @@ TEST_F(DamageTrackerTest, VerifyDamageForTransformedImageFilter) {
child->SetDrawsContent(true);
FilterOperations filters;
- filters.Append(
- FilterOperation::CreateReferenceFilter(sk_make_sp<BlurPaintFilter>(
- 2, 2, BlurPaintFilter::TileMode::kClampToBlack_TileMode, nullptr)));
+ filters.Append(FilterOperation::CreateReferenceFilter(
+ sk_make_sp<BlurPaintFilter>(2, 2, SkTileMode::kDecal, nullptr)));
// Setting the filter will damage the whole surface.
gfx::Transform transform;
@@ -2054,27 +2052,23 @@ TEST_F(DamageTrackerTest, CanUseCachedBackdropFilterResultTest) {
filters.Append(FilterOperation::CreateBlurFilter(2.f));
SetBackdropFilter(child1_, filters);
child1_->NoteLayerPropertyChanged();
- // can_use_cached_backdrop_filtered_result_ is false by default.
- EXPECT_FALSE(
- GetRenderSurface(child1_)->can_use_cached_backdrop_filtered_result());
+ // intersects_damage_under_ is false by default.
+ EXPECT_TRUE(GetRenderSurface(child1_)->intersects_damage_under());
EmulateDrawingOneFrame(root);
// child1_'s render target has changed its surface property.
- EXPECT_FALSE(
- GetRenderSurface(child1_)->can_use_cached_backdrop_filtered_result());
+ EXPECT_TRUE(GetRenderSurface(child1_)->intersects_damage_under());
// Let run for one update and there should be no damage left.
EmulateDrawingOneFrame(root);
- EXPECT_TRUE(
- GetRenderSurface(child1_)->can_use_cached_backdrop_filtered_result());
+ EXPECT_FALSE(GetRenderSurface(child1_)->intersects_damage_under());
// CASE 1.1: Setting a non-intersecting update rect on the root
// doesn't invalidate child1_'s cached backdrop-filtered result.
// Damage rect at 0,0 20x20 doesn't intersect 270,270 36x38.
root->UnionUpdateRect(gfx::Rect(0, 0, 20, 20));
EmulateDrawingOneFrame(root);
- EXPECT_TRUE(
- GetRenderSurface(child1_)->can_use_cached_backdrop_filtered_result());
+ EXPECT_FALSE(GetRenderSurface(child1_)->intersects_damage_under());
// CASE 1.2: Setting an intersecting update rect on the root invalidates
// child1_'s cached backdrop-filtered result.
@@ -2082,8 +2076,7 @@ TEST_F(DamageTrackerTest, CanUseCachedBackdropFilterResultTest) {
ClearDamageForAllSurfaces(root);
root->UnionUpdateRect(gfx::Rect(260, 260, 20, 20));
EmulateDrawingOneFrame(root);
- EXPECT_FALSE(
- GetRenderSurface(child1_)->can_use_cached_backdrop_filtered_result());
+ EXPECT_TRUE(GetRenderSurface(child1_)->intersects_damage_under());
// CASE 1.3: Damage on layers above the surface with the backdrop filter
// doesn't invalidate cached backdrop-filtered result. Move child2_ to overlap
@@ -2091,8 +2084,7 @@ TEST_F(DamageTrackerTest, CanUseCachedBackdropFilterResultTest) {
ClearDamageForAllSurfaces(root);
child2_->SetOffsetToTransformParent(gfx::Vector2dF(180.f, 180.f));
EmulateDrawingOneFrame(root);
- EXPECT_TRUE(GetRenderSurface(grand_child1_)
- ->can_use_cached_backdrop_filtered_result());
+ EXPECT_FALSE(GetRenderSurface(grand_child1_)->intersects_damage_under());
// CASE 2: Adding or removing a backdrop filter would invalidate cached
// backdrop-filtered result of the corresponding render surfaces.
@@ -2104,15 +2096,12 @@ TEST_F(DamageTrackerTest, CanUseCachedBackdropFilterResultTest) {
SetBackdropFilter(grand_child4_, filters);
grand_child4_->NoteLayerPropertyChanged();
EmulateDrawingOneFrame(root);
- EXPECT_FALSE(GetRenderSurface(grand_child4_)
- ->can_use_cached_backdrop_filtered_result());
- EXPECT_FALSE(GetRenderSurface(grand_child1_)
- ->can_use_cached_backdrop_filtered_result());
+ EXPECT_TRUE(GetRenderSurface(grand_child4_)->intersects_damage_under());
+ EXPECT_TRUE(GetRenderSurface(grand_child1_)->intersects_damage_under());
// Let run for one update and there should be no damage left.
EmulateDrawingOneFrame(root);
- EXPECT_TRUE(GetRenderSurface(grand_child4_)
- ->can_use_cached_backdrop_filtered_result());
+ EXPECT_FALSE(GetRenderSurface(grand_child4_)->intersects_damage_under());
// CASE 3.1: Adding a non-intersecting damage rect to a sibling layer under
// the render surface with the backdrop filter doesn't invalidate cached
@@ -2121,8 +2110,7 @@ TEST_F(DamageTrackerTest, CanUseCachedBackdropFilterResultTest) {
ClearDamageForAllSurfaces(root);
grand_child1_->AddDamageRect(gfx::Rect(2, 2, 1.f, 1.f));
EmulateDrawingOneFrame(root);
- EXPECT_TRUE(GetRenderSurface(grand_child4_)
- ->can_use_cached_backdrop_filtered_result());
+ EXPECT_FALSE(GetRenderSurface(grand_child4_)->intersects_damage_under());
// CASE 3.2: Adding an intersecting damage rect to a sibling layer under the
// render surface with the backdrop filter invalidates cached
@@ -2131,8 +2119,7 @@ TEST_F(DamageTrackerTest, CanUseCachedBackdropFilterResultTest) {
ClearDamageForAllSurfaces(root);
grand_child2_->AddDamageRect(gfx::Rect(0, 0, 1.f, 1.f));
EmulateDrawingOneFrame(root);
- EXPECT_FALSE(GetRenderSurface(grand_child4_)
- ->can_use_cached_backdrop_filtered_result());
+ EXPECT_TRUE(GetRenderSurface(grand_child4_)->intersects_damage_under());
// CASE 4.1: Non-intersecting damage rect on a sibling surface under the
// render surface with the backdrop filter doesn't invalidate cached
@@ -2147,8 +2134,7 @@ TEST_F(DamageTrackerTest, CanUseCachedBackdropFilterResultTest) {
EXPECT_EQ(gfx::Rect(170, 170, 1.f, 1.f), damage_rect);
// Damage rect at 170,170 1x1 in render target local space doesn't intersect
// 180,180 15x16.
- EXPECT_TRUE(GetRenderSurface(grand_child4_)
- ->can_use_cached_backdrop_filtered_result());
+ EXPECT_FALSE(GetRenderSurface(grand_child4_)->intersects_damage_under());
// CASE 4.2: Intersecting damage rect on a sibling surface under the render
// surface with the backdrop filter invalidates cached backdrop-filtered
@@ -2162,8 +2148,7 @@ TEST_F(DamageTrackerTest, CanUseCachedBackdropFilterResultTest) {
EXPECT_EQ(gfx::Rect(170, 170, 11.f, 11.f), damage_rect);
// Damage rect at 170,170 11x11 in render target local space intersects
// 180,180 15x16
- EXPECT_FALSE(GetRenderSurface(grand_child4_)
- ->can_use_cached_backdrop_filtered_result());
+ EXPECT_TRUE(GetRenderSurface(grand_child4_)->intersects_damage_under());
// CASE 5.1: Removing a non-intersecting sibling layer under the render
// surface with the backdrop filter doesn't invalidate cached
@@ -2185,8 +2170,7 @@ TEST_F(DamageTrackerTest, CanUseCachedBackdropFilterResultTest) {
host_impl()->active_tree()->AddLayer(std::move(layers[5]));
host_impl()->active_tree()->AddLayer(std::move(layers[6]));
EmulateDrawingOneFrame(root);
- EXPECT_TRUE(GetRenderSurface(grand_child4_)
- ->can_use_cached_backdrop_filtered_result());
+ EXPECT_FALSE(GetRenderSurface(grand_child4_)->intersects_damage_under());
// CASE 5.2: Removing an intersecting sibling layer under the render surface
// with the backdrop filter invalidates cached backdrop-filtered result.
@@ -2205,14 +2189,12 @@ TEST_F(DamageTrackerTest, CanUseCachedBackdropFilterResultTest) {
host_impl()->active_tree()->AddLayer(std::move(layers[5]));
EmulateDrawingOneFrame(root);
- EXPECT_FALSE(GetRenderSurface(grand_child4_)
- ->can_use_cached_backdrop_filtered_result());
+ EXPECT_TRUE(GetRenderSurface(grand_child4_)->intersects_damage_under());
// Let run for one update and there should be no damage left.
ClearDamageForAllSurfaces(root);
EmulateDrawingOneFrame(root);
- EXPECT_TRUE(GetRenderSurface(grand_child4_)
- ->can_use_cached_backdrop_filtered_result());
+ EXPECT_FALSE(GetRenderSurface(grand_child4_)->intersects_damage_under());
// CASE 6: Removing a intersecting sibling surface under the render
// surface with the backdrop filter invalidate cached backdrop-filtered
@@ -2221,8 +2203,7 @@ TEST_F(DamageTrackerTest, CanUseCachedBackdropFilterResultTest) {
SetRenderSurfaceReason(grand_child3_, RenderSurfaceReason::kNone);
grand_child3_->SetDrawsContent(false);
EmulateDrawingOneFrame(root);
- EXPECT_FALSE(GetRenderSurface(grand_child4_)
- ->can_use_cached_backdrop_filtered_result());
+ EXPECT_TRUE(GetRenderSurface(grand_child4_)->intersects_damage_under());
}
TEST_F(DamageTrackerTest, DamageRectOnlyVisibleContentsMoveToOutside) {
@@ -2344,5 +2325,45 @@ TEST_F(DamageTrackerTest,
->has_damage_from_contributing_content());
}
+TEST_F(DamageTrackerTest, VerifyDamageExpansionWithBackdropBlurFilters) {
+ LayerImpl* root = CreateAndSetUpTestTreeWithTwoSurfaces();
+
+ // Allow us to set damage on child1_.
+ child1_->SetDrawsContent(true);
+
+ FilterOperations filters;
+ filters.Append(FilterOperation::CreateBlurFilter(2.f));
+
+ // Setting the filter will damage the whole surface.
+ ClearDamageForAllSurfaces(root);
+ SetBackdropFilter(child1_, filters);
+ child1_->NoteLayerPropertyChanged();
+ EmulateDrawingOneFrame(root);
+
+ ClearDamageForAllSurfaces(root);
+ root->UnionUpdateRect(gfx::Rect(297, 297, 2, 2));
+ EmulateDrawingOneFrame(root);
+
+ // child1_'s render surface has a size of 206x208 due to the contributions
+ // from grand_child1_ and grand_child2_. The blur filter on child1_ intersects
+ // the damage from root and expands it to (100,100 206x208).
+ gfx::Rect expected_damage_rect = gfx::Rect(100, 100, 206, 208);
+ gfx::Rect root_damage_rect;
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
+ &root_damage_rect));
+ EXPECT_EQ(expected_damage_rect, root_damage_rect);
+
+ ClearDamageForAllSurfaces(root);
+ gfx::Rect damage_rect(97, 97, 2, 2);
+ root->UnionUpdateRect(damage_rect);
+ EmulateDrawingOneFrame(root);
+
+ // The blur filter on child1_ doesn't intersect the damage from root so the
+ // damage remains unchanged.
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
+ &root_damage_rect));
+ EXPECT_EQ(damage_rect, root_damage_rect);
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/trees/draw_properties_unittest.cc b/chromium/cc/trees/draw_properties_unittest.cc
index d461d6ae08d..83e66c1a946 100644
--- a/chromium/cc/trees/draw_properties_unittest.cc
+++ b/chromium/cc/trees/draw_properties_unittest.cc
@@ -10,14 +10,11 @@
#include <tuple>
#include <vector>
+#include "base/containers/contains.h"
#include "base/memory/ptr_util.h"
-#include "base/stl_util.h"
#include "cc/animation/animation.h"
#include "cc/animation/animation_host.h"
#include "cc/animation/animation_id_provider.h"
-#include "cc/animation/keyframed_animation_curve.h"
-#include "cc/animation/transform_operations.h"
-#include "cc/base/math_util.h"
#include "cc/layers/content_layer_client.h"
#include "cc/layers/effect_tree_layer_list_iterator.h"
#include "cc/layers/layer.h"
@@ -38,11 +35,14 @@
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "components/viz/common/frame_sinks/copy_output_result.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/animation/keyframe/keyframed_animation_curve.h"
#include "ui/gfx/geometry/quad_f.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/geometry/vector2d_conversions.h"
#include "ui/gfx/transform.h"
+#include "ui/gfx/transform_operations.h"
+#include "ui/gfx/transform_util.h"
namespace cc {
namespace {
@@ -67,20 +67,15 @@ class DrawPropertiesTestBase : public LayerTreeImplTestBase {
layer_impl->element_id());
}
- static float GetMaximumAnimationScale(LayerImpl* layer_impl) {
+ static float MaximumAnimationToScreenScale(LayerImpl* layer_impl) {
return layer_impl->layer_tree_impl()
->property_trees()
- ->GetAnimationScales(layer_impl->transform_tree_index(),
- layer_impl->layer_tree_impl())
- .maximum_animation_scale;
+ ->MaximumAnimationToScreenScale(layer_impl->transform_tree_index());
}
-
- static float GetStartingAnimationScale(LayerImpl* layer_impl) {
+ static bool AnimationAffectedByInvalidScale(LayerImpl* layer_impl) {
return layer_impl->layer_tree_impl()
->property_trees()
- ->GetAnimationScales(layer_impl->transform_tree_index(),
- layer_impl->layer_tree_impl())
- .starting_animation_scale;
+ ->AnimationAffectedByInvalidScale(layer_impl->transform_tree_index());
}
void UpdateMainDrawProperties(float device_scale_factor = 1.0f) {
@@ -291,8 +286,8 @@ TEST_F(DrawPropertiesTest, TransformsForSingleLayer) {
// Case 5: The layer transform should occur with respect to the anchor point.
gfx::Transform translation_to_anchor;
translation_to_anchor.Translate(5.0, 0.0);
- gfx::Transform expected_result =
- translation_to_anchor * layer_transform * Inverse(translation_to_anchor);
+ gfx::Transform expected_result = translation_to_anchor * layer_transform *
+ gfx::InvertAndCheck(translation_to_anchor);
SetTransformOrigin(layer, gfx::Point3F(5.f, 0.f, 0.f));
UpdateActiveTreeDrawProperties();
EXPECT_TRANSFORMATION_MATRIX_EQ(
@@ -306,7 +301,8 @@ TEST_F(DrawPropertiesTest, TransformsForSingleLayer) {
// current implementation of CalculateDrawProperties does this implicitly, but
// it is still worth testing to detect accidental regressions.
expected_result = position_transform * translation_to_anchor *
- layer_transform * Inverse(translation_to_anchor);
+ layer_transform *
+ gfx::InvertAndCheck(translation_to_anchor);
SetPostTranslation(layer, gfx::Vector2dF(0.f, 1.2f));
UpdateActiveTreeDrawProperties();
EXPECT_TRANSFORMATION_MATRIX_EQ(
@@ -465,7 +461,7 @@ TEST_F(DrawPropertiesTest, TransformsForSimpleHierarchy) {
parent_translation_to_anchor.Translate(2.5, 3.0);
gfx::Transform parent_composite_transform =
parent_translation_to_anchor * parent_layer_transform *
- Inverse(parent_translation_to_anchor);
+ gfx::InvertAndCheck(parent_translation_to_anchor);
SetTransform(parent, parent_layer_transform);
SetPostTranslation(parent, gfx::Vector2dF());
UpdateActiveTreeDrawProperties();
@@ -497,15 +493,15 @@ TEST_F(DrawPropertiesTest, TransformsForSingleRenderSurface) {
gfx::Transform parent_composite_transform =
parent_translation_to_anchor * parent_layer_transform *
- Inverse(parent_translation_to_anchor);
+ gfx::InvertAndCheck(parent_translation_to_anchor);
gfx::Vector2dF parent_composite_scale =
- MathUtil::ComputeTransform2dScaleComponents(parent_composite_transform,
- 1.f);
+ gfx::ComputeTransform2dScaleComponents(parent_composite_transform, 1.f);
gfx::Transform surface_sublayer_transform;
surface_sublayer_transform.Scale(parent_composite_scale.x(),
parent_composite_scale.y());
gfx::Transform surface_sublayer_composite_transform =
- parent_composite_transform * Inverse(surface_sublayer_transform);
+ parent_composite_transform *
+ gfx::InvertAndCheck(surface_sublayer_transform);
root->SetBounds(gfx::Size(1, 2));
parent->SetBounds(gfx::Size(100, 120));
@@ -586,11 +582,11 @@ TEST_F(DrawPropertiesTest, TransformsForRenderSurfaceHierarchy) {
gfx::Transform layer_transform;
layer_transform.Translate(1.0, 1.0);
- gfx::Transform A =
- translation_to_anchor * layer_transform * Inverse(translation_to_anchor);
+ gfx::Transform A = translation_to_anchor * layer_transform *
+ gfx::InvertAndCheck(translation_to_anchor);
gfx::Vector2dF surface1_parent_transform_scale =
- MathUtil::ComputeTransform2dScaleComponents(A, 1.f);
+ gfx::ComputeTransform2dScaleComponents(A, 1.f);
gfx::Transform surface1_sublayer_transform;
surface1_sublayer_transform.Scale(surface1_parent_transform_scale.x(),
surface1_parent_transform_scale.y());
@@ -599,10 +595,10 @@ TEST_F(DrawPropertiesTest, TransformsForRenderSurfaceHierarchy) {
gfx::Transform SS1 = surface1_sublayer_transform;
// S1 = transform to move from render_surface1 pixels to the layer space of
// the owning layer
- gfx::Transform S1 = Inverse(surface1_sublayer_transform);
+ gfx::Transform S1 = gfx::InvertAndCheck(surface1_sublayer_transform);
gfx::Vector2dF surface2_parent_transform_scale =
- MathUtil::ComputeTransform2dScaleComponents(SS1 * A, 1.f);
+ gfx::ComputeTransform2dScaleComponents(SS1 * A, 1.f);
gfx::Transform surface2_sublayer_transform;
surface2_sublayer_transform.Scale(surface2_parent_transform_scale.x(),
surface2_parent_transform_scale.y());
@@ -611,7 +607,7 @@ TEST_F(DrawPropertiesTest, TransformsForRenderSurfaceHierarchy) {
gfx::Transform SS2 = surface2_sublayer_transform;
// S2 = transform to move from render_surface2 pixels to the layer space of
// the owning layer
- gfx::Transform S2 = Inverse(surface2_sublayer_transform);
+ gfx::Transform S2 = gfx::InvertAndCheck(surface2_sublayer_transform);
root->SetBounds(gfx::Size(1, 2));
parent->SetBounds(gfx::Size(10, 10));
@@ -1746,8 +1742,8 @@ TEST_F(DrawPropertiesTest,
// Add a transform animation with a start delay to |grand_child|.
std::unique_ptr<KeyframeModel> keyframe_model = KeyframeModel::Create(
- std::unique_ptr<AnimationCurve>(new FakeTransformTransition(1.0)), 0, 1,
- TargetProperty::TRANSFORM);
+ std::unique_ptr<gfx::AnimationCurve>(new FakeTransformTransition(1.0)), 0,
+ 1, KeyframeModel::TargetPropertyId(TargetProperty::TRANSFORM));
keyframe_model->set_fill_mode(KeyframeModel::FillMode::NONE);
keyframe_model->set_time_offset(base::TimeDelta::FromMilliseconds(-1000));
AddKeyframeModelToElementWithAnimation(
@@ -2026,7 +2022,7 @@ TEST_F(DrawPropertiesDrawRectsTest, DrawRectsFor3dPerspectiveWhenClippedByW) {
static bool ProjectionClips(const gfx::Transform& map_transform,
const gfx::RectF& mapped_rect) {
- gfx::Transform inverse(Inverse(map_transform));
+ gfx::Transform inverse(gfx::InvertAndCheck(map_transform));
bool clipped = false;
if (!clipped)
MathUtil::ProjectPoint(inverse, mapped_rect.top_right(), &clipped);
@@ -3237,14 +3233,14 @@ TEST_F(DrawPropertiesScalingTest, SurfaceLayerTransformsInHighDPI) {
transform.Scale(device_scale_factor * page_scale_factor,
device_scale_factor * page_scale_factor);
gfx::Vector2dF scales =
- MathUtil::ComputeTransform2dScaleComponents(transform, 0.f);
+ gfx::ComputeTransform2dScaleComponents(transform, 0.f);
float max_2d_scale = std::max(scales.x(), scales.y());
EXPECT_FLOAT_EQ(max_2d_scale, scale_surface->GetIdealContentsScale());
// The ideal scale will draw 1:1 with its render target space along
// the larger-scale axis.
gfx::Vector2dF target_space_transform_scales =
- MathUtil::ComputeTransform2dScaleComponents(
+ gfx::ComputeTransform2dScaleComponents(
scale_surface->draw_properties().target_space_transform, 0.f);
EXPECT_FLOAT_EQ(max_2d_scale, std::max(target_space_transform_scales.x(),
target_space_transform_scales.y()));
@@ -4638,9 +4634,9 @@ TEST_F(DrawPropertiesTest, ScrollSnappingWithAnimatedScreenSpaceTransform) {
gfx::Transform end_scale;
end_scale.Scale(2.f, 2.f);
- TransformOperations start_operations;
+ gfx::TransformOperations start_operations;
start_operations.AppendMatrix(start_scale);
- TransformOperations end_operations;
+ gfx::TransformOperations end_operations;
end_operations.AppendMatrix(end_scale);
AddAnimatedTransformToElementWithAnimation(animated_layer->element_id(),
@@ -5482,17 +5478,17 @@ TEST_F(DrawPropertiesTest, MaximumAnimationScaleFactor) {
UpdateActiveTreeDrawProperties();
// No layers have animations.
- EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(grand_parent));
- EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(parent));
- EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(child));
- EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(grand_child));
+ EXPECT_EQ(1.f, MaximumAnimationToScreenScale(grand_child));
+ EXPECT_EQ(1.f, MaximumAnimationToScreenScale(child));
+ EXPECT_EQ(1.f, MaximumAnimationToScreenScale(parent));
+ EXPECT_EQ(1.f, MaximumAnimationToScreenScale(grand_parent));
- EXPECT_EQ(kNotScaled, GetStartingAnimationScale(grand_parent));
- EXPECT_EQ(kNotScaled, GetStartingAnimationScale(parent));
- EXPECT_EQ(kNotScaled, GetStartingAnimationScale(child));
- EXPECT_EQ(kNotScaled, GetStartingAnimationScale(grand_child));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(grand_child));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(child));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(parent));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(grand_parent));
- TransformOperations translation;
+ gfx::TransformOperations translation;
translation.AppendTranslate(1.f, 2.f, 3.f);
scoped_refptr<Animation> grand_parent_animation =
@@ -5516,68 +5512,70 @@ TEST_F(DrawPropertiesTest, MaximumAnimationScaleFactor) {
grand_child_animation->AttachElement(grand_child->element_id());
AddAnimatedTransformToAnimation(parent_animation.get(), 1.0,
- TransformOperations(), translation);
+ gfx::TransformOperations(), translation);
// No layers have scale-affecting animations.
- EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(grand_parent));
- EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(parent));
- EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(child));
- EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(grand_child));
+ EXPECT_EQ(1.f, MaximumAnimationToScreenScale(grand_child));
+ EXPECT_EQ(1.f, MaximumAnimationToScreenScale(child));
+ EXPECT_EQ(1.f, MaximumAnimationToScreenScale(parent));
+ EXPECT_EQ(1.f, MaximumAnimationToScreenScale(grand_parent));
- EXPECT_EQ(kNotScaled, GetStartingAnimationScale(grand_parent));
- EXPECT_EQ(kNotScaled, GetStartingAnimationScale(parent));
- EXPECT_EQ(kNotScaled, GetStartingAnimationScale(child));
- EXPECT_EQ(kNotScaled, GetStartingAnimationScale(grand_child));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(grand_child));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(child));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(parent));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(grand_parent));
- TransformOperations scale;
+ gfx::TransformOperations scale;
scale.AppendScale(5.f, 4.f, 3.f);
AddAnimatedTransformToAnimation(child_animation.get(), 1.0,
- TransformOperations(), scale);
+ gfx::TransformOperations(), scale);
UpdateActiveTreeDrawProperties();
// Only |child| has a scale-affecting animation.
- EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(grand_parent));
- EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(parent));
- EXPECT_EQ(5.f, GetMaximumAnimationScale(child));
- EXPECT_EQ(5.f, GetMaximumAnimationScale(grand_child));
+ EXPECT_EQ(5.f, MaximumAnimationToScreenScale(grand_child));
+ EXPECT_EQ(5.f, MaximumAnimationToScreenScale(child));
+ EXPECT_EQ(1.f, MaximumAnimationToScreenScale(parent));
+ EXPECT_EQ(1.f, MaximumAnimationToScreenScale(grand_parent));
- EXPECT_EQ(kNotScaled, GetStartingAnimationScale(grand_parent));
- EXPECT_EQ(kNotScaled, GetStartingAnimationScale(parent));
- EXPECT_EQ(1.f, GetStartingAnimationScale(child));
- EXPECT_EQ(1.f, GetStartingAnimationScale(grand_child));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(grand_child));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(child));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(parent));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(grand_parent));
AddAnimatedTransformToAnimation(grand_parent_animation.get(), 1.0,
- TransformOperations(), scale);
+ gfx::TransformOperations(), scale);
UpdateActiveTreeDrawProperties();
// |grand_parent| and |child| have scale-affecting animations.
- EXPECT_EQ(5.f, GetMaximumAnimationScale(grand_parent));
- EXPECT_EQ(5.f, GetMaximumAnimationScale(parent));
- // We don't support combining animated scales from two nodes; 0.f means
- // that the maximum scale could not be computed.
- EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(child));
- EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(grand_child));
-
- EXPECT_EQ(1.f, GetStartingAnimationScale(grand_parent));
- EXPECT_EQ(1.f, GetStartingAnimationScale(parent));
- EXPECT_EQ(kNotScaled, GetStartingAnimationScale(child));
- EXPECT_EQ(kNotScaled, GetStartingAnimationScale(grand_child));
+ // With nested animated scales, the child will use the parent's maximum
+ // animation scale, without combining the multiple animated scales.
+ EXPECT_EQ(5.f, MaximumAnimationToScreenScale(grand_child));
+ EXPECT_EQ(5.f, MaximumAnimationToScreenScale(child));
+ EXPECT_EQ(5.f, MaximumAnimationToScreenScale(parent));
+ EXPECT_EQ(5.f, MaximumAnimationToScreenScale(grand_parent));
+
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(grand_child));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(child));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(parent));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(grand_parent));
AddAnimatedTransformToAnimation(parent_animation.get(), 1.0,
- TransformOperations(), scale);
+ gfx::TransformOperations(), scale);
UpdateActiveTreeDrawProperties();
// |grand_parent|, |parent|, and |child| have scale-affecting animations.
- EXPECT_EQ(5.f, GetMaximumAnimationScale(grand_parent));
- EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(parent));
- EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(child));
- EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(grand_child));
-
- EXPECT_EQ(1.f, GetStartingAnimationScale(grand_parent));
- EXPECT_EQ(kNotScaled, GetStartingAnimationScale(parent));
- EXPECT_EQ(kNotScaled, GetStartingAnimationScale(child));
- EXPECT_EQ(kNotScaled, GetStartingAnimationScale(grand_child));
+ // For nested scale animations, the child uses the parent's maximum scale
+ // instead of combining them.
+ EXPECT_EQ(5.f, MaximumAnimationToScreenScale(grand_child));
+ EXPECT_EQ(5.f, MaximumAnimationToScreenScale(child));
+ EXPECT_EQ(5.f, MaximumAnimationToScreenScale(parent));
+ EXPECT_EQ(5.f, MaximumAnimationToScreenScale(grand_parent));
+
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(grand_child));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(child));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(parent));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(grand_parent));
grand_parent_animation->AbortKeyframeModelsWithProperty(
TargetProperty::TRANSFORM, false);
@@ -5586,24 +5584,30 @@ TEST_F(DrawPropertiesTest, MaximumAnimationScaleFactor) {
child_animation->AbortKeyframeModelsWithProperty(TargetProperty::TRANSFORM,
false);
- TransformOperations perspective;
+ // Recreate child_animation containing keyframes with perspective.
+ timeline_impl()->DetachAnimation(child_animation);
+ child_animation = Animation::Create(AnimationIdProvider::NextAnimationId());
+ timeline_impl()->AttachAnimation(child_animation);
+ child_animation->AttachElement(child->element_id());
+
+ gfx::TransformOperations perspective;
perspective.AppendPerspective(10.f);
- AddAnimatedTransformToAnimation(child_animation.get(), 1.0,
- TransformOperations(), perspective);
+ AddAnimatedTransformToAnimation(child_animation.get(), 1.0, perspective,
+ perspective);
UpdateActiveTreeDrawProperties();
// |child| has a scale-affecting animation but computing the maximum of this
// animation is not supported.
- EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(grand_parent));
- EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(parent));
- EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(child));
- EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(grand_child));
+ EXPECT_EQ(1.f, MaximumAnimationToScreenScale(grand_child));
+ EXPECT_EQ(1.f, MaximumAnimationToScreenScale(child));
+ EXPECT_EQ(1.f, MaximumAnimationToScreenScale(parent));
+ EXPECT_EQ(1.f, MaximumAnimationToScreenScale(grand_parent));
- EXPECT_EQ(kNotScaled, GetStartingAnimationScale(grand_parent));
- EXPECT_EQ(kNotScaled, GetStartingAnimationScale(parent));
- EXPECT_EQ(kNotScaled, GetStartingAnimationScale(child));
- EXPECT_EQ(kNotScaled, GetStartingAnimationScale(grand_child));
+ EXPECT_TRUE(AnimationAffectedByInvalidScale(grand_child));
+ EXPECT_TRUE(AnimationAffectedByInvalidScale(child));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(parent));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(grand_parent));
child_animation->AbortKeyframeModelsWithProperty(TargetProperty::TRANSFORM,
false);
@@ -5612,70 +5616,88 @@ TEST_F(DrawPropertiesTest, MaximumAnimationScaleFactor) {
scale_matrix.Scale(1.f, 2.f);
SetTransform(grand_parent, scale_matrix);
SetTransform(parent, scale_matrix);
+ SetTransform(child, scale_matrix);
AddAnimatedTransformToAnimation(parent_animation.get(), 1.0,
- TransformOperations(), scale);
+ gfx::TransformOperations(), scale);
UpdateActiveTreeDrawProperties();
- // |grand_parent| and |parent| each have scale 2.f. |parent| has a scale
- // animation with maximum scale 5.f.
- EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(grand_parent));
- EXPECT_EQ(10.f, GetMaximumAnimationScale(parent));
- EXPECT_EQ(10.f, GetMaximumAnimationScale(child));
- EXPECT_EQ(10.f, GetMaximumAnimationScale(grand_child));
+ // |grand_parent|, |parent| and |child| each has scale 2.f. |parent| has a
+ // scale animation with maximum scale 5.f.
+ EXPECT_EQ(20.f, MaximumAnimationToScreenScale(grand_child));
+ EXPECT_EQ(20.f, MaximumAnimationToScreenScale(child));
+ EXPECT_EQ(10.f, MaximumAnimationToScreenScale(parent));
+ EXPECT_EQ(2.f, MaximumAnimationToScreenScale(grand_parent));
- EXPECT_EQ(kNotScaled, GetStartingAnimationScale(grand_parent));
- EXPECT_EQ(2.f, GetStartingAnimationScale(parent));
- EXPECT_EQ(2.f, GetStartingAnimationScale(child));
- EXPECT_EQ(2.f, GetStartingAnimationScale(grand_child));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(grand_child));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(child));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(parent));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(grand_parent));
gfx::Transform perspective_matrix;
perspective_matrix.ApplyPerspectiveDepth(2.f);
SetTransform(child, perspective_matrix);
UpdateActiveTreeDrawProperties();
- // |child| has a transform that's neither a translation nor a scale.
- EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(grand_parent));
- EXPECT_EQ(10.f, GetMaximumAnimationScale(parent));
- EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(child));
- EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(grand_child));
+ // |child| has a transform with perspective. Use |parent|'s maximum animation
+ // scale.
+ EXPECT_EQ(10.f, MaximumAnimationToScreenScale(grand_child));
+ EXPECT_EQ(10.f, MaximumAnimationToScreenScale(child));
+ EXPECT_EQ(10.f, MaximumAnimationToScreenScale(parent));
+ EXPECT_EQ(2.f, MaximumAnimationToScreenScale(grand_parent));
- EXPECT_EQ(kNotScaled, GetStartingAnimationScale(grand_parent));
- EXPECT_EQ(2.f, GetStartingAnimationScale(parent));
- EXPECT_EQ(kNotScaled, GetStartingAnimationScale(child));
- EXPECT_EQ(kNotScaled, GetStartingAnimationScale(grand_child));
+ EXPECT_TRUE(AnimationAffectedByInvalidScale(grand_child));
+ EXPECT_TRUE(AnimationAffectedByInvalidScale(child));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(parent));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(grand_parent));
SetTransform(parent, perspective_matrix);
UpdateActiveTreeDrawProperties();
- // |parent| and |child| have transforms that are neither translations nor
- // scales.
- EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(grand_parent));
- EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(parent));
- EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(child));
- EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(grand_child));
+ // |parent| and |child| have transforms with perspective. Use |grand_parent|'s
+ // maximum animation scale.
+ EXPECT_EQ(2.f, MaximumAnimationToScreenScale(grand_child));
+ EXPECT_EQ(2.f, MaximumAnimationToScreenScale(child));
+ EXPECT_EQ(2.f, MaximumAnimationToScreenScale(parent));
+ EXPECT_EQ(2.f, MaximumAnimationToScreenScale(grand_parent));
- EXPECT_EQ(kNotScaled, GetStartingAnimationScale(grand_parent));
- EXPECT_EQ(kNotScaled, GetStartingAnimationScale(parent));
- EXPECT_EQ(kNotScaled, GetStartingAnimationScale(child));
- EXPECT_EQ(kNotScaled, GetStartingAnimationScale(grand_child));
+ EXPECT_TRUE(AnimationAffectedByInvalidScale(grand_child));
+ EXPECT_TRUE(AnimationAffectedByInvalidScale(child));
+ EXPECT_TRUE(AnimationAffectedByInvalidScale(parent));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(grand_parent));
SetTransform(parent, gfx::Transform());
SetTransform(child, gfx::Transform());
SetTransform(grand_parent, perspective_matrix);
+ UpdateActiveTreeDrawProperties();
+
+ // |grand_parent| has a transform with perspective.
+ EXPECT_EQ(1.f, MaximumAnimationToScreenScale(grand_child));
+ EXPECT_EQ(1.f, MaximumAnimationToScreenScale(child));
+ EXPECT_EQ(1.f, MaximumAnimationToScreenScale(parent));
+ EXPECT_EQ(1.f, MaximumAnimationToScreenScale(grand_parent));
+ EXPECT_TRUE(AnimationAffectedByInvalidScale(grand_child));
+ EXPECT_TRUE(AnimationAffectedByInvalidScale(child));
+ EXPECT_TRUE(AnimationAffectedByInvalidScale(parent));
+ EXPECT_TRUE(AnimationAffectedByInvalidScale(grand_parent));
+
+ gfx::Transform rotation_skew_scale;
+ rotation_skew_scale.Rotate(45.f);
+ rotation_skew_scale.Skew(45.f, 0.f);
+ rotation_skew_scale.Scale(2.f, 1.f);
+ SetTransform(grand_parent, rotation_skew_scale);
UpdateActiveTreeDrawProperties();
- // |grand_parent| has a transform that's neither a translation nor a scale.
- EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(grand_parent));
- EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(parent));
- EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(child));
- EXPECT_EQ(kNotScaled, GetMaximumAnimationScale(grand_child));
+ EXPECT_EQ(10.f, MaximumAnimationToScreenScale(grand_child));
+ EXPECT_EQ(10.f, MaximumAnimationToScreenScale(child));
+ EXPECT_EQ(10.f, MaximumAnimationToScreenScale(parent));
+ EXPECT_EQ(2.f, MaximumAnimationToScreenScale(grand_parent));
- EXPECT_EQ(kNotScaled, GetStartingAnimationScale(grand_parent));
- EXPECT_EQ(kNotScaled, GetStartingAnimationScale(parent));
- EXPECT_EQ(kNotScaled, GetStartingAnimationScale(child));
- EXPECT_EQ(kNotScaled, GetStartingAnimationScale(grand_child));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(grand_child));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(child));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(parent));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(grand_parent));
}
static void GatherDrawnLayers(LayerTreeImpl* tree_impl,
@@ -5919,14 +5941,14 @@ TEST_F(DrawPropertiesTestWithLayerTree, DrawPropertyDeviceScale) {
host()->SetRootLayer(root);
host()->SetElementIdsForTesting();
- TransformOperations scale;
+ gfx::TransformOperations scale;
scale.AppendScale(5.f, 8.f, 3.f);
child2->SetTransform(scale_transform_child2);
child2->SetBounds(gfx::Size(1, 1));
child2->SetIsDrawable(true);
- AddAnimatedTransformToElementWithAnimation(child2->element_id(), timeline(),
- 1.0, TransformOperations(), scale);
+ AddAnimatedTransformToElementWithAnimation(
+ child2->element_id(), timeline(), 1.0, gfx::TransformOperations(), scale);
CommitAndActivate();
@@ -5935,9 +5957,9 @@ TEST_F(DrawPropertiesTestWithLayerTree, DrawPropertyDeviceScale) {
EXPECT_FLOAT_EQ(3.f, ImplOf(mask)->GetIdealContentsScale());
EXPECT_FLOAT_EQ(5.f, ImplOf(child2)->GetIdealContentsScale());
- EXPECT_FLOAT_EQ(kNotScaled, GetMaximumAnimationScale(ImplOf(root)));
- EXPECT_FLOAT_EQ(kNotScaled, GetMaximumAnimationScale(ImplOf(child1)));
- EXPECT_FLOAT_EQ(8.f, GetMaximumAnimationScale(ImplOf(child2)));
+ EXPECT_FLOAT_EQ(8.f, MaximumAnimationToScreenScale(ImplOf(child2)));
+ EXPECT_FLOAT_EQ(3.f, MaximumAnimationToScreenScale(ImplOf(child1)));
+ EXPECT_FLOAT_EQ(1.f, MaximumAnimationToScreenScale(ImplOf(root)));
// Changing device-scale would affect ideal_contents_scale and
// maximum_animation_contents_scale.
@@ -5950,9 +5972,9 @@ TEST_F(DrawPropertiesTestWithLayerTree, DrawPropertyDeviceScale) {
EXPECT_FLOAT_EQ(12.f, ImplOf(mask)->GetIdealContentsScale());
EXPECT_FLOAT_EQ(20.f, ImplOf(child2)->GetIdealContentsScale());
- EXPECT_FLOAT_EQ(kNotScaled, GetMaximumAnimationScale(ImplOf(root)));
- EXPECT_FLOAT_EQ(kNotScaled, GetMaximumAnimationScale(ImplOf(child1)));
- EXPECT_FLOAT_EQ(32.f, GetMaximumAnimationScale(ImplOf(child2)));
+ EXPECT_FLOAT_EQ(32.f, MaximumAnimationToScreenScale(ImplOf(child2)));
+ EXPECT_FLOAT_EQ(12.f, MaximumAnimationToScreenScale(ImplOf(child1)));
+ EXPECT_FLOAT_EQ(4.f, MaximumAnimationToScreenScale(ImplOf(root)));
}
TEST_F(DrawPropertiesTest, DrawPropertyScales) {
@@ -5991,11 +6013,11 @@ TEST_F(DrawPropertiesTest, DrawPropertyScales) {
page_scale->transform_tree_index();
host()->RegisterViewportPropertyIds(viewport_property_ids);
- TransformOperations scale;
+ gfx::TransformOperations scale;
scale.AppendScale(5.f, 8.f, 3.f);
- AddAnimatedTransformToElementWithAnimation(child2->element_id(), timeline(),
- 1.0, TransformOperations(), scale);
+ AddAnimatedTransformToElementWithAnimation(
+ child2->element_id(), timeline(), 1.0, gfx::TransformOperations(), scale);
CommitAndActivate();
@@ -6004,10 +6026,10 @@ TEST_F(DrawPropertiesTest, DrawPropertyScales) {
EXPECT_FLOAT_EQ(3.f, ImplOf(child1)->GetIdealContentsScale());
EXPECT_FLOAT_EQ(5.f, ImplOf(child2)->GetIdealContentsScale());
- EXPECT_FLOAT_EQ(kNotScaled, GetMaximumAnimationScale(ImplOf(root)));
- EXPECT_FLOAT_EQ(kNotScaled, GetMaximumAnimationScale(ImplOf(page_scale)));
- EXPECT_FLOAT_EQ(kNotScaled, GetMaximumAnimationScale(ImplOf(child1)));
- EXPECT_FLOAT_EQ(8.f, GetMaximumAnimationScale(ImplOf(child2)));
+ EXPECT_FLOAT_EQ(8.f, MaximumAnimationToScreenScale(ImplOf(child2)));
+ EXPECT_FLOAT_EQ(3.f, MaximumAnimationToScreenScale(ImplOf(child1)));
+ EXPECT_FLOAT_EQ(1.f, MaximumAnimationToScreenScale(ImplOf(page_scale)));
+ EXPECT_FLOAT_EQ(1.f, MaximumAnimationToScreenScale(ImplOf(root)));
// Changing page-scale would affect ideal_contents_scale and
// maximum_animation_contents_scale.
@@ -6021,10 +6043,10 @@ TEST_F(DrawPropertiesTest, DrawPropertyScales) {
EXPECT_FLOAT_EQ(9.f, ImplOf(child1)->GetIdealContentsScale());
EXPECT_FLOAT_EQ(15.f, ImplOf(child2)->GetIdealContentsScale());
- EXPECT_FLOAT_EQ(kNotScaled, GetMaximumAnimationScale(ImplOf(root)));
- EXPECT_FLOAT_EQ(kNotScaled, GetMaximumAnimationScale(ImplOf(page_scale)));
- EXPECT_FLOAT_EQ(kNotScaled, GetMaximumAnimationScale(ImplOf(child1)));
- EXPECT_FLOAT_EQ(24.f, GetMaximumAnimationScale(ImplOf(child2)));
+ EXPECT_FLOAT_EQ(24.f, MaximumAnimationToScreenScale(ImplOf(child2)));
+ EXPECT_FLOAT_EQ(9.f, MaximumAnimationToScreenScale(ImplOf(child1)));
+ EXPECT_FLOAT_EQ(3.f, MaximumAnimationToScreenScale(ImplOf(page_scale)));
+ EXPECT_FLOAT_EQ(1.f, MaximumAnimationToScreenScale(ImplOf(root)));
// Changing device-scale would affect ideal_contents_scale and
// maximum_animation_contents_scale.
@@ -6037,10 +6059,10 @@ TEST_F(DrawPropertiesTest, DrawPropertyScales) {
EXPECT_FLOAT_EQ(36.f, ImplOf(child1)->GetIdealContentsScale());
EXPECT_FLOAT_EQ(60.f, ImplOf(child2)->GetIdealContentsScale());
- EXPECT_FLOAT_EQ(kNotScaled, GetMaximumAnimationScale(ImplOf(root)));
- EXPECT_FLOAT_EQ(kNotScaled, GetMaximumAnimationScale(ImplOf(page_scale)));
- EXPECT_FLOAT_EQ(kNotScaled, GetMaximumAnimationScale(ImplOf(child1)));
- EXPECT_FLOAT_EQ(96.f, GetMaximumAnimationScale(ImplOf(child2)));
+ EXPECT_FLOAT_EQ(96.f, MaximumAnimationToScreenScale(ImplOf(child2)));
+ EXPECT_FLOAT_EQ(36.f, MaximumAnimationToScreenScale(ImplOf(child1)));
+ EXPECT_FLOAT_EQ(12.f, MaximumAnimationToScreenScale(ImplOf(page_scale)));
+ EXPECT_FLOAT_EQ(4.f, MaximumAnimationToScreenScale(ImplOf(root)));
}
TEST_F(DrawPropertiesTest, AnimationScales) {
@@ -6062,34 +6084,83 @@ TEST_F(DrawPropertiesTest, AnimationScales) {
CopyProperties(child1, child2);
CreateTransformNode(child2).local = scale_transform_child2;
- TransformOperations scale;
+ gfx::TransformOperations scale;
scale.AppendScale(5.f, 8.f, 3.f);
- AddAnimatedTransformToElementWithAnimation(
- child2->element_id(), timeline_impl(), 1.0, TransformOperations(), scale);
+ AddAnimatedTransformToElementWithAnimation(child2->element_id(),
+ timeline_impl(), 1.0,
+ gfx::TransformOperations(), scale);
UpdateActiveTreeDrawProperties();
- EXPECT_FLOAT_EQ(kNotScaled, GetMaximumAnimationScale(root));
- EXPECT_FLOAT_EQ(kNotScaled, GetMaximumAnimationScale(child1));
- EXPECT_FLOAT_EQ(24.f, GetMaximumAnimationScale(child2));
-
- EXPECT_FLOAT_EQ(kNotScaled, GetStartingAnimationScale(root));
- EXPECT_FLOAT_EQ(kNotScaled, GetStartingAnimationScale(child1));
- EXPECT_FLOAT_EQ(3.f, GetStartingAnimationScale(child2));
+ EXPECT_FLOAT_EQ(24.f, MaximumAnimationToScreenScale(child2));
+ EXPECT_FLOAT_EQ(3.f, MaximumAnimationToScreenScale(child1));
+ EXPECT_FLOAT_EQ(1.f, MaximumAnimationToScreenScale(root));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(child2));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(child1));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(root));
// Correctly updates animation scale when layer property changes.
SetTransform(child1, gfx::Transform());
root->layer_tree_impl()->SetTransformMutated(child1->element_id(),
gfx::Transform());
UpdateActiveTreeDrawProperties();
- EXPECT_FLOAT_EQ(8.f, GetMaximumAnimationScale(child2));
- EXPECT_FLOAT_EQ(1.f, GetStartingAnimationScale(child2));
+ EXPECT_FLOAT_EQ(8.f, MaximumAnimationToScreenScale(child2));
// Do not update animation scale if already updated.
- host_impl()->active_tree()->property_trees()->SetAnimationScalesForTesting(
- child2->transform_tree_index(), 100.f, 100.f);
- EXPECT_FLOAT_EQ(100.f, GetMaximumAnimationScale(child2));
- EXPECT_FLOAT_EQ(100.f, GetStartingAnimationScale(child2));
+ bool affected_by_invalid_scale = true;
+ host_impl()
+ ->active_tree()
+ ->property_trees()
+ ->SetMaximumAnimationToScreenScaleForTesting(
+ child2->transform_tree_index(), 100.f, affected_by_invalid_scale);
+ EXPECT_FLOAT_EQ(100.f, MaximumAnimationToScreenScale(child2));
+ EXPECT_TRUE(AnimationAffectedByInvalidScale(child2));
+}
+
+TEST_F(DrawPropertiesTest, AnimationScaleFromSmallToOne) {
+ LayerImpl* root = root_layer();
+ root->SetBounds(gfx::Size(1, 1));
+ auto* parent = AddLayer<LayerImpl>();
+ parent->SetBounds(gfx::Size(1, 1));
+ auto* child = AddLayer<LayerImpl>();
+ child->SetBounds(gfx::Size(1, 1));
+ auto* grandchild = AddLayer<LayerImpl>();
+ grandchild->SetBounds(gfx::Size(1, 1));
+ SetElementIdsForTesting();
+
+ gfx::Transform parent_scale;
+ parent_scale.Scale(1, 2);
+ gfx::Transform small_scale;
+ small_scale.Scale(0.1, 0.2);
+
+ CopyProperties(root, parent);
+ CreateTransformNode(parent).local = parent_scale;
+ CopyProperties(parent, child);
+ CreateTransformNode(child).local = small_scale;
+ CopyProperties(child, grandchild);
+ CreateTransformNode(grandchild).local = small_scale;
+
+ gfx::TransformOperations small_scale_operations;
+ small_scale_operations.AppendMatrix(small_scale);
+ gfx::TransformOperations scale_one_operations;
+
+ // Both child and grandchild animate scale from 0.1x0.2 to 1.
+ AddAnimatedTransformToElementWithAnimation(
+ child->element_id(), timeline_impl(), 1.0, small_scale_operations,
+ scale_one_operations);
+ AddAnimatedTransformToElementWithAnimation(
+ grandchild->element_id(), timeline_impl(), 1.0, small_scale_operations,
+ scale_one_operations);
+ UpdateActiveTreeDrawProperties();
+
+ EXPECT_FLOAT_EQ(2.f, MaximumAnimationToScreenScale(grandchild));
+ EXPECT_FLOAT_EQ(2.f, MaximumAnimationToScreenScale(child));
+ EXPECT_FLOAT_EQ(2.f, MaximumAnimationToScreenScale(parent));
+ EXPECT_FLOAT_EQ(1.f, MaximumAnimationToScreenScale(root));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(grandchild));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(child));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(parent));
+ EXPECT_FALSE(AnimationAffectedByInvalidScale(root));
}
TEST_F(DrawPropertiesTest, VisibleContentRectInChildRenderSurface) {
@@ -6213,9 +6284,9 @@ TEST_F(DrawPropertiesTest,
CreateEffectNode(surface).render_surface_reason = RenderSurfaceReason::kTest;
CopyProperties(surface, descendant_of_keyframe_model);
- TransformOperations start_transform_operations;
+ gfx::TransformOperations start_transform_operations;
start_transform_operations.AppendMatrix(uninvertible_matrix);
- TransformOperations end_transform_operations;
+ gfx::TransformOperations end_transform_operations;
AddAnimatedTransformToElementWithAnimation(
animated->element_id(), timeline_impl(), 10.0, start_transform_operations,
@@ -6409,8 +6480,9 @@ TEST_F(DrawPropertiesTestWithLayerTree, SkippingSubtreeMain) {
// a singular transform, the subtree should still get processed.
int keyframe_model_id = 0;
std::unique_ptr<KeyframeModel> keyframe_model = KeyframeModel::Create(
- std::unique_ptr<AnimationCurve>(new FakeTransformTransition(1.0)),
- keyframe_model_id, 1, TargetProperty::TRANSFORM);
+ std::unique_ptr<gfx::AnimationCurve>(new FakeTransformTransition(1.0)),
+ keyframe_model_id, 1,
+ KeyframeModel::TargetPropertyId(TargetProperty::TRANSFORM));
keyframe_model->set_fill_mode(KeyframeModel::FillMode::NONE);
keyframe_model->set_time_offset(base::TimeDelta::FromMilliseconds(-1000));
AddKeyframeModelToElementWithAnimation(child->element_id(), timeline(),
@@ -6436,8 +6508,10 @@ TEST_F(DrawPropertiesTestWithLayerTree, SkippingSubtreeMain) {
// Add an opacity animation with a start delay.
keyframe_model_id = 1;
keyframe_model = KeyframeModel::Create(
- std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)),
- keyframe_model_id, 1, TargetProperty::OPACITY);
+ std::unique_ptr<gfx::AnimationCurve>(
+ new FakeFloatTransition(1.0, 0.f, 1.f)),
+ keyframe_model_id, 1,
+ KeyframeModel::TargetPropertyId(TargetProperty::OPACITY));
keyframe_model->set_fill_mode(KeyframeModel::FillMode::NONE);
keyframe_model->set_time_offset(base::TimeDelta::FromMilliseconds(-1000));
AddKeyframeModelToElementWithExistingKeyframeEffect(
@@ -6543,20 +6617,21 @@ TEST_F(DrawPropertiesTestWithLayerTree, SkippingLayerImpl) {
EXPECT_EQ(gfx::Rect(10, 10), ImplOf(grandchild)->visible_layer_rect());
child->SetTransform(gfx::Transform());
- std::unique_ptr<KeyframedTransformAnimationCurve> curve(
- KeyframedTransformAnimationCurve::Create());
- TransformOperations start;
+ std::unique_ptr<gfx::KeyframedTransformAnimationCurve> curve(
+ gfx::KeyframedTransformAnimationCurve::Create());
+ gfx::TransformOperations start;
start.AppendTranslate(1.f, 2.f, 3.f);
gfx::Transform transform;
transform.Scale3d(1.0, 2.0, 3.0);
- TransformOperations operation;
+ gfx::TransformOperations operation;
operation.AppendMatrix(transform);
curve->AddKeyframe(
- TransformKeyframe::Create(base::TimeDelta(), start, nullptr));
- curve->AddKeyframe(TransformKeyframe::Create(
+ gfx::TransformKeyframe::Create(base::TimeDelta(), start, nullptr));
+ curve->AddKeyframe(gfx::TransformKeyframe::Create(
base::TimeDelta::FromSecondsD(1.0), operation, nullptr));
- std::unique_ptr<KeyframeModel> transform_animation(
- KeyframeModel::Create(std::move(curve), 3, 3, TargetProperty::TRANSFORM));
+ std::unique_ptr<KeyframeModel> transform_animation(KeyframeModel::Create(
+ std::move(curve), 3, 3,
+ KeyframeModel::TargetPropertyId(TargetProperty::TRANSFORM)));
scoped_refptr<Animation> animation(Animation::Create(1));
timeline()->AttachAnimation(animation);
animation->AttachElement(parent->element_id());
@@ -6575,20 +6650,21 @@ TEST_F(DrawPropertiesTestWithLayerTree, SkippingLayerImpl) {
// compositor without recomputing the trees.
TEST_F(DrawPropertiesTest, LayerSkippingInSubtreeOfSingularTransform) {
// Set up a transform animation
- std::unique_ptr<KeyframedTransformAnimationCurve> curve(
- KeyframedTransformAnimationCurve::Create());
- TransformOperations start;
+ std::unique_ptr<gfx::KeyframedTransformAnimationCurve> curve(
+ gfx::KeyframedTransformAnimationCurve::Create());
+ gfx::TransformOperations start;
start.AppendTranslate(1.f, 2.f, 3.f);
gfx::Transform transform;
transform.Scale3d(1.0, 2.0, 3.0);
- TransformOperations operation;
+ gfx::TransformOperations operation;
operation.AppendMatrix(transform);
curve->AddKeyframe(
- TransformKeyframe::Create(base::TimeDelta(), start, nullptr));
- curve->AddKeyframe(TransformKeyframe::Create(
+ gfx::TransformKeyframe::Create(base::TimeDelta(), start, nullptr));
+ curve->AddKeyframe(gfx::TransformKeyframe::Create(
base::TimeDelta::FromSecondsD(1.0), operation, nullptr));
- std::unique_ptr<KeyframeModel> transform_animation(
- KeyframeModel::Create(std::move(curve), 3, 3, TargetProperty::TRANSFORM));
+ std::unique_ptr<KeyframeModel> transform_animation(KeyframeModel::Create(
+ std::move(curve), 3, 3,
+ KeyframeModel::TargetPropertyId(TargetProperty::TRANSFORM)));
scoped_refptr<Animation> animation(Animation::Create(1));
timeline_impl()->AttachAnimation(animation);
animation->AddKeyframeModel(std::move(transform_animation));
@@ -6690,17 +6766,18 @@ TEST_F(DrawPropertiesTestWithLayerTree, SkippingPendingLayerImpl) {
EXPECT_EQ(gfx::Rect(), PendingImplOf(grandchild)->visible_layer_rect());
// Check the animated case is not skipped.
- std::unique_ptr<KeyframedFloatAnimationCurve> curve(
- KeyframedFloatAnimationCurve::Create());
- std::unique_ptr<TimingFunction> func =
- CubicBezierTimingFunction::CreatePreset(
- CubicBezierTimingFunction::EaseType::EASE);
- curve->AddKeyframe(
- FloatKeyframe::Create(base::TimeDelta(), 0.9f, std::move(func)));
+ std::unique_ptr<gfx::KeyframedFloatAnimationCurve> curve(
+ gfx::KeyframedFloatAnimationCurve::Create());
+ std::unique_ptr<gfx::TimingFunction> func =
+ gfx::CubicBezierTimingFunction::CreatePreset(
+ gfx::CubicBezierTimingFunction::EaseType::EASE);
curve->AddKeyframe(
- FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 0.3f, nullptr));
- std::unique_ptr<KeyframeModel> keyframe_model(
- KeyframeModel::Create(std::move(curve), 3, 3, TargetProperty::OPACITY));
+ gfx::FloatKeyframe::Create(base::TimeDelta(), 0.9f, std::move(func)));
+ curve->AddKeyframe(gfx::FloatKeyframe::Create(
+ base::TimeDelta::FromSecondsD(1.0), 0.3f, nullptr));
+ std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create(
+ std::move(curve), 3, 3,
+ KeyframeModel::TargetPropertyId(TargetProperty::OPACITY)));
scoped_refptr<Animation> animation(Animation::Create(1));
timeline()->AttachAnimation(animation);
animation->AddKeyframeModel(std::move(keyframe_model));
@@ -7504,8 +7581,10 @@ TEST_F(DrawPropertiesTestWithLayerTree, OpacityAnimationsTrackingTest) {
int keyframe_model_id = 0;
std::unique_ptr<KeyframeModel> keyframe_model = KeyframeModel::Create(
- std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)),
- keyframe_model_id, 1, TargetProperty::OPACITY);
+ std::unique_ptr<gfx::AnimationCurve>(
+ new FakeFloatTransition(1.0, 0.f, 1.f)),
+ keyframe_model_id, 1,
+ KeyframeModel::TargetPropertyId(TargetProperty::OPACITY));
keyframe_model->set_fill_mode(KeyframeModel::FillMode::NONE);
keyframe_model->set_time_offset(base::TimeDelta::FromMilliseconds(-1000));
KeyframeModel* keyframe_model_ptr = keyframe_model.get();
@@ -7549,20 +7628,21 @@ TEST_F(DrawPropertiesTestWithLayerTree, TransformAnimationsTrackingTest) {
timeline()->AttachAnimation(animation);
animation->AttachElement(animated->element_id());
- std::unique_ptr<KeyframedTransformAnimationCurve> curve(
- KeyframedTransformAnimationCurve::Create());
- TransformOperations start;
+ std::unique_ptr<gfx::KeyframedTransformAnimationCurve> curve(
+ gfx::KeyframedTransformAnimationCurve::Create());
+ gfx::TransformOperations start;
start.AppendTranslate(1.f, 2.f, 3.f);
gfx::Transform transform;
transform.Scale3d(1.0, 2.0, 3.0);
- TransformOperations operation;
+ gfx::TransformOperations operation;
operation.AppendMatrix(transform);
curve->AddKeyframe(
- TransformKeyframe::Create(base::TimeDelta(), start, nullptr));
- curve->AddKeyframe(TransformKeyframe::Create(
+ gfx::TransformKeyframe::Create(base::TimeDelta(), start, nullptr));
+ curve->AddKeyframe(gfx::TransformKeyframe::Create(
base::TimeDelta::FromSecondsD(1.0), operation, nullptr));
- std::unique_ptr<KeyframeModel> keyframe_model(
- KeyframeModel::Create(std::move(curve), 3, 3, TargetProperty::TRANSFORM));
+ std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create(
+ std::move(curve), 3, 3,
+ KeyframeModel::TargetPropertyId(TargetProperty::TRANSFORM)));
keyframe_model->set_fill_mode(KeyframeModel::FillMode::NONE);
keyframe_model->set_time_offset(base::TimeDelta::FromMilliseconds(-1000));
KeyframeModel* keyframe_model_ptr = keyframe_model.get();
diff --git a/chromium/cc/trees/draw_property_utils.cc b/chromium/cc/trees/draw_property_utils.cc
index c2e79fc3b7e..aa4433edce3 100644
--- a/chromium/cc/trees/draw_property_utils.cc
+++ b/chromium/cc/trees/draw_property_utils.cc
@@ -640,19 +640,20 @@ void SetSurfaceDrawTransform(const PropertyTrees* property_trees,
gfx::Rect LayerVisibleRect(PropertyTrees* property_trees, LayerImpl* layer) {
const EffectNode* effect_node =
property_trees->effect_tree.Node(layer->effect_tree_index());
- int effect_ancestor_with_cache_render_surface =
- effect_node->closest_ancestor_with_cached_render_surface_id;
- int effect_ancestor_with_copy_request =
- effect_node->closest_ancestor_with_copy_request_id;
int lower_effect_closest_ancestor =
- std::max(effect_ancestor_with_cache_render_surface,
- effect_ancestor_with_copy_request);
- bool non_root_copy_request_or_cache_render_surface =
+ effect_node->closest_ancestor_with_cached_render_surface_id;
+ lower_effect_closest_ancestor =
+ std::max(lower_effect_closest_ancestor,
+ effect_node->closest_ancestor_with_copy_request_id);
+ lower_effect_closest_ancestor =
+ std::max(lower_effect_closest_ancestor,
+ effect_node->closest_ancestor_being_captured_id);
+ const bool non_root_with_render_surface =
lower_effect_closest_ancestor > EffectTree::kContentsRootNodeId;
gfx::Rect layer_content_rect = gfx::Rect(layer->bounds());
gfx::RectF accumulated_clip_in_root_space;
- if (non_root_copy_request_or_cache_render_surface) {
+ if (non_root_with_render_surface) {
bool include_expanding_clips = true;
ConditionalClip accumulated_clip = ComputeAccumulatedClip(
property_trees, include_expanding_clips, layer->clip_tree_index(),
@@ -668,7 +669,7 @@ gfx::Rect LayerVisibleRect(PropertyTrees* property_trees, LayerImpl* layer) {
}
const EffectNode* root_effect_node =
- non_root_copy_request_or_cache_render_surface
+ non_root_with_render_surface
? property_trees->effect_tree.Node(lower_effect_closest_ancestor)
: property_trees->effect_tree.Node(EffectTree::kContentsRootNodeId);
ConditionalClip accumulated_clip_in_layer_space =
@@ -890,8 +891,7 @@ void AddSurfaceToRenderSurfaceList(RenderSurfaceImpl* render_surface,
// TODO(senorblanco): make this smarter for the SkImageFilter case (check for
// pixel-moving filters)
const FilterOperations& filters = render_surface->Filters();
- bool is_occlusion_immune = render_surface->HasCopyRequest() ||
- render_surface->ShouldCacheRenderSurface() ||
+ bool is_occlusion_immune = render_surface->CopyOfOutputRequired() ||
filters.HasReferenceFilter() ||
filters.HasFilterThatMovesPixels();
if (is_occlusion_immune) {
@@ -1225,9 +1225,11 @@ bool CC_EXPORT LayerShouldBeSkippedForDrawPropertiesComputation(
if (effect_node->HasRenderSurface() && effect_node->subtree_has_copy_request)
return false;
- // Skip if the node's subtree is hidden and no need to cache.
- if (effect_node->subtree_hidden && !effect_node->cache_render_surface)
+ // Skip if the node's subtree is hidden and no need to cache, or capture.
+ if (effect_node->subtree_hidden && !effect_node->cache_render_surface &&
+ !effect_node->subtree_capture_id.is_valid()) {
return true;
+ }
// If the layer transform is not invertible, it should be skipped. In case the
// transform is animating and singular, we should not skip it.
diff --git a/chromium/cc/trees/effect_node.cc b/chromium/cc/trees/effect_node.cc
index fa07fea5b79..20b4257603f 100644
--- a/chromium/cc/trees/effect_node.cc
+++ b/chromium/cc/trees/effect_node.cc
@@ -42,7 +42,8 @@ EffectNode::EffectNode()
clip_id(0),
target_id(1),
closest_ancestor_with_cached_render_surface_id(-1),
- closest_ancestor_with_copy_request_id(-1) {}
+ closest_ancestor_with_copy_request_id(-1),
+ closest_ancestor_being_captured_id(-1) {}
EffectNode::EffectNode(const EffectNode& other) = default;
@@ -54,6 +55,7 @@ bool EffectNode::operator==(const EffectNode& other) const {
stable_id == other.stable_id && opacity == other.opacity &&
screen_space_opacity == other.screen_space_opacity &&
backdrop_filter_quality == other.backdrop_filter_quality &&
+ subtree_capture_id == other.subtree_capture_id &&
cache_render_surface == other.cache_render_surface &&
has_copy_request == other.has_copy_request &&
filters == other.filters &&
@@ -94,7 +96,9 @@ bool EffectNode::operator==(const EffectNode& other) const {
closest_ancestor_with_cached_render_surface_id ==
other.closest_ancestor_with_cached_render_surface_id &&
closest_ancestor_with_copy_request_id ==
- other.closest_ancestor_with_copy_request_id;
+ other.closest_ancestor_with_copy_request_id &&
+ closest_ancestor_being_captured_id ==
+ other.closest_ancestor_being_captured_id;
}
#endif // DCHECK_IS_ON()
@@ -138,6 +142,10 @@ const char* RenderSurfaceReasonToString(RenderSurfaceReason reason) {
return "cache";
case RenderSurfaceReason::kCopyRequest:
return "copy request";
+ case RenderSurfaceReason::kMirrored:
+ return "mirrored";
+ case RenderSurfaceReason::kSubtreeIsBeingCaptured:
+ return "subtree being captured";
case RenderSurfaceReason::kTest:
return "test";
default:
@@ -172,6 +180,7 @@ void EffectNode::AsValueInto(base::trace_event::TracedValue* value) const {
}
}
value->SetString("blend_mode", SkBlendMode_Name(blend_mode));
+ value->SetString("subtree_capture_id", subtree_capture_id.ToString());
value->SetBoolean("cache_render_surface", cache_render_surface);
value->SetBoolean("has_copy_request", has_copy_request);
value->SetBoolean("double_sided", double_sided);
@@ -198,6 +207,8 @@ void EffectNode::AsValueInto(base::trace_event::TracedValue* value) const {
closest_ancestor_with_cached_render_surface_id);
value->SetInteger("closest_ancestor_with_copy_request_id",
closest_ancestor_with_copy_request_id);
+ value->SetInteger("closest_ancestor_being_captured_id",
+ closest_ancestor_being_captured_id);
value->SetBoolean("affected_by_backdrop_filter", affected_by_backdrop_filter);
}
diff --git a/chromium/cc/trees/effect_node.h b/chromium/cc/trees/effect_node.h
index 2a2541d123d..65edbca03b1 100644
--- a/chromium/cc/trees/effect_node.h
+++ b/chromium/cc/trees/effect_node.h
@@ -8,6 +8,7 @@
#include "cc/cc_export.h"
#include "cc/paint/element_id.h"
#include "cc/paint/filter_operations.h"
+#include "components/viz/common/surfaces/subtree_capture_id.h"
#include "third_party/skia/include/core/SkBlendMode.h"
#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/geometry/size_f.h"
@@ -44,6 +45,7 @@ enum class RenderSurfaceReason : uint8_t {
kCache,
kCopyRequest,
kMirrored,
+ kSubtreeIsBeingCaptured,
// This must be the last value because it's used in tracing code to know the
// number of reasons.
kTest,
@@ -90,6 +92,8 @@ struct CC_EXPORT EffectNode {
gfx::Vector2dF surface_contents_scale;
+ viz::SubtreeCaptureId subtree_capture_id;
+
bool cache_render_surface : 1;
bool has_copy_request : 1;
bool hidden_by_backface_visibility : 1;
@@ -154,6 +158,7 @@ struct CC_EXPORT EffectNode {
int target_id;
int closest_ancestor_with_cached_render_surface_id;
int closest_ancestor_with_copy_request_id;
+ int closest_ancestor_being_captured_id;
bool HasRenderSurface() const {
return render_surface_reason != RenderSurfaceReason::kNone;
diff --git a/chromium/cc/trees/image_animation_controller.cc b/chromium/cc/trees/image_animation_controller.cc
index bfb3f30cc30..9ea34f94547 100644
--- a/chromium/cc/trees/image_animation_controller.cc
+++ b/chromium/cc/trees/image_animation_controller.cc
@@ -10,6 +10,7 @@
#include "base/bind.h"
#include "base/metrics/histogram_macros.h"
#include "base/trace_event/trace_event.h"
+#include "cc/base/features.h"
#include "cc/paint/image_animation_count.h"
namespace cc {
@@ -41,7 +42,9 @@ ImageAnimationController::ImageAnimationController(
Client* client,
bool enable_image_animation_resync)
: scheduler_(task_runner, client),
- enable_image_animation_resync_(enable_image_animation_resync) {}
+ enable_image_animation_resync_(enable_image_animation_resync),
+ use_resume_behavior_(
+ base::FeatureList::IsEnabled(features::kAnimatedImageResume)) {}
ImageAnimationController::~ImageAnimationController() = default;
@@ -96,7 +99,8 @@ const PaintImageIdFlatSet& ImageAnimationController::AnimateForSyncTree(
// If we were able to advance this animation, invalidate it on the sync
// tree.
- if (state.AdvanceFrame(args, enable_image_animation_resync_))
+ if (state.AdvanceFrame(args, enable_image_animation_resync_,
+ use_resume_behavior_))
images_animated_on_sync_tree_.insert(id);
TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
@@ -225,7 +229,14 @@ ImageAnimationController::AnimationState::~AnimationState() {
}
bool ImageAnimationController::AnimationState::ShouldAnimate() const {
- DCHECK(repetitions_completed_ == 0 || is_complete());
+ return ShouldAnimate(current_state_.repetitions_completed,
+ current_state_.pending_index);
+}
+
+bool ImageAnimationController::AnimationState::ShouldAnimate(
+ int repetitions_completed,
+ size_t pending_index) const {
+ DCHECK(current_state_.repetitions_completed == 0 || is_complete());
// If we have no drivers for this image, no need to animate it.
if (!should_animate_from_drivers_)
@@ -233,7 +244,7 @@ bool ImageAnimationController::AnimationState::ShouldAnimate() const {
switch (requested_repetitions_) {
case kAnimationLoopOnce:
- if (repetitions_completed_ >= 1)
+ if (repetitions_completed >= 1)
return false;
break;
case kAnimationNone:
@@ -242,20 +253,20 @@ bool ImageAnimationController::AnimationState::ShouldAnimate() const {
case kAnimationLoopInfinite:
break;
default:
- if (requested_repetitions_ <= repetitions_completed_)
+ if (requested_repetitions_ <= repetitions_completed)
return false;
}
// If we have not yet received all data for this image, we can not advance to
// an incomplete frame.
- if (!frames_[NextFrameIndex()].complete)
+ if (!frames_[NextFrameIndex(pending_index)].complete)
return false;
// If we don't have all data for this image, we can not trust the frame count
// and loop back to the first frame.
size_t last_frame_index = frames_.size() - 1;
if (completion_state_ != PaintImage::CompletionState::DONE &&
- pending_index_ == last_frame_index) {
+ pending_index == last_frame_index) {
return false;
}
@@ -274,25 +285,28 @@ bool ImageAnimationController::AnimationState::ShouldAnimate() const {
// the frame should be displayed.
bool ImageAnimationController::AnimationState::AdvanceFrame(
const viz::BeginFrameArgs& args,
- bool enable_image_animation_resync) {
- DCHECK(ShouldAnimate());
+ bool enable_image_animation_resync,
+ bool use_resume_behavior) {
+ DCHECK(ShouldAnimate(current_state_.repetitions_completed,
+ current_state_.pending_index));
const base::TimeTicks next_tick_time = args.frame_time + args.interval;
// Start the animation from the first frame, if not yet started. The code
// falls through to catching up if the duration for the first frame is less
// than the interval.
if (!animation_started_) {
- DCHECK_EQ(pending_index_, 0u);
+ DCHECK_EQ(current_state_.pending_index, 0u);
animation_started_time_ = args.frame_time;
- next_desired_frame_time_ = args.frame_time + frames_[0].duration;
- next_desired_tick_time_ =
- SnappedTickTimeFromFrameTime(args, next_desired_frame_time_);
+ current_state_.next_desired_frame_time =
+ args.frame_time + frames_[0].duration;
+ current_state_.next_desired_tick_time = SnappedTickTimeFromFrameTime(
+ args, current_state_.next_desired_frame_time);
animation_started_ = true;
}
// Don't advance the animation if its not time yet to move to the next frame.
- if (args.frame_time < next_desired_tick_time_)
+ if (args.frame_time < current_state_.next_desired_tick_time)
return needs_invalidation();
// If the animation is more than 5 min out of date, we don't bother catching
@@ -300,35 +314,70 @@ bool ImageAnimationController::AnimationState::AdvanceFrame(
// Note that we don't need to invalidate this image since the active tree
// is already displaying the current frame.
if (enable_image_animation_resync &&
- args.frame_time - next_desired_frame_time_ > kAnimationResyncCutoff) {
+ args.frame_time - current_state_.next_desired_frame_time >
+ kAnimationResyncCutoff) {
TRACE_EVENT_INSTANT0("cc", "Resync - early out", TRACE_EVENT_SCOPE_THREAD);
- DCHECK_EQ(pending_index_, active_index_);
- next_desired_frame_time_ =
- args.frame_time + frames_[pending_index_].duration;
- next_desired_tick_time_ =
- std::max(SnappedTickTimeFromFrameTime(args, next_desired_frame_time_),
+ DCHECK_EQ(current_state_.pending_index, active_index_);
+ current_state_.next_desired_frame_time =
+ args.frame_time + frames_[current_state_.pending_index].duration;
+ current_state_.next_desired_tick_time =
+ std::max(SnappedTickTimeFromFrameTime(
+ args, current_state_.next_desired_frame_time),
next_tick_time);
return needs_invalidation();
}
- // Keep catching up the animation until we reach the frame we should be
- // displaying now.
- const size_t last_frame_index = frames_.size() - 1;
- size_t num_of_frames_advanced = 0u;
- while (next_desired_tick_time_ < next_tick_time && ShouldAnimate()) {
- num_of_frames_advanced++;
- size_t next_frame_index = NextFrameIndex();
+ current_state_.num_of_frames_advanced = 0u;
+ if (use_resume_behavior) {
+ // When using the resume method, run the animation advancement starting
+ // at the current frame time rather than the saved tick time.
+
+ // Advance only as many frames as would fit in the display rate.
+ // IE if the display refresh rate is 60 Hz and the animated image updated
+ // every 11 ms, we could have a display frame that spans 2 animation
+ // frames.
+ current_state_ = AdvanceAnimationState(
+ current_state_, args, args.frame_time, enable_image_animation_resync);
+ } else {
+ // Keep catching up the animation from the last saved tick time until we
+ // reach the frame we should be displaying now.
+ current_state_ = AdvanceAnimationState(
+ current_state_, args, current_state_.next_desired_tick_time,
+ enable_image_animation_resync);
+ }
+ DCHECK_GE(current_state_.num_of_frames_advanced, 1u);
+ last_num_frames_skipped_ = current_state_.num_of_frames_advanced - 1u;
+
+ return needs_invalidation();
+}
+
+ImageAnimationController::AnimationState::AnimationAdvancementState
+ImageAnimationController::AnimationState::AdvanceAnimationState(
+ AnimationAdvancementState animation_advancement_state,
+ const viz::BeginFrameArgs& args,
+ base::TimeTicks start,
+ bool enable_image_animation_resync) const {
+ const base::TimeTicks end = args.frame_time + args.interval;
+ base::TimeTicks elapsed_time = start;
+ while (elapsed_time < end &&
+ ShouldAnimate(animation_advancement_state.repetitions_completed,
+ animation_advancement_state.pending_index)) {
+ animation_advancement_state.num_of_frames_advanced++;
+ size_t next_frame_index =
+ NextFrameIndex(animation_advancement_state.pending_index);
+ elapsed_time += frames_[next_frame_index].duration;
TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
- "FrameDurationAndIndex", TRACE_EVENT_SCOPE_THREAD,
+ "FrameDurationIndex", TRACE_EVENT_SCOPE_THREAD,
"frame_index", next_frame_index, "duration",
frames_[next_frame_index].duration.InMillisecondsF());
base::TimeTicks next_desired_frame_time =
- next_desired_frame_time_ + frames_[next_frame_index].duration;
+ animation_advancement_state.next_desired_frame_time +
+ frames_[next_frame_index].duration;
// The image may load more slowly than it's supposed to animate, so that by
// the time we reach the end of the first repetition, we're well behind.
// Start the animation from the first frame in this case, so that we don't
- // skip frames (or whole iterations) trying to "catch up". This is a
+ // skip frames (or whole iterations) trying to "catch up". This is a
// tradeoff: It guarantees users see the whole animation the second time
// through and don't miss any repetitions, and is closer to what other
// browsers do; on the other hand, it makes animations "less accurate" for
@@ -336,55 +385,62 @@ bool ImageAnimationController::AnimationState::AdvanceFrame(
// especially if users switch tabs (and thus stop drawing the animation,
// which will pause it) during that initial loop, then switch back later.
if (enable_image_animation_resync && next_frame_index == 0u &&
- repetitions_completed_ == 1 &&
+ animation_advancement_state.repetitions_completed == 1 &&
next_desired_frame_time <= args.frame_time) {
- pending_index_ = 0u;
- next_desired_frame_time_ = args.frame_time + frames_[0].duration;
- next_desired_tick_time_ =
- std::max(SnappedTickTimeFromFrameTime(args, next_desired_frame_time_),
- next_tick_time);
- repetitions_completed_ = 0;
+ animation_advancement_state.pending_index = 0u;
+ animation_advancement_state.next_desired_frame_time =
+ args.frame_time + frames_[0].duration;
+ animation_advancement_state.next_desired_tick_time = std::max(
+ SnappedTickTimeFromFrameTime(
+ args, animation_advancement_state.next_desired_frame_time),
+ end);
+ animation_advancement_state.repetitions_completed = 0;
break;
}
- pending_index_ = next_frame_index;
- next_desired_frame_time_ = next_desired_frame_time;
- next_desired_tick_time_ =
- SnappedTickTimeFromFrameTime(args, next_desired_frame_time_);
+ animation_advancement_state.pending_index = next_frame_index;
+ animation_advancement_state.next_desired_frame_time =
+ next_desired_frame_time;
+ animation_advancement_state.next_desired_tick_time =
+ SnappedTickTimeFromFrameTime(
+ args, animation_advancement_state.next_desired_frame_time);
// If we are advancing to the last frame and the image has been completely
// loaded (which means that the frame count is known to be accurate), we
// just finished a loop in the animation.
- if (pending_index_ == last_frame_index && is_complete())
- repetitions_completed_++;
+ if (animation_advancement_state.pending_index == frames_.size() - 1 &&
+ is_complete())
+ animation_advancement_state.repetitions_completed++;
}
// We should have advanced a single frame, anything more than that are frames
// skipped trying to catch up.
- DCHECK_GT(num_of_frames_advanced, 0u);
- last_num_frames_skipped_ = num_of_frames_advanced - 1u;
- switch (repetitions_completed_) {
+ DCHECK_GT(animation_advancement_state.num_of_frames_advanced, 0u);
+ size_t frames_skipped =
+ animation_advancement_state.num_of_frames_advanced - 1u;
+ switch (animation_advancement_state.repetitions_completed) {
case 0:
UMA_HISTOGRAM_COUNTS_100000(
"AnimatedImage.NumOfFramesSkipped.FirstAnimationLoop",
- last_num_frames_skipped_);
+ frames_skipped);
break;
case 1:
UMA_HISTOGRAM_COUNTS_100000(
"AnimatedImage.NumOfFramesSkipped.SecondAnimationLoop",
- last_num_frames_skipped_);
+ frames_skipped);
break;
case 2:
case 3:
case 4:
UMA_HISTOGRAM_COUNTS_100000(
"AnimatedImage.NumOfFramesSkipped.ThirdToFifthAnimationLoop",
- last_num_frames_skipped_);
+ frames_skipped);
break;
}
UMA_HISTOGRAM_COUNTS_100000("AnimatedImage.NumOfFramesSkipped.Compositor",
- last_num_frames_skipped_);
- return needs_invalidation();
+ frames_skipped);
+
+ return animation_advancement_state;
}
void ImageAnimationController::AnimationState::UpdateMetadata(
@@ -408,9 +464,9 @@ void ImageAnimationController::AnimationState::UpdateMetadata(
// Update the repetition count in case we have displayed the last frame and
// we now know the frame count to be accurate.
size_t last_frame_index = frames_.size() - 1;
- if (pending_index_ == last_frame_index && is_complete() &&
- repetitions_completed_ == 0)
- repetitions_completed_++;
+ if (current_state_.pending_index == last_frame_index && is_complete() &&
+ current_state_.repetitions_completed == 0)
+ current_state_.repetitions_completed++;
// Reset the animation if the sequence id received in this recording was
// incremented.
@@ -421,7 +477,7 @@ void ImageAnimationController::AnimationState::UpdateMetadata(
}
void ImageAnimationController::AnimationState::PushPendingToActive() {
- active_index_ = pending_index_;
+ active_index_ = current_state_.pending_index;
}
void ImageAnimationController::AnimationState::AddDriver(
@@ -446,9 +502,9 @@ void ImageAnimationController::AnimationState::UpdateStateFromDrivers() {
void ImageAnimationController::AnimationState::ResetAnimation() {
animation_started_ = false;
- next_desired_frame_time_ = base::TimeTicks();
- repetitions_completed_ = 0;
- pending_index_ = 0u;
+ current_state_.next_desired_frame_time = base::TimeTicks();
+ current_state_.repetitions_completed = 0;
+ current_state_.pending_index = 0u;
// Don't reset the |active_index_|, tiles on the active tree still need it.
}
@@ -458,19 +514,22 @@ std::string ImageAnimationController::AnimationState::ToString() const {
<< requested_repetitions_ << "]\nrepetitions_completed["
<< requested_repetitions_ << "]\ndrivers[" << drivers_.size()
<< "]\nactive_index[" << active_index_ << "]\npending_index["
- << pending_index_ << "]\nnext_desired_frame_time["
- << (next_desired_frame_time_ - animation_started_time_).InMillisecondsF()
+ << current_state_.pending_index << "]\nnext_desired_frame_time["
+ << (current_state_.next_desired_frame_time - animation_started_time_)
+ .InMillisecondsF()
<< "]\nnext_desired_tick_time["
- << (next_desired_tick_time_ - animation_started_time_).InMillisecondsF()
+ << (current_state_.next_desired_tick_time - animation_started_time_)
+ .InMillisecondsF()
<< "]\nshould_animate_from_drivers[" << should_animate_from_drivers_
<< "]\ncompletion_state[" << static_cast<int>(completion_state_) << "]";
return str.str();
}
-size_t ImageAnimationController::AnimationState::NextFrameIndex() const {
+size_t ImageAnimationController::AnimationState::NextFrameIndex(
+ size_t pending_index) const {
if (!animation_started_)
return 0u;
- return (pending_index_ + 1) % frames_.size();
+ return (pending_index + 1) % frames_.size();
}
ImageAnimationController::InvalidationScheduler::InvalidationScheduler(
diff --git a/chromium/cc/trees/image_animation_controller.h b/chromium/cc/trees/image_animation_controller.h
index 59c1c19faa1..5dfcdb374cd 100644
--- a/chromium/cc/trees/image_animation_controller.h
+++ b/chromium/cc/trees/image_animation_controller.h
@@ -144,8 +144,10 @@ class CC_EXPORT ImageAnimationController {
AnimationState& operator=(AnimationState&& other);
bool ShouldAnimate() const;
+ bool ShouldAnimate(int repetitions_completed, size_t pending_index) const;
bool AdvanceFrame(const viz::BeginFrameArgs& args,
- bool enable_image_animation_resync);
+ bool enable_image_animation_resync,
+ bool use_resume_behavior);
void UpdateMetadata(const DiscardableImageMap::AnimatedImageMetadata& data);
void PushPendingToActive();
@@ -154,10 +156,10 @@ class CC_EXPORT ImageAnimationController {
void UpdateStateFromDrivers();
bool has_drivers() const { return !drivers_.empty(); }
- size_t pending_index() const { return pending_index_; }
+ size_t pending_index() const { return current_state_.pending_index; }
size_t active_index() const { return active_index_; }
base::TimeTicks next_desired_tick_time() const {
- return next_desired_tick_time_;
+ return current_state_.next_desired_tick_time;
}
const base::flat_set<AnimationDriver*>& drivers_for_testing() const {
return drivers_;
@@ -168,12 +170,42 @@ class CC_EXPORT ImageAnimationController {
std::string ToString() const;
private:
+ struct AnimationAdvancementState {
+ // The index being displayed on the pending tree.
+ size_t pending_index = PaintImage::kDefaultFrameIndex;
+
+ // The time at which we would like to display the next frame. This can be
+ // in the past, for instance, if we pause the animation from the image
+ // becoming invisible. This time is updated based on either the animation
+ // timeline provided by the image (when using Catch-up behavior) or the
+ // next displayed frame (when using Resume behavior). Here, "displayed
+ // frame" means an animation that updates faster than the display's
+ // refresh rate and might skip frames to maintain display speed. See
+ // kAnimatedImageResume.
+ base::TimeTicks next_desired_frame_time;
+
+ // The time of the next tick at which we want to invalidate and update the
+ // current frame.
+ base::TimeTicks next_desired_tick_time;
+
+ // The number of loops the animation has finished so far.
+ int repetitions_completed = 0;
+ size_t num_of_frames_advanced = 0u;
+ };
+
+ AnimationAdvancementState AdvanceAnimationState(
+ AnimationAdvancementState animation_advancement_state,
+ const viz::BeginFrameArgs& args,
+ base::TimeTicks start,
+ bool enable_image_animation_resync) const;
void ResetAnimation();
- size_t NextFrameIndex() const;
+ size_t NextFrameIndex(size_t pending_index) const;
bool is_complete() const {
return completion_state_ == PaintImage::CompletionState::DONE;
}
- bool needs_invalidation() const { return pending_index_ != active_index_; }
+ bool needs_invalidation() const {
+ return current_state_.pending_index != active_index_;
+ }
PaintImage::Id paint_image_id_ = PaintImage::kInvalidId;
@@ -187,8 +219,7 @@ class CC_EXPORT ImageAnimationController {
// cc/paint/image_animation_count.h
int requested_repetitions_ = kAnimationNone;
- // The number of loops the animation has finished so far.
- int repetitions_completed_ = 0;
+ AnimationAdvancementState current_state_;
// A set of drivers interested in animating this image.
base::flat_set<AnimationDriver*> drivers_;
@@ -197,19 +228,6 @@ class CC_EXPORT ImageAnimationController {
// is still present.
size_t active_index_ = PaintImage::kDefaultFrameIndex;
- // The index being displayed on the pending tree.
- size_t pending_index_ = PaintImage::kDefaultFrameIndex;
-
- // The time at which we would like to display the next frame. This can be in
- // the past, for instance, if we pause the animation from the image becoming
- // invisible. This time is updated strictly based on the animation timeline
- // provided by the image.
- base::TimeTicks next_desired_frame_time_;
-
- // The time of the next tick at which we want to invalidate and update the
- // current frame.
- base::TimeTicks next_desired_tick_time_;
-
// Set if there is at least one driver interested in animating this image,
// cached from the last update.
bool should_animate_from_drivers_ = false;
@@ -290,6 +308,7 @@ class CC_EXPORT ImageAnimationController {
InvalidationScheduler scheduler_;
const bool enable_image_animation_resync_;
+ const bool use_resume_behavior_;
bool did_navigate_ = false;
};
diff --git a/chromium/cc/trees/layer_tree_host.cc b/chromium/cc/trees/layer_tree_host.cc
index 03e3c41c5e5..3b598eb3144 100644
--- a/chromium/cc/trees/layer_tree_host.cc
+++ b/chromium/cc/trees/layer_tree_host.cc
@@ -37,6 +37,7 @@
#include "cc/base/histograms.h"
#include "cc/base/math_util.h"
#include "cc/debug/rendering_stats_instrumentation.h"
+#include "cc/document_transition/document_transition_request.h"
#include "cc/input/layer_selection_bound.h"
#include "cc/input/overscroll_behavior.h"
#include "cc/input/page_scale_animation.h"
@@ -198,8 +199,6 @@ void LayerTreeHost::InitializeProxy(std::unique_ptr<Proxy> proxy) {
proxy_->Start();
UpdateDeferMainFrameUpdateInternal();
-
- mutator_host_->SetSupportsScrollAnimations(proxy_->SupportsImplScrolling());
}
LayerTreeHost::~LayerTreeHost() {
@@ -491,6 +490,10 @@ void LayerTreeHost::CommitComplete() {
client_->DidCompletePageScaleAnimation();
did_complete_scale_animation_ = false;
}
+
+ for (auto& closure : committed_document_transition_callbacks_)
+ std::move(closure).Run();
+ committed_document_transition_callbacks_.clear();
}
void LayerTreeHost::SetLayerTreeFrameSink(
@@ -535,9 +538,8 @@ std::unique_ptr<LayerTreeHostImpl> LayerTreeHost::CreateLayerTreeHostImpl(
LayerTreeHostImplClient* client) {
DCHECK(task_runner_provider_->IsImplThread());
- const bool supports_impl_scrolling = task_runner_provider_->HasImplThread();
std::unique_ptr<MutatorHost> mutator_host_impl =
- mutator_host_->CreateImplInstance(supports_impl_scrolling);
+ mutator_host_->CreateImplInstance();
if (!settings_.scroll_animation_duration_for_testing.is_zero()) {
mutator_host_->SetScrollAnimationDurationForTesting(
@@ -653,10 +655,7 @@ void LayerTreeHost::SetNeedsCommitWithForcedRedraw() {
proxy_->SetNeedsCommit();
}
-void LayerTreeHost::SetDebugState(const LayerTreeDebugState& debug_state) {
- LayerTreeDebugState new_debug_state =
- LayerTreeDebugState::Unite(settings_.initial_debug_state, debug_state);
-
+void LayerTreeHost::SetDebugState(const LayerTreeDebugState& new_debug_state) {
if (LayerTreeDebugState::Equal(debug_state_, new_debug_state))
return;
@@ -780,11 +779,12 @@ std::string LayerTreeHost::LayersAsString() const {
}
bool LayerTreeHost::CaptureContent(std::vector<NodeInfo>* content) {
- if (viewport_visible_rect_.IsEmpty())
+ if (visual_device_viewport_intersection_rect_.IsEmpty())
return false;
- gfx::Rect rect = gfx::Rect(viewport_visible_rect_.width(),
- viewport_visible_rect_.height());
+ gfx::Rect rect =
+ gfx::Rect(visual_device_viewport_intersection_rect_.width(),
+ visual_device_viewport_intersection_rect_.height());
for (auto* layer : *this) {
// Normally, the node won't be drawn in multiple layers, even it is, such as
// text strokes, the visual rect don't have too much different.
@@ -800,11 +800,17 @@ void LayerTreeHost::DidObserveFirstScrollDelay(
first_scroll_timestamp);
}
+void LayerTreeHost::AddDocumentTransitionRequest(
+ std::unique_ptr<DocumentTransitionRequest> request) {
+ document_transition_requests_.push_back(std::move(request));
+ SetNeedsCommit();
+}
+
bool LayerTreeHost::DoUpdateLayers() {
TRACE_EVENT1("cc,benchmark", "LayerTreeHost::DoUpdateLayers",
"source_frame_number", SourceFrameNumber());
- UpdateHudLayer(debug_state_.ShowHudInfo());
+ UpdateHudLayer(debug_state_.ShouldCreateHudLayer());
// In layer lists mode, the cc property trees are built directly and do not
// need to be built here.
@@ -917,29 +923,6 @@ void LayerTreeHost::ApplyViewportChanges(
SetNeedsUpdateLayers();
}
-void LayerTreeHost::RecordManipulationTypeCounts(
- const CompositorCommitData& commit_data) {
- client_->RecordManipulationTypeCounts(commit_data.manipulation_info);
-}
-
-void LayerTreeHost::SendOverscrollAndScrollEndEventsFromImplSide(
- const CompositorCommitData& commit_data) {
- if (commit_data.scroll_latched_element_id == ElementId())
- return;
-
- if (!commit_data.overscroll_delta.IsZero()) {
- client_->SendOverscrollEventFromImplSide(
- commit_data.overscroll_delta, commit_data.scroll_latched_element_id);
- }
- // TODO(bokan): If a scroll ended and a new one began in the same Blink frame
- // (e.g. during a long running main thread task), this will erroneously
- // dispatch the scroll end to the latter (still-scrolling) element.
- // https://crbug.com/1116780.
- if (commit_data.scroll_gesture_did_end)
- client_->SendScrollEndEventFromImplSide(
- commit_data.scroll_latched_element_id);
-}
-
void LayerTreeHost::UpdateScrollOffsetFromImpl(
const ElementId& id,
const gfx::ScrollOffset& delta,
@@ -1015,14 +998,12 @@ void LayerTreeHost::ApplyCompositorChanges(CompositorCommitData* commit_data) {
}
}
- SendOverscrollAndScrollEndEventsFromImplSide(*commit_data);
+ client_->UpdateCompositorScrollState(*commit_data);
// This needs to happen after scroll deltas have been sent to prevent top
// controls from clamping the layout viewport both on the compositor and
// on the main thread.
ApplyViewportChanges(*commit_data);
-
- RecordManipulationTypeCounts(*commit_data);
}
void LayerTreeHost::ApplyMutatorEvents(std::unique_ptr<MutatorEvents> events) {
@@ -1245,6 +1226,13 @@ void LayerTreeHost::SetViewportRectAndScale(
local_surface_id_from_parent_;
SetLocalSurfaceIdFromParent(local_surface_id_from_parent);
+ TRACE_EVENT_NESTABLE_ASYNC_END0("cc", "LayerTreeHostSize",
+ TRACE_ID_LOCAL(this));
+ TRACE_EVENT_NESTABLE_ASYNC_BEGIN2("cc", "LayerTreeHostSize",
+ TRACE_ID_LOCAL(this), "size",
+ device_viewport_rect.ToString(), "lsid",
+ local_surface_id_from_parent.ToString());
+
bool device_viewport_rect_changed = false;
if (device_viewport_rect_ != device_viewport_rect) {
device_viewport_rect_ = device_viewport_rect;
@@ -1273,11 +1261,21 @@ void LayerTreeHost::SetViewportRectAndScale(
}
}
-void LayerTreeHost::SetViewportVisibleRect(const gfx::Rect& visible_rect) {
- if (visible_rect == viewport_visible_rect_)
+void LayerTreeHost::SetVisualDeviceViewportIntersectionRect(
+ const gfx::Rect& intersection_rect) {
+ if (intersection_rect == visual_device_viewport_intersection_rect_)
+ return;
+
+ visual_device_viewport_intersection_rect_ = intersection_rect;
+}
+
+void LayerTreeHost::SetVisualDeviceViewportSize(
+ const gfx::Size& visual_device_viewport_size) {
+ if (visual_device_viewport_size == visual_device_viewport_size_)
return;
- viewport_visible_rect_ = visible_rect;
+ visual_device_viewport_size_ = visual_device_viewport_size;
+ SetNeedsCommit();
}
void LayerTreeHost::SetBrowserControlsParams(
@@ -1522,6 +1520,16 @@ void LayerTreeHost::UpdateHudLayer(bool show_hud_info) {
root_layer_->AddChild(hud_layer_);
hud_layer_->UpdateLocationAndSize(device_viewport_rect_.size(),
device_scale_factor_);
+ if (debug_state_.show_web_vital_metrics) {
+ // This WebVitalMetrics is filled by the main frame, which is equivalent
+ // to WebPerf's numbers. The main frame's number doesn't include any
+ // iframes. UMA/UKM records metrics for the entire page aggregating all
+ // the frames. The page metrics are in the browser process.
+ // TODO(weiliangc): Get the page metrics for display.
+ auto metrics = client_->GetWebVitalMetrics();
+ if (metrics && metrics->HasValue())
+ hud_layer_->UpdateWebVitalMetrics(std::move(metrics));
+ }
} else if (hud_layer_.get()) {
hud_layer_->RemoveFromParent();
hud_layer_ = nullptr;
@@ -1616,6 +1624,16 @@ void LayerTreeHost::PushLayerTreePropertiesTo(LayerTreeImpl* tree_impl) {
if (delegated_ink_metadata_)
tree_impl->set_delegated_ink_metadata(std::move(delegated_ink_metadata_));
+
+ // Transfer page transition directives.
+ for (auto& request : document_transition_requests_) {
+ // Store the commit callback on LayerTreeHost, so that we can invoke them in
+ // CommitComplete.
+ committed_document_transition_callbacks_.push_back(
+ request->TakeCommitCallback());
+ tree_impl->AddDocumentTransitionRequest(std::move(request));
+ }
+ document_transition_requests_.clear();
}
void LayerTreeHost::PushSurfaceRangesTo(LayerTreeImpl* tree_impl) {
@@ -1636,6 +1654,7 @@ void LayerTreeHost::PushLayerTreeHostPropertiesTo(
RecordGpuRasterizationHistogram(host_impl);
host_impl->SetDebugState(debug_state_);
+ host_impl->SetVisualDeviceViewportSize(visual_device_viewport_size_);
}
Layer* LayerTreeHost::LayerByElementId(ElementId element_id) const {
@@ -1794,13 +1813,11 @@ void LayerTreeHost::ElementIsAnimatingChanged(
true);
}
-void LayerTreeHost::AnimationScalesChanged(ElementId element_id,
- ElementListType list_type,
- float maximum_scale,
- float starting_scale) {
+void LayerTreeHost::MaximumScaleChanged(ElementId element_id,
+ ElementListType list_type,
+ float maximum_scale) {
DCHECK_EQ(ElementListType::ACTIVE, list_type);
- property_trees()->AnimationScalesChanged(element_id, maximum_scale,
- starting_scale);
+ property_trees()->MaximumAnimationScaleChanged(element_id, maximum_scale);
}
gfx::ScrollOffset LayerTreeHost::GetScrollOffsetForAnimation(
@@ -1883,4 +1900,15 @@ void LayerTreeHost::SetEnableFrameRateThrottling(
proxy_->SetEnableFrameRateThrottling(enable_frame_rate_throttling);
}
+void LayerTreeHost::SetDelegatedInkMetadata(
+ std::unique_ptr<viz::DelegatedInkMetadata> metadata) {
+ delegated_ink_metadata_ = std::move(metadata);
+ SetNeedsCommit();
+}
+
+std::vector<std::unique_ptr<DocumentTransitionRequest>>
+LayerTreeHost::TakeDocumentTransitionRequestsForTesting() {
+ return std::move(document_transition_requests_);
+}
+
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host.h b/chromium/cc/trees/layer_tree_host.h
index e5e66fa7cc6..3447ff7c385 100644
--- a/chromium/cc/trees/layer_tree_host.h
+++ b/chromium/cc/trees/layer_tree_host.h
@@ -39,6 +39,7 @@
#include "cc/metrics/begin_main_frame_metrics.h"
#include "cc/metrics/events_metrics_manager.h"
#include "cc/metrics/frame_sequence_tracker.h"
+#include "cc/metrics/web_vital_metrics.h"
#include "cc/paint/node_id.h"
#include "cc/trees/browser_controls_params.h"
#include "cc/trees/compositor_mode.h"
@@ -64,25 +65,27 @@ struct PresentationFeedback;
namespace cc {
-class RasterDarkModeFilter;
+class DocumentTransitionRequest;
class HeadsUpDisplayLayer;
class Layer;
class LayerTreeHostImpl;
class LayerTreeHostImplClient;
class LayerTreeHostSingleThreadClient;
class LayerTreeMutator;
-class PaintWorkletLayerPainter;
class MutatorEvents;
class MutatorHost;
-struct PendingPageScaleAnimation;
+class PaintWorkletLayerPainter;
+class RasterDarkModeFilter;
class RenderFrameMetadataObserver;
class RenderingStatsInstrumentation;
-struct OverscrollBehavior;
class TaskGraphRunner;
class UIResourceManager;
class UkmRecorderFactory;
-struct RenderingStats;
+
struct CompositorCommitData;
+struct OverscrollBehavior;
+struct PendingPageScaleAnimation;
+struct RenderingStats;
// Returned from LayerTreeHost::DeferMainFrameUpdate. Automatically un-defers on
// destruction.
@@ -402,7 +405,22 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
float device_scale_factor,
const viz::LocalSurfaceId& local_surface_id_from_parent);
- void SetViewportVisibleRect(const gfx::Rect& visible_rect);
+ // VisualDeviceViewportIntersectionRect is the intersection of this
+ // compositor's viewport with the "visible size", aka this compositor's
+ // viewport intersection with the global viewport (i.e.
+ // VisualDeviceViewportSize). It is also specified in the device viewport
+ // coordinate space.
+ void SetVisualDeviceViewportIntersectionRect(
+ const gfx::Rect& intersection_rect);
+
+ // VisualDeviceViewportSize is the size of the global viewport across all
+ // compositors that are part of the scene that this compositor contributes to
+ // (i.e. the visual viewport), allowing for that scene to be broken up into
+ // multiple compositors that each contribute to the whole (e.g. cross-origin
+ // iframes are isolated from each other). This is a size instead of a rect
+ // because each compositor doesn't know its position relative to other
+ // compositors. This is specified in device viewport coordinate space.
+ void SetVisualDeviceViewportSize(const gfx::Size&);
gfx::Rect device_viewport_rect() const { return device_viewport_rect_; }
@@ -662,15 +680,13 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
ElementListType list_type,
const PropertyAnimationState& mask,
const PropertyAnimationState& state) override;
- void AnimationScalesChanged(ElementId element_id,
- ElementListType list_type,
- float maximum_scale,
- float starting_scale) override;
+ void MaximumScaleChanged(ElementId element_id,
+ ElementListType list_type,
+ float maximum_scale) override;
void OnCustomPropertyMutated(
- ElementId element_id,
- const std::string& custom_property_name,
- PaintWorkletInput::PropertyValue custom_property_value) override {}
+ PaintWorkletInput::PropertyKey property_key,
+ PaintWorkletInput::PropertyValue property_value) override {}
void ScrollOffsetAnimationFinished() override {}
gfx::ScrollOffset GetScrollOffsetForAnimation(
@@ -711,9 +727,7 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
}
void SetDelegatedInkMetadata(
- std::unique_ptr<viz::DelegatedInkMetadata> metadata) {
- delegated_ink_metadata_ = std::move(metadata);
- }
+ std::unique_ptr<viz::DelegatedInkMetadata> metadata);
viz::DelegatedInkMetadata* DelegatedInkMetadataForTesting() {
return delegated_ink_metadata_.get();
}
@@ -721,6 +735,12 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
void DidObserveFirstScrollDelay(base::TimeDelta first_scroll_delay,
base::TimeTicks first_scroll_timestamp);
+ void AddDocumentTransitionRequest(
+ std::unique_ptr<DocumentTransitionRequest> request);
+
+ std::vector<std::unique_ptr<DocumentTransitionRequest>>
+ TakeDocumentTransitionRequestsForTesting();
+
protected:
LayerTreeHost(InitParams params, CompositorMode mode);
@@ -764,9 +784,6 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
enum { kNumFramesToConsiderBeforeRemovingSlowPathFlag = 60 };
void ApplyViewportChanges(const CompositorCommitData& commit_data);
- void RecordManipulationTypeCounts(const CompositorCommitData& commit_data);
- void SendOverscrollAndScrollEndEventsFromImplSide(
- const CompositorCommitData& commit_data);
void ApplyPageScaleDeltaFromImplSide(float page_scale_delta);
void InitializeProxy(std::unique_ptr<Proxy> proxy);
@@ -862,8 +879,8 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
LayerSelection selection_;
gfx::Rect device_viewport_rect_;
-
- gfx::Rect viewport_visible_rect_;
+ gfx::Rect visual_device_viewport_intersection_rect_;
+ gfx::Size visual_device_viewport_size_;
bool have_scroll_event_handlers_ = false;
EventListenerProperties event_listener_properties_
@@ -948,6 +965,16 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
// sticking around and potentially being reused.
std::unique_ptr<viz::DelegatedInkMetadata> delegated_ink_metadata_;
+ // A list of document transitions that need to be transported from Blink to
+ // Viz, as a CompositorFrameTransitionDirective.
+ std::vector<std::unique_ptr<DocumentTransitionRequest>>
+ document_transition_requests_;
+
+ // A list of callbacks that need to be invoked in commit callback,
+ // representing document transitions that have been committed to
+ // LayerTreeImpl.
+ std::vector<base::OnceClosure> committed_document_transition_callbacks_;
+
// Used to vend weak pointers to LayerTreeHost to ScopedDeferMainFrameUpdate
// objects.
base::WeakPtrFactory<LayerTreeHost> defer_main_frame_update_weak_ptr_factory_{
diff --git a/chromium/cc/trees/layer_tree_host_client.cc b/chromium/cc/trees/layer_tree_host_client.cc
new file mode 100644
index 00000000000..6baef660763
--- /dev/null
+++ b/chromium/cc/trees/layer_tree_host_client.cc
@@ -0,0 +1,15 @@
+// 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.
+
+#include "cc/trees/layer_tree_host_client.h"
+
+#include "cc/metrics/web_vital_metrics.h"
+
+namespace cc {
+
+std::unique_ptr<WebVitalMetrics> LayerTreeHostClient::GetWebVitalMetrics() {
+ return nullptr;
+}
+
+} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_client.h b/chromium/cc/trees/layer_tree_host_client.h
index 5a804d2f009..4a8332b88ca 100644
--- a/chromium/cc/trees/layer_tree_host_client.h
+++ b/chromium/cc/trees/layer_tree_host_client.h
@@ -11,6 +11,7 @@
#include "base/time/time.h"
#include "cc/input/browser_controls_state.h"
#include "cc/metrics/frame_sequence_tracker_collection.h"
+#include "cc/trees/property_tree.h"
#include "ui/gfx/geometry/scroll_offset.h"
#include "ui/gfx/geometry/vector2d_f.h"
@@ -24,7 +25,7 @@ struct BeginFrameArgs;
namespace cc {
struct BeginMainFrameMetrics;
-struct ElementId;
+struct WebVitalMetrics;
struct ApplyViewportChangesArgs {
// Scroll offset delta of the inner (visual) viewport.
@@ -65,6 +66,7 @@ constexpr ManipulationInfo kManipulationInfoWheel = 1 << 0;
constexpr ManipulationInfo kManipulationInfoTouch = 1 << 1;
constexpr ManipulationInfo kManipulationInfoPrecisionTouchPad = 1 << 2;
constexpr ManipulationInfo kManipulationInfoPinchZoom = 1 << 3;
+constexpr ManipulationInfo kManipulationInfoScrollbar = 1 << 4;
struct PaintBenchmarkResult {
double record_time_ms = 0;
@@ -136,17 +138,10 @@ class LayerTreeHostClient {
// related to pinch-zoom, browser controls (aka URL bar), overscroll, etc.
virtual void ApplyViewportChanges(const ApplyViewportChangesArgs& args) = 0;
- // Record use counts of different methods of scrolling (e.g. wheel, touch,
- // precision touchpad, etc.).
- virtual void RecordManipulationTypeCounts(ManipulationInfo info) = 0;
-
- // Notifies the client when an overscroll has happened.
- virtual void SendOverscrollEventFromImplSide(
- const gfx::Vector2dF& overscroll_delta,
- ElementId scroll_latched_element_id) = 0;
- // Notifies the client when a gesture scroll has ended.
- virtual void SendScrollEndEventFromImplSide(
- ElementId scroll_latched_element_id) = 0;
+ // Notifies the client about scroll and input related changes that occurred in
+ // the LayerTreeHost since the last commit.
+ virtual void UpdateCompositorScrollState(
+ const CompositorCommitData& commit_data) = 0;
// Request a LayerTreeFrameSink from the client. When the client has one it
// should call LayerTreeHost::SetLayerTreeFrameSink. This will result in
@@ -182,6 +177,9 @@ class LayerTreeHostClient {
virtual std::unique_ptr<BeginMainFrameMetrics> GetBeginMainFrameMetrics() = 0;
virtual void NotifyThroughputTrackerResults(CustomTrackerResults results) = 0;
+ // Should only be implemented by Blink.
+ virtual std::unique_ptr<WebVitalMetrics> GetWebVitalMetrics() = 0;
+
virtual void RunPaintBenchmark(int repeat_count,
PaintBenchmarkResult& result) {}
diff --git a/chromium/cc/trees/layer_tree_host_impl.cc b/chromium/cc/trees/layer_tree_host_impl.cc
index 9efdf67d48c..2c3b6b3a2a8 100644
--- a/chromium/cc/trees/layer_tree_host_impl.cc
+++ b/chromium/cc/trees/layer_tree_host_impl.cc
@@ -38,6 +38,7 @@
#include "cc/base/switches.h"
#include "cc/benchmarks/benchmark_instrumentation.h"
#include "cc/debug/rendering_stats_instrumentation.h"
+#include "cc/document_transition/document_transition_request.h"
#include "cc/input/browser_controls_offset_manager.h"
#include "cc/input/main_thread_scrolling_reason.h"
#include "cc/input/page_scale_animation.h"
@@ -202,7 +203,7 @@ void DidVisibilityChange(LayerTreeHostImpl* id, bool visible) {
if (visible) {
TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(
"cc,benchmark", "LayerTreeHostImpl::SetVisible", TRACE_ID_LOCAL(id),
- "LayerTreeHostImpl", id);
+ "LayerTreeHostImpl", static_cast<void*>(id));
return;
}
@@ -356,6 +357,12 @@ const LayerTreeHostImpl& LayerTreeHostImpl::GetImplDeprecated() const {
return *this;
}
+bool LayerTreeHostImpl::CanInjectJankOnMain() const {
+ return !!frame_trackers_.FrameSequenceTrackerActiveTypes() &&
+ compositor_frame_reporting_controller_
+ ->is_main_thread_driving_smoothness();
+}
+
LayerTreeHostImpl::FrameData::FrameData() = default;
LayerTreeHostImpl::FrameData::~FrameData() = default;
LayerTreeHostImpl::UIResourceData::UIResourceData() = default;
@@ -745,16 +752,13 @@ PaintWorkletJobMap LayerTreeHostImpl::GatherDirtyPaintWorklets(
PaintWorkletJob::AnimatedPropertyValues animated_property_values;
for (const auto& element : input->GetPropertyKeys()) {
- // We should not have multiple property ids with the same name.
- DCHECK(!animated_property_values.contains(element.first));
+ DCHECK(!animated_property_values.contains(element));
const PaintWorkletInput::PropertyValue& animated_property_value =
paint_worklet_tracker_.GetPropertyAnimationValue(element);
// No value indicates that the input property was not mutated by CC
// animation.
- if (animated_property_value.has_value()) {
- animated_property_values.emplace(element.first,
- animated_property_value);
- }
+ if (animated_property_value.has_value())
+ animated_property_values.emplace(element, animated_property_value);
}
job_vector->data.emplace_back(layer->id(), input,
@@ -1126,7 +1130,7 @@ bool LayerTreeHostImpl::HasDamage() const {
return root_surface_has_visible_damage ||
active_tree_->property_trees()->effect_tree.HasCopyRequests() ||
- hud_wants_to_draw_;
+ hud_wants_to_draw_ || active_tree_->HasDocumentTransitionRequests();
}
DrawResult LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) {
@@ -1173,8 +1177,7 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) {
render_surface->EffectTreeIndex() == EffectTree::kContentsRootNodeId;
bool should_draw_into_render_pass =
is_root_surface || render_surface->contributes_to_drawn_surface() ||
- render_surface->HasCopyRequest() ||
- render_surface->ShouldCacheRenderSurface();
+ render_surface->CopyOfOutputRequired();
if (should_draw_into_render_pass)
frame->render_passes.push_back(render_surface->CreateRenderPass());
}
@@ -1227,6 +1230,8 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) {
// Advance our de-jelly state. This is a no-op if de-jelly is not active.
de_jelly_state_.AdvanceFrame(active_tree_.get());
+ if (settings_.enable_compositing_based_throttling)
+ throttle_decider_.Prepare();
for (EffectTreeLayerListIterator it(active_tree());
it.state() != EffectTreeLayerListIterator::State::END; ++it) {
auto target_render_pass_id = it.target_render_surface()->render_pass_id();
@@ -1244,6 +1249,8 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) {
render_surface->EffectTreeIndex(),
&target_render_pass->copy_requests);
}
+ if (settings_.enable_compositing_based_throttling && target_render_pass)
+ throttle_decider_.ProcessRenderPass(*target_render_pass);
} else if (it.state() ==
EffectTreeLayerListIterator::State::CONTRIBUTING_SURFACE) {
RenderSurfaceImpl* render_surface = it.current_render_surface();
@@ -1601,7 +1608,8 @@ void LayerTreeHostImpl::RemoveRenderPasses(FrameData* frame) {
}
if (pass->quad_list.empty() && pass->copy_requests.empty() &&
- pass->filters.IsEmpty() && pass->backdrop_filters.IsEmpty()) {
+ !pass->subtree_capture_id.is_valid() && pass->filters.IsEmpty() &&
+ pass->backdrop_filters.IsEmpty()) {
// Remove the pass and decrement |i| to counter the for loop's increment,
// so we don't skip the next pass in the loop.
frame->render_passes.erase(frame->render_passes.begin() + i);
@@ -2023,22 +2031,13 @@ void LayerTreeHostImpl::DidReceiveCompositorFrameAck() {
void LayerTreeHostImpl::DidPresentCompositorFrame(
uint32_t frame_token,
const viz::FrameTimingDetails& details) {
- frame_trackers_.NotifyFramePresented(frame_token,
- details.presentation_feedback);
- PresentationTimeCallbackBuffer::PendingCallbacks activated =
+ PresentationTimeCallbackBuffer::PendingCallbacks activated_callbacks =
presentation_time_callbacks_.PopPendingCallbacks(frame_token);
- // The callbacks in |compositor_thread_callbacks| expect to be run on the
- // compositor thread so we'll run them now.
- for (LayerTreeHost::PresentationTimeCallback& callback :
- activated.compositor_thread_callbacks) {
- std::move(callback).Run(details.presentation_feedback);
- }
-
- // Send all the main-thread callbacks to the client in one batch. The client
- // is in charge of posting them to the main thread.
+ // Send all tasks to the client so that it can decide which tasks
+ // should run on which thread.
client_->DidPresentCompositorFrameOnImplThread(
- frame_token, std::move(activated.main_thread_callbacks), details);
+ frame_token, std::move(activated_callbacks), details);
// Send all pending lag events waiting on the frame pointed by |frame_token|.
// It is posted as a task because LayerTreeHostImpl::DidPresentCompositorFrame
@@ -2221,6 +2220,9 @@ viz::CompositorFrameMetadata LayerTreeHostImpl::MakeCompositorFrameMetadata() {
metadata.delegated_ink_metadata = std::move(delegated_ink_metadata);
}
+ for (auto& request : active_tree_->TakeDocumentTransitionRequests())
+ metadata.transition_directives.push_back(request->ConstructDirective());
+
return metadata;
}
@@ -2416,6 +2418,12 @@ bool LayerTreeHostImpl::DrawLayers(FrameData* frame) {
devtools_instrumentation::DidDrawFrame(id_);
benchmark_instrumentation::IssueImplThreadRenderingStatsEvent(
rendering_stats_instrumentation_->TakeImplThreadRenderingStats());
+
+ if (settings_.enable_compositing_based_throttling &&
+ throttle_decider_.HasThrottlingChanged()) {
+ client_->FrameSinksToThrottleUpdated(throttle_decider_.ids());
+ }
+
return true;
}
@@ -2429,7 +2437,7 @@ viz::CompositorFrame LayerTreeHostImpl::GenerateCompositorFrame(
memory_history_->SaveEntry(tile_manager_.memory_stats_from_last_assign());
- if (debug_state_.ShowHudRects()) {
+ if (debug_state_.ShowDebugRects()) {
debug_rect_history_->SaveDebugRectsForCurrentFrame(
active_tree(), active_tree_->hud_layer(), *frame->render_surface_list,
debug_state_);
@@ -2482,12 +2490,30 @@ viz::CompositorFrame LayerTreeHostImpl::GenerateCompositorFrame(
frame->deadline_in_frames.value_or(0u), CurrentBeginFrameArgs().interval,
frame->use_default_lower_bound_deadline);
- frame_rate_estimator_.WillDraw(CurrentBeginFrameArgs().frame_time);
-
- if (settings_.force_preferred_interval_for_video ||
- enable_frame_rate_throttling_) {
+ constexpr auto kFudgeDelta = base::TimeDelta::FromMilliseconds(1);
+ constexpr auto kTwiceOfDefaultInterval =
+ viz::BeginFrameArgs::DefaultInterval() * 2;
+ constexpr auto kMinDelta = kTwiceOfDefaultInterval - kFudgeDelta;
+ if (enable_frame_rate_throttling_) {
metadata.preferred_frame_interval = viz::BeginFrameArgs::MaxInterval();
+ } else if (mutator_host_->MainThreadAnimationsCount() == 0 &&
+ mutator_host_->MinimumTickInterval() > kMinDelta) {
+ // All animations are impl-thread animations that tick at no more than
+ // half the default display compositing fps.
+ // Here and below with FrameRateEstimator::GetPreferredInterval(), the
+ // meta data's preferred_frame_interval is constrainted to either 0 or
+ // twice the default interval. The reason is because GPU process side
+ // viz::FrameRateDecider is optimized for when all the preferred frame
+ // rates are similar.
+ // In general it may cause an animation to be less smooth if its fps is
+ // less than 30 fps and it updates at 30 fps. However, the frame rate
+ // reduction optimization is only applied when a webpage has two or more
+ // videos, i.e., very likely a video conferencing scene. It doesn't apply
+ // to general webpages.
+ metadata.preferred_frame_interval = kTwiceOfDefaultInterval;
} else {
+ // There are main-thread or high frequency impl-thread animations.
+ frame_rate_estimator_.WillDraw(CurrentBeginFrameArgs().frame_time);
metadata.preferred_frame_interval =
frame_rate_estimator_.GetPreferredInterval();
}
@@ -2499,8 +2525,11 @@ viz::CompositorFrame LayerTreeHostImpl::GenerateCompositorFrame(
if (render_frame_metadata_observer_) {
last_draw_render_frame_metadata_ = MakeRenderFrameMetadata(frame);
- last_draw_render_frame_metadata_->has_delegated_ink_metadata =
- metadata.delegated_ink_metadata.get();
+ if (viz::DelegatedInkMetadata* ink_metadata =
+ metadata.delegated_ink_metadata.get()) {
+ last_draw_render_frame_metadata_->delegated_ink_metadata =
+ DelegatedInkBrowserMetadata(ink_metadata->is_hovering());
+ }
// We cache the value of any new vertical scroll direction so that we can
// accurately determine when the next change in vertical scroll direction
@@ -2772,6 +2801,9 @@ bool LayerTreeHostImpl::WillBeginImplFrame(const viz::BeginFrameArgs& args) {
frame_trackers_.NotifyBeginImplFrame(args);
total_frame_counter_.OnBeginFrame(args);
+ UMA_HISTOGRAM_CUSTOM_COUNTS("GPU.AcceleratedSurfaceRefreshRate",
+ 1 / args.interval.InSecondsF(), 0, 121, 122);
+
if (is_likely_to_require_a_draw_) {
// Optimistically schedule a draw. This will let us expect the tile manager
// to complete its work so that we can draw new tiles within the impl frame
@@ -3002,7 +3034,7 @@ void LayerTreeHostImpl::DidLoseLayerTreeFrameSink() {
client_->DidLoseLayerTreeFrameSinkOnImplThread();
lag_tracking_manager_.Clear();
- dropped_frame_counter_.ResetFrameSorter();
+ dropped_frame_counter_.ResetPendingFrames(base::TimeTicks::Now());
}
bool LayerTreeHostImpl::OnlyExpandTopControlsAtPageTop() const {
@@ -3246,6 +3278,13 @@ void LayerTreeHostImpl::OnMemoryPressure(
if (level != base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL)
return;
+ // TODO(crbug.com/1189208): Unlocking decoded-image-tracker images causes
+ // flickering in visible trees if Out-Of-Process rasterization is enabled.
+#if defined(OS_FUCHSIA)
+ if (use_oop_rasterization() && visible())
+ return;
+#endif // defined(OS_FUCHSIA)
+
ReleaseTileResources();
active_tree_->OnPurgeMemory();
if (pending_tree_)
@@ -3260,6 +3299,7 @@ void LayerTreeHostImpl::OnMemoryPressure(
}
if (resource_pool_)
resource_pool_->OnMemoryPressure(level);
+
tile_manager_.decoded_image_tracker().UnlockAllImages();
}
@@ -3269,10 +3309,14 @@ void LayerTreeHostImpl::SetVisible(bool visible) {
if (visible_ == visible)
return;
visible_ = visible;
- if (visible_)
- total_frame_counter_.OnShow(base::TimeTicks::Now());
- else
- total_frame_counter_.OnHide(base::TimeTicks::Now());
+ if (visible_) {
+ auto now = base::TimeTicks::Now();
+ total_frame_counter_.OnShow(now);
+ } else {
+ auto now = base::TimeTicks::Now();
+ total_frame_counter_.OnHide(now);
+ dropped_frame_counter_.ResetPendingFrames(now);
+ }
DidVisibilityChange(this, visible_);
UpdateTileManagerMemoryPolicy(ActualManagedMemoryPolicy());
@@ -3358,8 +3402,6 @@ void LayerTreeHostImpl::RecreateTileResources() {
}
void LayerTreeHostImpl::CreateTileManagerResources() {
- raster_buffer_provider_ = CreateRasterBufferProvider();
-
viz::ResourceFormat tile_format = TileRasterBufferFormat(
settings_, layer_tree_frame_sink_->context_provider(),
use_gpu_rasterization_);
@@ -3372,6 +3414,11 @@ void LayerTreeHostImpl::CreateTileManagerResources() {
tile_format),
settings_.decoded_image_working_set_budget_bytes, max_texture_size_,
paint_image_generator_client_id_, dark_mode_filter_);
+
+ pending_raster_queries_ = std::make_unique<RasterQueryQueue>(
+ layer_tree_frame_sink_->worker_context_provider(),
+ can_use_oop_rasterization_);
+
} else {
bool gpu_compositing = !!layer_tree_frame_sink_->context_provider();
image_decode_cache_ = std::make_unique<SoftwareImageDecodeCache>(
@@ -3380,6 +3427,8 @@ void LayerTreeHostImpl::CreateTileManagerResources() {
paint_image_generator_client_id_);
}
+ raster_buffer_provider_ = CreateRasterBufferProvider();
+
// Pass the single-threaded synchronous task graph runner to the worker pool
// if we're in synchronous single-threaded mode.
TaskGraphRunner* task_graph_runner = task_graph_runner_;
@@ -3392,7 +3441,8 @@ void LayerTreeHostImpl::CreateTileManagerResources() {
tile_manager_.SetResources(resource_pool_.get(), image_decode_cache_.get(),
task_graph_runner, raster_buffer_provider_.get(),
- use_gpu_rasterization_, use_oop_rasterization());
+ use_gpu_rasterization_, use_oop_rasterization(),
+ pending_raster_queries_.get());
tile_manager_.SetCheckerImagingForceDisabled(
settings_.only_checker_images_with_gpu_raster && !use_gpu_rasterization_);
UpdateTileManagerMemoryPolicy(ActualManagedMemoryPolicy());
@@ -3423,7 +3473,7 @@ LayerTreeHostImpl::CreateRasterBufferProvider() {
settings_.resource_settings.use_gpu_memory_buffer_resources,
tile_format, settings_.max_gpu_raster_tile_size,
settings_.unpremultiply_and_dither_low_bit_depth_tiles,
- can_use_oop_rasterization_);
+ can_use_oop_rasterization_, pending_raster_queries_.get());
}
bool use_zero_copy = settings_.use_zero_copy;
@@ -3520,6 +3570,7 @@ void LayerTreeHostImpl::CleanUpTileManagerResources() {
single_thread_synchronous_task_graph_runner_ = nullptr;
image_decode_cache_ = nullptr;
raster_buffer_provider_ = nullptr;
+ pending_raster_queries_ = nullptr;
// Any resources that were allocated previously should be considered not good
// for reuse, as the RasterBufferProvider will be replaced and it may choose
// to allocate future resources differently.
@@ -3875,6 +3926,15 @@ void LayerTreeHostImpl::BindToInputHandler(
input_delegate_ = std::move(delegate);
}
+void LayerTreeHostImpl::SetVisualDeviceViewportSize(
+ const gfx::Size& visual_device_viewport_size) {
+ visual_device_viewport_size_ = visual_device_viewport_size;
+}
+
+gfx::Size LayerTreeHostImpl::VisualDeviceViewportSize() const {
+ return visual_device_viewport_size_;
+}
+
ScrollTree& LayerTreeHostImpl::GetScrollTree() const {
return active_tree_->property_trees()->scroll_tree;
}
@@ -3903,6 +3963,8 @@ LayerTreeHostImpl::ProcessCompositorDeltas() {
commit_data->page_scale_delta =
active_tree_->page_scale_factor()->PullDeltaForMainThread();
commit_data->is_pinch_gesture_active = active_tree_->PinchGestureActive();
+ commit_data->is_scroll_active =
+ input_delegate_ && GetInputHandler().IsCurrentlyScrolling();
// We should never process non-unit page_scale_delta for an OOPIF subframe.
// TODO(wjmaclean): Remove this DCHECK as a pre-condition to closing the bug.
// https://crbug.com/845097
@@ -4396,7 +4458,7 @@ void LayerTreeHostImpl::CreateUIResource(UIResourceId uid,
// fully filled by drawBitmap(), so we ensure they start empty. (See
// crbug.com/642011 for an example.)
scaled_canvas->clear(SK_ColorTRANSPARENT);
- scaled_canvas->drawBitmap(source_bitmap, 0, 0);
+ scaled_canvas->drawImage(source_bitmap.asImage(), 0, 0);
if (layer_tree_frame_sink_->context_provider()) {
SkPixmap pixmap;
@@ -4641,11 +4703,10 @@ void LayerTreeHostImpl::SetElementFilterMutated(
}
void LayerTreeHostImpl::OnCustomPropertyMutated(
- ElementId element_id,
- const std::string& custom_property_name,
- PaintWorkletInput::PropertyValue custom_property_value) {
- paint_worklet_tracker_.OnCustomPropertyMutated(
- element_id, custom_property_name, std::move(custom_property_value));
+ PaintWorkletInput::PropertyKey property_key,
+ PaintWorkletInput::PropertyValue property_value) {
+ paint_worklet_tracker_.OnCustomPropertyMutated(std::move(property_key),
+ std::move(property_value));
}
void LayerTreeHostImpl::SetElementBackdropFilterMutated(
@@ -4716,15 +4777,14 @@ void LayerTreeHostImpl::ElementIsAnimatingChanged(
tree->set_needs_update_draw_properties();
}
-void LayerTreeHostImpl::AnimationScalesChanged(ElementId element_id,
- ElementListType list_type,
- float maximum_scale,
- float starting_scale) {
+void LayerTreeHostImpl::MaximumScaleChanged(ElementId element_id,
+ ElementListType list_type,
+ float maximum_scale) {
if (LayerTreeImpl* tree = list_type == ElementListType::ACTIVE
? active_tree()
: pending_tree()) {
- tree->property_trees()->AnimationScalesChanged(element_id, maximum_scale,
- starting_scale);
+ tree->property_trees()->MaximumAnimationScaleChanged(element_id,
+ maximum_scale);
}
}
@@ -4758,11 +4818,6 @@ gfx::ScrollOffset LayerTreeHostImpl::GetScrollOffsetForAnimation(
return gfx::ScrollOffset();
}
-bool LayerTreeHostImpl::SupportsImplScrolling() const {
- // Supported in threaded mode.
- return task_runner_provider_->HasImplThread();
-}
-
bool LayerTreeHostImpl::CommitToActiveTree() const {
return settings_.commit_to_active_tree;
}
@@ -4846,6 +4901,20 @@ void LayerTreeHostImpl::SetUkmSmoothnessDestination(
ukm_smoothness_mapping_.GetMemoryAs<UkmSmoothnessDataShared>());
}
+void LayerTreeHostImpl::NotifyDidPresentCompositorFrameOnImplThread(
+ uint32_t frame_token,
+ PresentationTimeCallbackBuffer::PendingCallbacks callbacks,
+ const viz::FrameTimingDetails& details) {
+ frame_trackers_.NotifyFramePresented(frame_token,
+ details.presentation_feedback);
+ // The callbacks in |compositor_thread_callbacks| expect to be run on the
+ // compositor thread so we'll run them now.
+ for (LayerTreeHost::PresentationTimeCallback& callback :
+ callbacks.compositor_thread_callbacks) {
+ std::move(callback).Run(details.presentation_feedback);
+ }
+}
+
void LayerTreeHostImpl::AllocateLocalSurfaceId() {
child_local_surface_id_allocator_.GenerateId();
}
diff --git a/chromium/cc/trees/layer_tree_host_impl.h b/chromium/cc/trees/layer_tree_host_impl.h
index eee1d46bc15..d62e352010b 100644
--- a/chromium/cc/trees/layer_tree_host_impl.h
+++ b/chromium/cc/trees/layer_tree_host_impl.h
@@ -41,6 +41,7 @@
#include "cc/metrics/total_frame_counter.h"
#include "cc/paint/discardable_image_map.h"
#include "cc/paint/paint_worklet_job.h"
+#include "cc/raster/raster_query_queue.h"
#include "cc/resources/ui_resource_client.h"
#include "cc/scheduler/begin_frame_tracker.h"
#include "cc/scheduler/commit_earlyout_reason.h"
@@ -62,6 +63,7 @@
#include "cc/trees/presentation_time_callback_buffer.h"
#include "cc/trees/render_frame_metadata.h"
#include "cc/trees/task_runner_provider.h"
+#include "cc/trees/throttle_decider.h"
#include "cc/trees/ukm_manager.h"
#include "components/viz/client/client_resource_provider.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
@@ -161,10 +163,11 @@ class LayerTreeHostImplClient {
virtual void RequestBeginMainFrameNotExpected(bool new_state) = 0;
// Called when a presentation time is requested. |frame_token| identifies
- // the frame that was presented.
+ // the frame that was presented. |callbacks| holds both impl side and main
+ // side callbacks to be called.
virtual void DidPresentCompositorFrameOnImplThread(
uint32_t frame_token,
- std::vector<LayerTreeHost::PresentationTimeCallback> callbacks,
+ PresentationTimeCallbackBuffer::PendingCallbacks callbacks,
const viz::FrameTimingDetails& details) = 0;
// Returns whether the main-thread is expected to receive a BeginMainFrame.
@@ -188,6 +191,9 @@ class LayerTreeHostImplClient {
// code as a result.
virtual bool IsInSynchronousComposite() const = 0;
+ virtual void FrameSinksToThrottleUpdated(
+ const base::flat_set<viz::FrameSinkId>& ids) = 0;
+
protected:
virtual ~LayerTreeHostImplClient() = default;
};
@@ -372,12 +378,23 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient,
void DidScrollContent(ElementId element_id, bool animated) override;
float DeviceScaleFactor() const override;
float PageScaleFactor() const override;
+ gfx::Size VisualDeviceViewportSize() const override;
const LayerTreeSettings& GetSettings() const override;
LayerTreeHostImpl& GetImplDeprecated() override;
const LayerTreeHostImpl& GetImplDeprecated() const override;
+ bool CanInjectJankOnMain() const;
FrameSequenceTrackerCollection& frame_trackers() { return frame_trackers_; }
+ // VisualDeviceViewportSize is the size of the global viewport across all
+ // compositors that are part of the scene that this compositor contributes to
+ // (i.e. the visual viewport), allowing for that scene to be broken up into
+ // multiple compositors that each contribute to the whole (e.g. cross-origin
+ // iframes are isolated from each other). This is a size instead of a rect
+ // because each compositor doesn't know its position relative to other
+ // compositors. This is specified in device viewport coordinate space.
+ void SetVisualDeviceViewportSize(const gfx::Size&);
+
// Updates registered ElementIds present in |changed_list|. Call this after
// changing the property trees for the |changed_list| trees.
void UpdateElements(ElementListType changed_list);
@@ -422,14 +439,12 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient,
ElementListType list_type,
const PropertyAnimationState& mask,
const PropertyAnimationState& state) override;
- void AnimationScalesChanged(ElementId element_id,
- ElementListType list_type,
- float maximum_scale,
- float starting_scale) override;
+ void MaximumScaleChanged(ElementId element_id,
+ ElementListType list_type,
+ float maximum_scale) override;
void OnCustomPropertyMutated(
- ElementId element_id,
- const std::string& custom_property_name,
- PaintWorkletInput::PropertyValue custom_property_value) override;
+ PaintWorkletInput::PropertyKey property_key,
+ PaintWorkletInput::PropertyValue property_value) override;
void ScrollOffsetAnimationFinished() override;
gfx::ScrollOffset GetScrollOffsetForAnimation(
@@ -730,7 +745,6 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient,
// Only valid for synchronous (non-scheduled) single-threaded case.
void SynchronouslyInitializeAllTiles();
- bool SupportsImplScrolling() const;
bool CommitToActiveTree() const;
// Virtual so tests can inject their own.
@@ -790,6 +804,13 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient,
void SetUkmSmoothnessDestination(
base::WritableSharedMemoryMapping ukm_smoothness_data);
+ // Notifies FrameTrackers, impl side callbacks that the compsitor frame
+ // was presented.
+ void NotifyDidPresentCompositorFrameOnImplThread(
+ uint32_t frame_token,
+ PresentationTimeCallbackBuffer::PendingCallbacks callbacks,
+ const viz::FrameTimingDetails& details);
+
CompositorFrameReportingController* compositor_frame_reporting_controller()
const {
return compositor_frame_reporting_controller_.get();
@@ -818,6 +839,10 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient,
return client_->IsInSynchronousComposite();
}
+ RasterQueryQueue* GetRasterQueryQueueForTesting() const {
+ return pending_raster_queries_.get();
+ }
+
protected:
LayerTreeHostImpl(
const LayerTreeSettings& settings,
@@ -1012,6 +1037,7 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient,
GpuRasterizationStatus::OFF_DEVICE;
std::unique_ptr<RasterBufferProvider> raster_buffer_provider_;
std::unique_ptr<ResourcePool> resource_pool_;
+ std::unique_ptr<RasterQueryQueue> pending_raster_queries_;
std::unique_ptr<ImageDecodeCache> image_decode_cache_;
GlobalStateThatImpactsTilePriority global_tile_state_;
@@ -1111,6 +1137,8 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient,
std::unique_ptr<Viewport> viewport_;
+ gfx::Size visual_device_viewport_size_;
+
std::unique_ptr<PendingTreeRasterDurationHistogramTimer>
pending_tree_raster_duration_timer_;
@@ -1207,6 +1235,10 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient,
// mutable because |contains_srgb_cache_| is accessed in a const method.
mutable base::MRUCache<gfx::ColorSpace, bool> contains_srgb_cache_;
+ // When enabled, calculates which frame sinks can be throttled based on
+ // some pre-defined criteria.
+ ThrottleDecider throttle_decider_;
+
// 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 a9c0a3e8e39..3c78b9ea2eb 100644
--- a/chromium/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/chromium/cc/trees/layer_tree_host_impl_unittest.cc
@@ -26,9 +26,9 @@
#include "build/build_config.h"
#include "cc/animation/animation_host.h"
#include "cc/animation/animation_id_provider.h"
-#include "cc/animation/transform_operations.h"
#include "cc/base/features.h"
#include "cc/base/histograms.h"
+#include "cc/document_transition/document_transition_request.h"
#include "cc/input/browser_controls_offset_manager.h"
#include "cc/input/main_thread_scrolling_reason.h"
#include "cc/input/page_scale_animation.h"
@@ -100,6 +100,7 @@
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/geometry/vector2d_conversions.h"
+#include "ui/gfx/transform_operations.h"
#define EXPECT_SCOPED(statements) \
{ \
@@ -260,8 +261,12 @@ class LayerTreeHostImplTest : public testing::Test,
void RequestBeginMainFrameNotExpected(bool new_state) override {}
void DidPresentCompositorFrameOnImplThread(
uint32_t frame_token,
- std::vector<LayerTreeHost::PresentationTimeCallback> callbacks,
- const viz::FrameTimingDetails& details) override {}
+ PresentationTimeCallbackBuffer::PendingCallbacks activated,
+ const viz::FrameTimingDetails& details) override {
+ std::move(activated.main_thread_callbacks);
+ host_impl_->NotifyDidPresentCompositorFrameOnImplThread(
+ frame_token, std::move(activated), details);
+ }
void NotifyAnimationWorkletStateChange(AnimationWorkletMutationState state,
ElementListType tree_type) override {}
void NotifyPaintWorkletStateChange(
@@ -274,6 +279,8 @@ class LayerTreeHostImplTest : public testing::Test,
first_scroll_observed++;
}
bool IsInSynchronousComposite() const override { return false; }
+ void FrameSinksToThrottleUpdated(
+ const base::flat_set<viz::FrameSinkId>& ids) override {}
void set_reduce_memory_result(bool reduce_memory_result) {
reduce_memory_result_ = reduce_memory_result;
}
@@ -423,6 +430,7 @@ class LayerTreeHostImplTest : public testing::Test,
auto* root =
SetupRootLayer<LayerImpl>(layer_tree_impl, inner_viewport_size);
SetupViewport(root, outer_viewport_size, content_size);
+ host_impl_->SetVisualDeviceViewportSize(inner_viewport_size);
UpdateDrawProperties(layer_tree_impl);
layer_tree_impl->DidBecomeActive();
@@ -518,7 +526,7 @@ class LayerTreeHostImplTest : public testing::Test,
ASSERT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
ASSERT_TRUE(status.needs_main_thread_hit_test);
} else {
- ASSERT_EQ(ScrollThread::SCROLL_UNKNOWN, status.thread);
+ ASSERT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread);
ASSERT_EQ(MainThreadScrollingReason::kFailedHitTest,
status.main_thread_scrolling_reasons);
}
@@ -533,7 +541,7 @@ class LayerTreeHostImplTest : public testing::Test,
ASSERT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
ASSERT_TRUE(status.needs_main_thread_hit_test);
} else {
- ASSERT_EQ(ScrollThread::SCROLL_UNKNOWN, status.thread);
+ ASSERT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread);
ASSERT_EQ(MainThreadScrollingReason::kFailedHitTest,
status.main_thread_scrolling_reasons);
}
@@ -1635,7 +1643,7 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest,
status.main_thread_scrolling_reasons);
EXPECT_TRUE(status.needs_main_thread_hit_test);
} else {
- EXPECT_EQ(ScrollThread::SCROLL_UNKNOWN, status.thread);
+ EXPECT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread);
EXPECT_EQ(MainThreadScrollingReason::kFailedHitTest,
status.main_thread_scrolling_reasons);
}
@@ -1665,9 +1673,13 @@ class LayerTreeHostImplTestInvokeMainThreadCallbacks
public:
void DidPresentCompositorFrameOnImplThread(
uint32_t frame_token,
- std::vector<LayerTreeHost::PresentationTimeCallback> callbacks,
+ PresentationTimeCallbackBuffer::PendingCallbacks activated,
const viz::FrameTimingDetails& details) override {
- for (LayerTreeHost::PresentationTimeCallback& callback : callbacks) {
+ auto main_thread_callbacks = std::move(activated.main_thread_callbacks);
+ host_impl_->NotifyDidPresentCompositorFrameOnImplThread(
+ frame_token, std::move(activated), details);
+ for (LayerTreeHost::PresentationTimeCallback& callback :
+ main_thread_callbacks) {
std::move(callback).Run(details.presentation_feedback);
}
}
@@ -2025,7 +2037,7 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest,
status.main_thread_scrolling_reasons);
ASSERT_TRUE(status.needs_main_thread_hit_test);
} else {
- ASSERT_EQ(ScrollThread::SCROLL_UNKNOWN, status.thread);
+ ASSERT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread);
ASSERT_EQ(MainThreadScrollingReason::kFailedHitTest,
status.main_thread_scrolling_reasons);
}
@@ -2081,7 +2093,7 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest,
status.main_thread_scrolling_reasons);
EXPECT_TRUE(status.needs_main_thread_hit_test);
} else {
- EXPECT_EQ(ScrollThread::SCROLL_UNKNOWN, status.thread);
+ EXPECT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread);
EXPECT_EQ(MainThreadScrollingReason::kFailedHitTest,
status.main_thread_scrolling_reasons);
}
@@ -2290,7 +2302,7 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, FixedLayerOverNonFixedLayer) {
status.main_thread_scrolling_reasons);
EXPECT_TRUE(status.needs_main_thread_hit_test);
} else {
- EXPECT_EQ(ScrollThread::SCROLL_UNKNOWN, status.thread);
+ EXPECT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread);
EXPECT_EQ(MainThreadScrollingReason::kFailedHitTest,
status.main_thread_scrolling_reasons);
}
@@ -2680,8 +2692,12 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, SnapAnimationTargetUpdated) {
AnimatedUpdateState(gfx::Point(10, 10), gfx::Vector2dF(0, -10)).get());
EXPECT_FALSE(GetInputHandler().animating_for_snap_for_testing());
// Finish the smooth scroll animation for wheel.
+ const int scroll_animation_duration_ms =
+ base::FeatureList::IsEnabled(features::kImpulseScrollAnimations) ? 300
+ : 150;
BeginImplFrameAndAnimate(begin_frame_args,
- start_time + base::TimeDelta::FromMilliseconds(150));
+ start_time + base::TimeDelta::FromMilliseconds(
+ scroll_animation_duration_ms));
// At the end of the previous scroll animation, a new animation for the
// snapping should have started.
@@ -3260,9 +3276,9 @@ TEST_F(CommitToPendingTreeLayerTreeHostImplTest,
CreateTransformNode(child);
// Add a translate from 6,7 to 8,9.
- TransformOperations start;
+ gfx::TransformOperations start;
start.AppendTranslate(6, 7, 0);
- TransformOperations end;
+ gfx::TransformOperations end;
end.AppendTranslate(8, 9, 0);
AddAnimatedTransformToElementWithAnimation(child->element_id(), timeline(),
4.0, start, end);
@@ -3355,9 +3371,9 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest,
CreateTransformNode(child);
// Add a translate animation.
- TransformOperations start;
+ gfx::TransformOperations start;
start.AppendTranslate(6, 7, 0);
- TransformOperations end;
+ gfx::TransformOperations end;
end.AppendTranslate(8, 9, 0);
AddAnimatedTransformToElementWithAnimation(child->element_id(), timeline(),
4.0, start, end);
@@ -11435,14 +11451,14 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, UIResourceManagement) {
host_impl_->CreateUIResource(ui_resource_id, bitmap);
EXPECT_EQ(1u, sii->shared_image_count());
viz::ResourceId id1 = host_impl_->ResourceIdForUIResource(ui_resource_id);
- EXPECT_NE(0u, id1);
+ EXPECT_NE(viz::kInvalidResourceId, id1);
// Multiple requests with the same id is allowed. The previous texture is
// deleted.
host_impl_->CreateUIResource(ui_resource_id, bitmap);
EXPECT_EQ(1u, sii->shared_image_count());
viz::ResourceId id2 = host_impl_->ResourceIdForUIResource(ui_resource_id);
- EXPECT_NE(0u, id2);
+ EXPECT_NE(viz::kInvalidResourceId, id2);
EXPECT_NE(id1, id2);
// Deleting invalid UIResourceId is allowed and does not change state.
@@ -11451,11 +11467,12 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, UIResourceManagement) {
// Should return zero for invalid UIResourceId. Number of textures should
// not change.
- EXPECT_EQ(0u, host_impl_->ResourceIdForUIResource(-1));
+ EXPECT_EQ(viz::kInvalidResourceId, host_impl_->ResourceIdForUIResource(-1));
EXPECT_EQ(1u, sii->shared_image_count());
host_impl_->DeleteUIResource(ui_resource_id);
- EXPECT_EQ(0u, host_impl_->ResourceIdForUIResource(ui_resource_id));
+ EXPECT_EQ(viz::kInvalidResourceId,
+ host_impl_->ResourceIdForUIResource(ui_resource_id));
EXPECT_EQ(0u, sii->shared_image_count());
// Should not change state for multiple deletion on one UIResourceId
@@ -11485,7 +11502,7 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, CreateETC1UIResource) {
host_impl_->CreateUIResource(ui_resource_id, bitmap);
EXPECT_EQ(1u, sii->shared_image_count());
viz::ResourceId id1 = host_impl_->ResourceIdForUIResource(ui_resource_id);
- EXPECT_NE(0u, id1);
+ EXPECT_NE(viz::kInvalidResourceId, id1);
}
TEST_P(ScrollUnifiedLayerTreeHostImplTest, ObeyMSAACaps) {
@@ -11651,7 +11668,7 @@ TEST_P(LayerTreeHostImplTestWithRenderer, ShutdownReleasesContext) {
// LayerTreeHostImpl::IsInitialScrollHitTestReliable for details.
TEST_P(ScrollUnifiedLayerTreeHostImplTest, ScrollHitTestIsNotReliable) {
// If we ray cast a scroller that is not on the first layer's ancestor chain,
- // we should return ScrollThread::SCROLL_UNKNOWN.
+ // we should return ScrollThread::SCROLL_ON_MAIN_THREAD.
gfx::Size viewport_size(50, 50);
gfx::Size content_size(100, 100);
SetupViewportLayersOuterScrolls(viewport_size, content_size);
@@ -11677,7 +11694,7 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, ScrollHitTestIsNotReliable) {
EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
EXPECT_TRUE(status.needs_main_thread_hit_test);
} else {
- EXPECT_EQ(ScrollThread::SCROLL_UNKNOWN, status.thread);
+ EXPECT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread);
EXPECT_EQ(MainThreadScrollingReason::kFailedHitTest,
status.main_thread_scrolling_reasons);
}
@@ -11688,7 +11705,7 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, ScrollHitTestIsNotReliable) {
TEST_P(ScrollUnifiedLayerTreeHostImplTest, ScrollHitTestAncestorMismatch) {
// If we ray cast a scroller this is on the first layer's ancestor chain, but
// is not the first scroller we encounter when walking up from the layer, we
- // should also return ScrollThread::SCROLL_UNKNOWN.
+ // should also return ScrollThread::SCROLL_ON_MAIN_THREAD.
gfx::Size viewport_size(50, 50);
gfx::Size content_size(100, 100);
SetupViewportLayersOuterScrolls(viewport_size, content_size);
@@ -11720,7 +11737,7 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, ScrollHitTestAncestorMismatch) {
EXPECT_EQ(ScrollThread::SCROLL_ON_IMPL_THREAD, status.thread);
EXPECT_TRUE(status.needs_main_thread_hit_test);
} else {
- EXPECT_EQ(ScrollThread::SCROLL_UNKNOWN, status.thread);
+ EXPECT_EQ(ScrollThread::SCROLL_ON_MAIN_THREAD, status.thread);
EXPECT_EQ(MainThreadScrollingReason::kFailedHitTest,
status.main_thread_scrolling_reasons);
}
@@ -13885,14 +13902,14 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, FadedOutPaintedScrollbarHitTest) {
// MouseDown on the track of a scrollbar with opacity 0 should not produce a
// scroll.
- scrollbar->set_scrollbar_painted_opacity(0);
+ scrollbar->SetScrollbarPaintedOpacity(0);
InputHandlerPointerResult result = GetInputHandler().MouseDown(
gfx::PointF(350, 100), /*jump_key_modifier*/ false);
EXPECT_EQ(result.scroll_offset.y(), 0u);
// MouseDown on the track of a scrollbar with opacity > 0 should produce a
// scroll.
- scrollbar->set_scrollbar_painted_opacity(1);
+ scrollbar->SetScrollbarPaintedOpacity(1);
result = GetInputHandler().MouseDown(gfx::PointF(350, 100),
/*jump_key_modifier*/ false);
EXPECT_GT(result.scroll_offset.y(), 0u);
@@ -14252,7 +14269,7 @@ TEST_F(LayerTreeHostImplTest, JumpOnScrollbarClick) {
InputHandlerPointerResult result = GetInputHandler().MouseDown(
gfx::PointF(350, 400), /*jump_key_modifier*/ true);
EXPECT_EQ(result.type, PointerResultType::kScrollbarScroll);
- EXPECT_EQ(result.scroll_offset.y(), 2194);
+ EXPECT_FLOAT_EQ(result.scroll_offset.y(), 2194.2856f);
result = GetInputHandler().MouseUp(gfx::PointF(350, 400));
EXPECT_EQ(result.type, PointerResultType::kScrollbarScroll);
EXPECT_EQ(result.scroll_offset.y(), 0);
@@ -14265,7 +14282,7 @@ TEST_F(LayerTreeHostImplTest, JumpOnScrollbarClick) {
InputHandlerPointerResult result = GetInputHandler().MouseDown(
gfx::PointF(350, 400), /*jump_key_modifier*/ false);
EXPECT_EQ(result.type, PointerResultType::kScrollbarScroll);
- EXPECT_EQ(result.scroll_offset.y(), 2194);
+ EXPECT_FLOAT_EQ(result.scroll_offset.y(), 2194.2856f);
result = GetInputHandler().MouseUp(gfx::PointF(350, 400));
EXPECT_EQ(result.type, PointerResultType::kScrollbarScroll);
EXPECT_EQ(result.scroll_offset.y(), 0);
@@ -14342,7 +14359,8 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, ThumbDragAfterJumpClick) {
gfx::PointF(350, 560), /*jump_key_modifier*/ true);
// This verifies that the jump click took place as expected.
- EXPECT_EQ(gfx::ScrollOffset(0, 243), result.scroll_offset);
+ EXPECT_EQ(0, result.scroll_offset.x());
+ EXPECT_FLOAT_EQ(result.scroll_offset.y(), 243.80952f);
// This verifies that the drag_state_ was initialized when a jump click
// occurred.
@@ -14351,10 +14369,93 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, ThumbDragAfterJumpClick) {
->drag_state_.has_value());
// This verifies that the jump click delta was accounted for correctly.
- EXPECT_EQ(GetInputHandler()
- .scrollbar_controller_for_testing()
- ->drag_state_->scroll_position_at_start_,
- 243);
+ EXPECT_FLOAT_EQ(GetInputHandler()
+ .scrollbar_controller_for_testing()
+ ->drag_state_->scroll_position_at_start_,
+ 243.80952f);
+ }
+
+ // Tear down the LayerTreeHostImpl before the InputHandlerClient.
+ host_impl_->ReleaseLayerTreeFrameSink();
+ host_impl_ = nullptr;
+}
+
+// Tests that an existing scroll offset animation (for a scrollbar) is aborted
+// before a new one is created.
+TEST_P(ScrollUnifiedLayerTreeHostImplTest,
+ AbortAnimatedScrollBeforeStartingAutoscroll) {
+ LayerTreeSettings settings = DefaultSettings();
+ settings.compositor_threaded_scrollbar_scrolling = true;
+ CreateHostImpl(settings, CreateLayerTreeFrameSink());
+
+ // Setup the viewport.
+ const gfx::Size viewport_size = gfx::Size(360, 600);
+ const gfx::Size content_size = gfx::Size(345, 3800);
+ SetupViewportLayersOuterScrolls(viewport_size, content_size);
+ LayerImpl* scroll_layer = OuterViewportScrollLayer();
+
+ // Set up the scrollbar and its dimensions.
+ LayerTreeImpl* layer_tree_impl = host_impl_->active_tree();
+ auto* scrollbar = AddLayer<PaintedScrollbarLayerImpl>(
+ layer_tree_impl, ScrollbarOrientation::VERTICAL,
+ /*is_left_side_vertical_scrollbar*/ false,
+ /*is_overlay*/ false);
+
+ SetupScrollbarLayer(scroll_layer, scrollbar);
+ const gfx::Size scrollbar_size = gfx::Size(15, 600);
+ scrollbar->SetBounds(scrollbar_size);
+ host_impl_->set_force_smooth_wheel_scrolling_for_testing(true);
+
+ // Set up the thumb dimensions.
+ scrollbar->SetThumbThickness(15);
+ scrollbar->SetThumbLength(50);
+ scrollbar->SetTrackRect(gfx::Rect(0, 15, 15, 575));
+
+ // Set up scrollbar arrows.
+ scrollbar->SetBackButtonRect(
+ gfx::Rect(gfx::Point(345, 0), gfx::Size(15, 15)));
+ scrollbar->SetForwardButtonRect(
+ gfx::Rect(gfx::Point(345, 570), gfx::Size(15, 15)));
+ scrollbar->SetOffsetToTransformParent(gfx::Vector2dF(345, 0));
+
+ TestInputHandlerClient input_handler_client;
+ GetInputHandler().BindToClient(&input_handler_client);
+
+ {
+ // Set up an animated scrollbar autoscroll.
+ GetInputHandler().scrollbar_controller_for_testing()->HandlePointerDown(
+ gfx::PointF(350, 560), /*jump_key_modifier*/ false);
+ auto begin_state = BeginState(gfx::Point(350, 560), gfx::Vector2d(0, 40),
+ ui::ScrollInputType::kScrollbar);
+ EXPECT_EQ(
+ ScrollThread::SCROLL_ON_IMPL_THREAD,
+ GetInputHandler()
+ .ScrollBegin(begin_state.get(), ui::ScrollInputType::kScrollbar)
+ .thread);
+ auto update_state = UpdateState(gfx::Point(350, 560), gfx::Vector2dF(0, 40),
+ ui::ScrollInputType::kScrollbar);
+ update_state->data()->delta_granularity =
+ ui::ScrollGranularity::kScrollByPixel;
+ GetInputHandler().ScrollUpdate(update_state.get());
+
+ // Autoscroll animations should be active.
+ EXPECT_TRUE(GetInputHandler()
+ .scrollbar_controller_for_testing()
+ ->ScrollbarScrollIsActive());
+ EXPECT_TRUE(GetImplAnimationHost()->ImplOnlyScrollAnimatingElement());
+ }
+
+ {
+ // When it's time to kick off the scrollbar autoscroll animation (i.e ~250ms
+ // after pointerdown), the ScrollbarController should ensure that any
+ // existing scroll offset animations are aborted and a new autoscroll
+ // animation is created. Test passes if unit test doesn't hit any DCHECK
+ // failures.
+ GetInputHandler()
+ .scrollbar_controller_for_testing()
+ ->StartAutoScrollAnimation(/*scroll_velocity*/ 800,
+ ScrollbarPart::FORWARD_TRACK);
+ EXPECT_TRUE(GetImplAnimationHost()->ImplOnlyScrollAnimatingElement());
}
// Tear down the LayerTreeHostImpl before the InputHandlerClient.
@@ -14530,7 +14631,7 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, ThumbDragScrollerLengthIncrease) {
host_impl_->WillBeginImplFrame(begin_frame_args);
result = GetInputHandler().MouseMoveAt(gfx::Point(350, 20));
- EXPECT_EQ(result.scroll_offset.y(), 12);
+ EXPECT_FLOAT_EQ(result.scroll_offset.y(), 12.190476f);
// This is intentional. The thumb drags that follow will test the behavior
// *after* the scroller length expansion.
@@ -14563,7 +14664,7 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, ThumbDragScrollerLengthIncrease) {
begin_frame_args.frame_id.sequence_number++;
host_impl_->WillBeginImplFrame(begin_frame_args);
result = GetInputHandler().MouseMoveAt(gfx::Point(350, 26));
- EXPECT_EQ(result.scroll_offset.y(), 49);
+ EXPECT_FLOAT_EQ(result.scroll_offset.y(), 48.761906f);
GetInputHandler().MouseUp(gfx::PointF(350, 26));
host_impl_->DidFinishImplFrame(begin_frame_args);
@@ -14618,7 +14719,7 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, MainThreadFallback) {
// InputHandlerPointerResult should return a zero offset. This will cause the
// main thread to handle the scroll.
GetScrollNode(scroll_layer)->main_thread_scrolling_reasons =
- MainThreadScrollingReason::kHasNonLayerViewportConstrainedObjects;
+ MainThreadScrollingReason::kThreadedScrollingDisabled;
compositor_threaded_scrolling_result = GetInputHandler().MouseDown(
gfx::PointF(350, 500), /*jump_key_modifier*/ false);
GetInputHandler().MouseUp(gfx::PointF(350, 500));
@@ -14761,7 +14862,10 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, ScrollAnimatedWithDelay) {
begin_frame_args.frame_id.sequence_number++;
host_impl_->WillBeginImplFrame(begin_frame_args);
host_impl_->UpdateAnimationState(true);
- EXPECT_EQ(50, CurrentScrollOffset(scrolling_layer).y());
+ EXPECT_NEAR(
+ (base::FeatureList::IsEnabled(features::kImpulseScrollAnimations) ? 87
+ : 50),
+ CurrentScrollOffset(scrolling_layer).y(), 1);
host_impl_->DidFinishImplFrame(begin_frame_args);
// Update target.
@@ -16306,9 +16410,9 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, UpdatedTilingsForNonDrawingLayers) {
// Now add a transform animation to this layer. While we don't drawn layers
// with non-invertible transforms, we still raster them if there is a
// transform animation.
- TransformOperations start_transform_operations;
+ gfx::TransformOperations start_transform_operations;
start_transform_operations.AppendMatrix(singular);
- TransformOperations end_transform_operations;
+ gfx::TransformOperations end_transform_operations;
AddAnimatedTransformToElementWithAnimation(
animated_transform_layer->element_id(), timeline(), 10.0,
start_transform_operations, end_transform_operations);
@@ -17403,7 +17507,7 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, PercentBasedScrollbarDeltasDSF3) {
GetInputHandler().BindToClient(&input_handler_client);
// Test scrolling with device scale factor = 3.
- const float expected_delta = floorf(kPercentDeltaForDirectionalScroll * 500);
+ const float expected_delta = kPercentDeltaForDirectionalScroll * 500;
host_impl_->active_tree()->set_painted_device_scale_factor(3);
@@ -18141,4 +18245,38 @@ TEST_F(LayerTreeHostImplTest, FrameElementIdHitTestOverlapSibling) {
GetInputHandler().FindFrameElementIdAtPoint(gfx::PointF(30, 30)));
}
+TEST_F(LayerTreeHostImplTest, DocumentTransitionRequestCausesDamage) {
+ const gfx::Size viewport_size(100, 100);
+ SetupDefaultRootLayer(viewport_size);
+ UpdateDrawProperties(host_impl_->active_tree());
+
+ const gfx::Transform draw_transform;
+ const gfx::Rect draw_viewport(viewport_size);
+ bool resourceless_software_draw = false;
+
+ // Clear any damage.
+ host_impl_->OnDraw(draw_transform, draw_viewport, resourceless_software_draw,
+ false);
+ last_on_draw_frame_.reset();
+ did_request_redraw_ = false;
+
+ // Ensure there is no damage.
+ host_impl_->OnDraw(draw_transform, draw_viewport, resourceless_software_draw,
+ false);
+ EXPECT_FALSE(did_request_redraw_);
+ EXPECT_TRUE(last_on_draw_frame_->has_no_damage);
+ last_on_draw_frame_.reset();
+ did_request_redraw_ = false;
+
+ // Adding a transition effect should cause us to redraw.
+ host_impl_->active_tree()->AddDocumentTransitionRequest(
+ DocumentTransitionRequest::CreateStart(base::OnceClosure()));
+
+ // Ensure there is damage and we requested a redraw.
+ host_impl_->OnDraw(draw_transform, draw_viewport, resourceless_software_draw,
+ false);
+ EXPECT_TRUE(did_request_redraw_);
+ EXPECT_FALSE(last_on_draw_frame_->has_no_damage);
+}
+
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_blending.cc b/chromium/cc/trees/layer_tree_host_pixeltest_blending.cc
index 496bdbf6da9..98bb4f49eb5 100644
--- a/chromium/cc/trees/layer_tree_host_pixeltest_blending.cc
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_blending.cc
@@ -123,7 +123,7 @@ class LayerTreeHostBlendingPixelTest
gfx::Size bounds(width, height);
backdrop_client_.set_bounds(bounds);
backdrop_client_.add_draw_image(backing_store->makeImageSnapshot(),
- gfx::Point(), PaintFlags());
+ gfx::Point());
scoped_refptr<FakePictureLayer> layer =
FakePictureLayer::Create(&backdrop_client_);
layer->SetIsDrawable(true);
@@ -146,8 +146,7 @@ class LayerTreeHostBlendingPixelTest
SkRect::MakeXYWH(1, 0, bounds.width() - 1, bounds.height()), paint);
mask_client_.set_bounds(bounds);
- mask_client_.add_draw_image(surface->makeImageSnapshot(), gfx::Point(),
- PaintFlags());
+ mask_client_.add_draw_image(surface->makeImageSnapshot(), gfx::Point());
scoped_refptr<FakePictureLayer> mask =
FakePictureLayer::Create(&mask_client_);
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc b/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc
index 3687e59cfa0..d0a756797cf 100644
--- a/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc
@@ -59,7 +59,7 @@ class LayerTreeHostFiltersPixelTest
};
FilterOperations filters;
- SkImageFilter::CropRect cropRect(
+ PaintFilter::CropRect cropRect(
SkRect::MakeXYWH(-40000, -40000, 80000, 80000));
filters.Append(FilterOperation::CreateReferenceFilter(
sk_make_sp<ColorFilterPaintFilter>(SkColorFilters::Matrix(matrix),
@@ -98,8 +98,7 @@ TEST_P(LayerTreeHostFiltersPixelTest, BackdropFilterBlurRect) {
background->AddChild(blur);
FilterOperations filters;
- filters.Append(FilterOperation::CreateBlurFilter(
- 2.f, SkBlurImageFilter::kClamp_TileMode));
+ filters.Append(FilterOperation::CreateBlurFilter(2.f, SkTileMode::kClamp));
blur->SetBackdropFilters(filters);
gfx::RRectF backdrop_filter_bounds(gfx::RectF(gfx::SizeF(blur->bounds())), 0);
blur->SetBackdropFilterBounds(backdrop_filter_bounds);
@@ -164,8 +163,7 @@ TEST_P(LayerTreeHostFiltersPixelTest, BackdropFilterBlurRadius) {
background->AddChild(blur);
FilterOperations filters;
- filters.Append(FilterOperation::CreateBlurFilter(
- 30.f, SkBlurImageFilter::kClamp_TileMode));
+ filters.Append(FilterOperation::CreateBlurFilter(30.f, SkTileMode::kClamp));
blur->SetBackdropFilters(filters);
gfx::RRectF backdrop_filter_bounds(gfx::RectF(gfx::SizeF(blur->bounds())), 0);
blur->SetBackdropFilterBounds(backdrop_filter_bounds);
@@ -206,8 +204,7 @@ TEST_P(LayerTreeHostFiltersPixelTest, BackdropFilterBlurRounded) {
background->AddChild(blur);
FilterOperations filters;
- filters.Append(FilterOperation::CreateBlurFilter(
- 2.f, SkBlurImageFilter::kClamp_TileMode));
+ filters.Append(FilterOperation::CreateBlurFilter(2.f, SkTileMode::kClamp));
blur->SetBackdropFilters(filters);
gfx::RRectF backdrop_filter_bounds(gfx::RectF(gfx::SizeF(blur->bounds())), 14,
16, 18, 20, 22, 30, 40, 50);
@@ -254,8 +251,7 @@ TEST_P(LayerTreeHostFiltersPixelTest, BackdropFilterBlurOutsets) {
background->AddChild(blur);
FilterOperations filters;
- filters.Append(FilterOperation::CreateBlurFilter(
- 5.f, SkBlurImageFilter::kClamp_TileMode));
+ filters.Append(FilterOperation::CreateBlurFilter(5.f, SkTileMode::kClamp));
blur->SetBackdropFilters(filters);
gfx::RRectF backdrop_filter_bounds(gfx::RectF(gfx::SizeF(blur->bounds())), 0);
blur->SetBackdropFilterBounds(backdrop_filter_bounds);
@@ -339,8 +335,7 @@ class LayerTreeHostBlurFiltersPixelTestGPULayerList
EffectNode& blur_effect_node = CreateEffectNode(blur_layers[0].get());
FilterOperations filters;
- filters.Append(FilterOperation::CreateBlurFilter(
- 2.f, SkBlurImageFilter::kClamp_TileMode));
+ filters.Append(FilterOperation::CreateBlurFilter(2.f, SkTileMode::kClamp));
blur_effect_node.backdrop_filters = filters;
blur_effect_node.render_surface_reason =
RenderSurfaceReason::kBackdropFilter;
@@ -497,7 +492,7 @@ TEST_P(LayerTreeHostFiltersPixelTest, CroppedFilter) {
// Check that a filter with a zero-height crop rect crops out its
// result completely.
FilterOperations filters;
- SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(0, 0, 100, 0));
+ PaintFilter::CropRect cropRect(SkRect::MakeXYWH(0, 0, 100, 0));
sk_sp<PaintFilter> offset(
sk_make_sp<OffsetPaintFilter>(0, 0, nullptr, &cropRect));
filters.Append(FilterOperation::CreateReferenceFilter(offset));
@@ -518,7 +513,7 @@ TEST_P(LayerTreeHostFiltersPixelTest, ImageFilterClipped) {
// This filter does a red-blue swap, so the foreground becomes blue.
matrix[2] = matrix[6] = matrix[10] = matrix[18] = 1.0f;
// We filter only the bottom 200x100 pixels of the foreground.
- SkImageFilter::CropRect crop_rect(SkRect::MakeXYWH(0, 100, 200, 100));
+ PaintFilter::CropRect crop_rect(SkRect::MakeXYWH(0, 100, 200, 100));
FilterOperations filters;
filters.Append(
FilterOperation::CreateReferenceFilter(sk_make_sp<ColorFilterPaintFilter>(
@@ -610,7 +605,11 @@ TEST_P(LayerTreeHostFiltersPixelTest, ImageFilterScaled) {
RunPixelTest(
background,
- base::FilePath(FILE_PATH_LITERAL("backdrop_filter_on_scaled_layer_.png"))
+ base::FilePath(
+ (use_swangle() || use_skia_vulkan())
+ ? FILE_PATH_LITERAL("backdrop_filter_on_scaled_layer_.png")
+ : FILE_PATH_LITERAL(
+ "backdrop_filter_on_scaled_layer_legacy_swiftshader_.png"))
.InsertBeforeExtensionASCII(GetRendererSuffix()));
}
@@ -644,8 +643,7 @@ TEST_P(LayerTreeHostFiltersPixelTest, BackdropFilterRotated) {
// Add a blur filter to the blue layer.
FilterOperations filters;
- filters.Append(FilterOperation::CreateBlurFilter(
- 5.0f, SkBlurImageFilter::kClamp_TileMode));
+ filters.Append(FilterOperation::CreateBlurFilter(5.0f, SkTileMode::kClamp));
filter_layer->SetBackdropFilters(filters);
gfx::RRectF backdrop_filter_bounds(
gfx::RectF(gfx::SizeF(filter_layer->bounds())), 0);
@@ -724,7 +722,11 @@ TEST_P(LayerTreeHostFiltersPixelTest, ImageRenderSurfaceScaled) {
RunPixelTest(
background,
- base::FilePath(FILE_PATH_LITERAL("scaled_render_surface_layer_.png"))
+ base::FilePath(
+ (use_swangle() || use_skia_vulkan())
+ ? FILE_PATH_LITERAL("scaled_render_surface_layer_.png")
+ : FILE_PATH_LITERAL(
+ "scaled_render_surface_layer_legacy_swiftshader_.png"))
.InsertBeforeExtensionASCII(GetRendererSuffix()));
}
@@ -1019,7 +1021,7 @@ TEST_P(LayerTreeHostFiltersPixelTest, EnlargedTextureWithCropOffsetFilter) {
filter_layer->AddChild(child2);
FilterOperations filters;
- SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(10, 10, 80, 80));
+ PaintFilter::CropRect cropRect(SkRect::MakeXYWH(10, 10, 80, 80));
filters.Append(FilterOperation::CreateReferenceFilter(
sk_make_sp<OffsetPaintFilter>(0, 0, nullptr, &cropRect)));
filter_layer->SetFilters(filters);
@@ -1052,8 +1054,7 @@ TEST_P(LayerTreeHostFiltersPixelTest, BlurFilterWithClip) {
filter_layer->AddChild(child4);
FilterOperations filters;
- filters.Append(FilterOperation::CreateBlurFilter(
- 2.f, SkBlurImageFilter::kClamp_TileMode));
+ filters.Append(FilterOperation::CreateBlurFilter(2.f, SkTileMode::kClamp));
filter_layer->SetFilters(filters);
// Force the allocation a larger textures.
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc b/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc
index 63b1f719917..f0f9fe67a4e 100644
--- a/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc
@@ -59,7 +59,7 @@ class MaskContentLayerClient : public ContentLayerClient {
bool FillsBoundsCompletely() const override { return false; }
- gfx::Rect PaintableRegion() override { return gfx::Rect(bounds_); }
+ gfx::Rect PaintableRegion() const override { return gfx::Rect(bounds_); }
scoped_refptr<DisplayItemList> PaintContentsToDisplayList() override {
auto display_list = base::MakeRefCounted<DisplayItemList>();
@@ -192,7 +192,7 @@ class SolidColorEmptyMaskContentLayerClient : public ContentLayerClient {
bool FillsBoundsCompletely() const override { return false; }
- gfx::Rect PaintableRegion() override { return gfx::Rect(bounds_); }
+ gfx::Rect PaintableRegion() const override { return gfx::Rect(bounds_); }
scoped_refptr<DisplayItemList> PaintContentsToDisplayList() override {
// Intentionally return a solid color, empty mask display list. This
@@ -333,8 +333,7 @@ TEST_P(LayerTreeHostMaskPixelTestWithLayerList, ImageMaskWithEffect) {
FakeContentLayerClient layer_client;
layer_client.set_bounds(mask_bounds_);
- layer_client.add_draw_image(surface->makeImageSnapshot(), gfx::Point(),
- PaintFlags());
+ layer_client.add_draw_image(surface->makeImageSnapshot(), gfx::Point());
mask_layer_ = FakePictureLayer::Create(&layer_client);
pixel_comparator_ =
@@ -361,8 +360,7 @@ TEST_P(LayerTreeHostMasksPixelTest, ImageMaskOfLayer) {
FakeContentLayerClient mask_client;
mask_client.set_bounds(mask_bounds);
- mask_client.add_draw_image(surface->makeImageSnapshot(), gfx::Point(),
- PaintFlags());
+ mask_client.add_draw_image(surface->makeImageSnapshot(), gfx::Point());
scoped_refptr<FakePictureLayer> mask = FakePictureLayer::Create(&mask_client);
mask->SetIsDrawable(true);
mask->SetBounds(mask_bounds);
@@ -441,7 +439,7 @@ class CheckerContentLayerClient : public ContentLayerClient {
: bounds_(bounds), color_(color), vertical_(vertical) {}
~CheckerContentLayerClient() override = default;
bool FillsBoundsCompletely() const override { return false; }
- gfx::Rect PaintableRegion() override { return gfx::Rect(bounds_); }
+ gfx::Rect PaintableRegion() const override { return gfx::Rect(bounds_); }
scoped_refptr<DisplayItemList> PaintContentsToDisplayList() override {
auto display_list = base::MakeRefCounted<DisplayItemList>();
display_list->StartPaint();
@@ -488,7 +486,7 @@ class CircleContentLayerClient : public ContentLayerClient {
: bounds_(bounds) {}
~CircleContentLayerClient() override = default;
bool FillsBoundsCompletely() const override { return false; }
- gfx::Rect PaintableRegion() override { return gfx::Rect(bounds_); }
+ gfx::Rect PaintableRegion() const override { return gfx::Rect(bounds_); }
scoped_refptr<DisplayItemList> PaintContentsToDisplayList() override {
auto display_list = base::MakeRefCounted<DisplayItemList>();
display_list->StartPaint();
@@ -713,7 +711,7 @@ class StaticPictureLayer : private ContentLayerClient, public PictureLayer {
new StaticPictureLayer(std::move(display_list)));
}
- gfx::Rect PaintableRegion() override { return gfx::Rect(bounds()); }
+ gfx::Rect PaintableRegion() const override { return gfx::Rect(bounds()); }
scoped_refptr<DisplayItemList> PaintContentsToDisplayList() override {
return display_list_;
}
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc b/chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc
index d8c4420ce21..b531ed8694d 100644
--- a/chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc
@@ -173,14 +173,22 @@ TEST_P(LayerTreeHostScrollbarsPixelTest, MAYBE_HugeTransformScale) {
scale_transform.Scale(scale, scale);
layer->SetTransform(scale_transform);
- if (renderer_type_ == viz::RendererType::kSkiaGL ||
+ if (use_swangle() || use_skia_vulkan() ||
+ renderer_type_ == viz::RendererType::kSkiaGL ||
renderer_type_ == viz::RendererType::kSkiaDawn)
pixel_comparator_ = std::make_unique<FuzzyPixelOffByOneComparator>(true);
- RunPixelTest(background,
- use_skia_vulkan()
- ? base::FilePath(FILE_PATH_LITERAL("spiral_64_scale_vk.png"))
- : base::FilePath(FILE_PATH_LITERAL("spiral_64_scale.png")));
+ RunPixelTest(
+ background,
+ base::FilePath(
+ use_swangle()
+ ? (use_skia_vulkan() ? FILE_PATH_LITERAL("spiral_64_scale_vk.png")
+ : FILE_PATH_LITERAL("spiral_64_scale.png"))
+ : (use_skia_vulkan()
+ ? FILE_PATH_LITERAL(
+ "spiral_64_scale_legacy_swiftshader_vk.png")
+ : FILE_PATH_LITERAL(
+ "spiral_64_scale_legacy_swiftshader.png"))));
}
class LayerTreeHostOverlayScrollbarsPixelTest
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc b/chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc
index d837df92f79..a3f7a12b671 100644
--- a/chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc
@@ -71,7 +71,7 @@ class BlueYellowClient : public ContentLayerClient {
explicit BlueYellowClient(const gfx::Size& size)
: size_(size), blue_top_(true) {}
- gfx::Rect PaintableRegion() override { return gfx::Rect(size_); }
+ gfx::Rect PaintableRegion() const override { return gfx::Rect(size_); }
scoped_refptr<DisplayItemList> PaintContentsToDisplayList() override {
auto display_list = base::MakeRefCounted<DisplayItemList>();
@@ -151,7 +151,7 @@ class PrimaryColorClient : public ContentLayerClient {
public:
explicit PrimaryColorClient(const gfx::Size& size) : size_(size) {}
- gfx::Rect PaintableRegion() override { return gfx::Rect(size_); }
+ gfx::Rect PaintableRegion() const override { return gfx::Rect(size_); }
scoped_refptr<DisplayItemList> PaintContentsToDisplayList() override {
// When painted, the DisplayItemList should produce blocks of red, green,
// and blue to test primary color reproduction.
@@ -353,7 +353,8 @@ TEST_P(LayerTreeHostTilesTestRasterColorSpace, CustomColorSpace) {
// This test doesn't work on Vulkan because on our hardware we can't render to
// RGBA4444 format using either SwiftShader or native Vulkan. See
-// crbug.com/987278 for details
+// crbug.com/987278 for details.
+// TODO(crbug.com/1151490) : Re-enable after this is supported for OOPR.
#if BUILDFLAG(ENABLE_GL_BACKEND_TESTS)
class LayerTreeHostTilesTestPartialInvalidationLowBitDepth
: public LayerTreeHostTilesTestPartialInvalidation {
@@ -373,14 +374,16 @@ INSTANTIATE_TEST_SUITE_P(
RasterTestConfig{viz::RendererType::kGL, TestRasterType::kGpu}),
::testing::PrintToStringParamName());
-TEST_P(LayerTreeHostTilesTestPartialInvalidationLowBitDepth, PartialRaster) {
+TEST_P(LayerTreeHostTilesTestPartialInvalidationLowBitDepth,
+ DISABLED_PartialRaster) {
use_partial_raster_ = true;
RunSingleThreadedPixelTest(picture_layer_,
base::FilePath(FILE_PATH_LITERAL(
"blue_yellow_partial_flipped_dither.png")));
}
-TEST_P(LayerTreeHostTilesTestPartialInvalidationLowBitDepth, FullRaster) {
+TEST_P(LayerTreeHostTilesTestPartialInvalidationLowBitDepth,
+ DISABLED_FullRaster) {
RunSingleThreadedPixelTest(
picture_layer_,
base::FilePath(FILE_PATH_LITERAL("blue_yellow_flipped_dither.png")));
diff --git a/chromium/cc/trees/layer_tree_host_single_thread_client.h b/chromium/cc/trees/layer_tree_host_single_thread_client.h
index f2ce8e18597..f35d3cfd6b2 100644
--- a/chromium/cc/trees/layer_tree_host_single_thread_client.h
+++ b/chromium/cc/trees/layer_tree_host_single_thread_client.h
@@ -5,7 +5,9 @@
#ifndef CC_TREES_LAYER_TREE_HOST_SINGLE_THREAD_CLIENT_H_
#define CC_TREES_LAYER_TREE_HOST_SINGLE_THREAD_CLIENT_H_
+#include "base/containers/flat_set.h"
#include "base/time/time.h"
+#include "components/viz/common/surfaces/frame_sink_id.h"
namespace cc {
@@ -31,6 +33,12 @@ class LayerTreeHostSingleThreadClient {
// run the machinery to acquire a new LayerTreeFrameSink.
virtual void DidLoseLayerTreeFrameSink() = 0;
+ // When compositing-based throttling is enabled, this function is called every
+ // time when a frame composition change has updated the frame sinks to
+ // throttle.
+ virtual void FrameSinksToThrottleUpdated(
+ const base::flat_set<viz::FrameSinkId>& ids) {}
+
protected:
virtual ~LayerTreeHostSingleThreadClient() {}
};
diff --git a/chromium/cc/trees/layer_tree_host_unittest.cc b/chromium/cc/trees/layer_tree_host_unittest.cc
index 163146ca91e..79ceaf87f18 100644
--- a/chromium/cc/trees/layer_tree_host_unittest.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest.cc
@@ -12,16 +12,18 @@
#include "base/auto_reset.h"
#include "base/bind.h"
#include "base/callback_helpers.h"
+#include "base/containers/contains.h"
#include "base/location.h"
#include "base/single_thread_task_runner.h"
-#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/lock.h"
+#include "base/test/bind.h"
+#include "base/test/simple_test_tick_clock.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "cc/animation/animation_host.h"
-#include "cc/animation/timing_function.h"
+#include "cc/document_transition/document_transition_request.h"
#include "cc/input/scroll_elasticity_helper.h"
#include "cc/layers/content_layer_client.h"
#include "cc/layers/heads_up_display_layer.h"
@@ -66,6 +68,7 @@
#include "components/viz/common/frame_sinks/begin_frame_args.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "components/viz/common/frame_sinks/copy_output_result.h"
+#include "components/viz/common/quads/compositor_frame_transition_directive.h"
#include "components/viz/common/quads/compositor_render_pass_draw_quad.h"
#include "components/viz/common/quads/draw_quad.h"
#include "components/viz/common/quads/tile_draw_quad.h"
@@ -79,6 +82,7 @@
#include "third_party/khronos/GLES2/gl2ext.h"
#include "third_party/skia/include/core/SkPicture.h"
#include "third_party/skia/include/gpu/GrDirectContext.h"
+#include "ui/gfx/animation/keyframe/timing_function.h"
#include "ui/gfx/geometry/point_conversions.h"
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/geometry/vector2d_conversions.h"
@@ -913,8 +917,7 @@ class LayerTreeHostTestInvisibleLayersSkipRenderPass
void AddBackgroundBlurFilter(Layer* layer) {
FilterOperations filters;
- filters.Append(FilterOperation::CreateBlurFilter(
- 30, SkBlurImageFilter::kClamp_TileMode));
+ filters.Append(FilterOperation::CreateBlurFilter(30, SkTileMode::kClamp));
layer->SetBackdropFilters(filters);
}
@@ -8267,7 +8270,7 @@ class LayerTreeHostTestImageAnimationDrawImage
private:
void AddImageOp(const PaintImage& image) override {
- content_layer_client_.add_draw_image(image, gfx::Point(0, 0), PaintFlags());
+ content_layer_client_.add_draw_image(image, gfx::Point(0, 0));
}
};
@@ -8289,7 +8292,7 @@ class LayerTreeHostTestImageAnimationDrawRecordShader
: public LayerTreeHostTestImageAnimation {
void AddImageOp(const PaintImage& image) override {
auto record = sk_make_sp<PaintOpBuffer>();
- record->push<DrawImageOp>(image, 0.f, 0.f, nullptr);
+ record->push<DrawImageOp>(image, 0.f, 0.f);
PaintFlags flags;
flags.setShader(PaintShader::MakePaintRecord(
record, SkRect::MakeWH(500, 500), SkTileMode::kClamp,
@@ -8304,7 +8307,7 @@ class LayerTreeHostTestImageAnimationPaintFilter
: public LayerTreeHostTestImageAnimation {
void AddImageOp(const PaintImage& image) override {
auto record = sk_make_sp<PaintOpBuffer>();
- record->push<DrawImageOp>(image, 0.f, 0.f, nullptr);
+ record->push<DrawImageOp>(image, 0.f, 0.f);
PaintFlags flags;
flags.setImageFilter(
sk_make_sp<RecordPaintFilter>(record, SkRect::MakeWH(500, 500)));
@@ -8380,12 +8383,9 @@ class LayerTreeHostTestImageDecodingHints : public LayerTreeHostTest {
.set_id(3)
.set_decoding_mode(PaintImage::DecodingMode::kUnspecified)
.TakePaintImage();
- content_layer_client_.add_draw_image(async_image, gfx::Point(0, 0),
- PaintFlags());
- content_layer_client_.add_draw_image(sync_image, gfx::Point(1, 2),
- PaintFlags());
- content_layer_client_.add_draw_image(unspecified_image, gfx::Point(3, 4),
- PaintFlags());
+ content_layer_client_.add_draw_image(async_image, gfx::Point(0, 0));
+ content_layer_client_.add_draw_image(sync_image, gfx::Point(1, 2));
+ content_layer_client_.add_draw_image(unspecified_image, gfx::Point(3, 4));
layer_tree_host()->SetRootLayer(
FakePictureLayer::Create(&content_layer_client_));
@@ -8817,7 +8817,7 @@ MULTI_THREAD_TEST_F(LayerTreeHostTopControlsDeltaTriggersViewportUpdate);
// Tests that custom sequence throughput tracking result is reported to
// LayerTreeHostClient.
constexpr MutatorHost::TrackedAnimationSequenceId kSequenceId = 1u;
-class LayerTreeHostCustomThrougputTrackerTest : public LayerTreeHostTest {
+class LayerTreeHostCustomThroughputTrackerTest : public LayerTreeHostTest {
public:
void BeginTest() override { PostSetNeedsCommitToMainThread(); }
@@ -8850,7 +8850,7 @@ class LayerTreeHostCustomThrougputTrackerTest : public LayerTreeHostTest {
}
};
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCustomThrougputTrackerTest);
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCustomThroughputTrackerTest);
// Confirm that DelegatedInkMetadata set on the LTH propagates to the
// CompositorFrameMetadata and RenderFrameMetadata, and then both are correctly
@@ -8901,9 +8901,10 @@ class LayerTreeHostTestDelegatedInkMetadataOnAndOff
gfx::PointF point = gfx::PointF(135, 45);
gfx::RectF area = gfx::RectF(173, 438);
base::TimeTicks timestamp = base::TimeTicks::Now();
+ bool is_hovering = true;
- expected_metadata_ =
- viz::DelegatedInkMetadata(point, diameter, color, timestamp, area);
+ expected_metadata_ = viz::DelegatedInkMetadata(
+ point, diameter, color, timestamp, area, is_hovering);
layer_tree_host()->SetDelegatedInkMetadata(
std::make_unique<viz::DelegatedInkMetadata>(
expected_metadata_.value()));
@@ -8925,24 +8926,29 @@ class LayerTreeHostTestDelegatedInkMetadataOnAndOff
}
}
- void ExpectMetadata(bool had_delegated_ink_metadata,
+ void ExpectMetadata(base::Optional<DelegatedInkBrowserMetadata>
+ browser_delegated_ink_metadata,
viz::DelegatedInkMetadata* actual_metadata) {
if (expected_metadata_.has_value()) {
- EXPECT_TRUE(had_delegated_ink_metadata);
+ EXPECT_TRUE(browser_delegated_ink_metadata.has_value());
EXPECT_TRUE(actual_metadata);
+ EXPECT_TRUE(
+ browser_delegated_ink_metadata.value().delegated_ink_is_hovering);
EXPECT_EQ(expected_metadata_->point(), actual_metadata->point());
EXPECT_EQ(expected_metadata_->color(), actual_metadata->color());
EXPECT_EQ(expected_metadata_->diameter(), actual_metadata->diameter());
EXPECT_EQ(expected_metadata_->presentation_area(),
actual_metadata->presentation_area());
EXPECT_EQ(expected_metadata_->timestamp(), actual_metadata->timestamp());
+ EXPECT_EQ(expected_metadata_->is_hovering(),
+ actual_metadata->is_hovering());
// Record the frame time from the metadata so we can confirm that it
// matches the LayerTreeHostImpl's frame time in DrawLayersOnThread.
EXPECT_GT(actual_metadata->frame_time(), base::TimeTicks::Min());
metadata_frame_time_ = actual_metadata->frame_time();
} else {
- EXPECT_FALSE(had_delegated_ink_metadata);
+ EXPECT_FALSE(browser_delegated_ink_metadata.has_value());
EXPECT_FALSE(actual_metadata);
EndTest();
}
@@ -8954,7 +8960,7 @@ class LayerTreeHostTestDelegatedInkMetadataOnAndOff
const RenderFrameMetadata& render_frame_metadata,
viz::CompositorFrameMetadata* compositor_frame_metadata,
bool force_send) override {
- ExpectMetadata(render_frame_metadata.has_delegated_ink_metadata,
+ ExpectMetadata(render_frame_metadata.delegated_ink_metadata,
compositor_frame_metadata->delegated_ink_metadata.get());
}
@@ -8999,18 +9005,30 @@ class LayerTreeHostTestEventsMetrics : public LayerTreeHostTest {
private:
void SimulateEventOnMain() {
- std::unique_ptr<EventMetrics> metrics = EventMetrics::Create(
+ base::SimpleTestTickClock tick_clock;
+ tick_clock.Advance(base::TimeDelta::FromMicroseconds(10));
+ base::TimeTicks event_time = tick_clock.NowTicks();
+ tick_clock.Advance(base::TimeDelta::FromMicroseconds(10));
+ std::unique_ptr<EventMetrics> metrics = EventMetrics::CreateForTesting(
ui::ET_GESTURE_SCROLL_UPDATE,
- EventMetrics::ScrollUpdateType::kContinued, base::TimeTicks::Now(),
- ui::ScrollInputType::kWheel);
+ EventMetrics::ScrollUpdateType::kContinued, ui::ScrollInputType::kWheel,
+ event_time, &tick_clock);
+ DCHECK_NE(metrics, nullptr);
{
+ tick_clock.Advance(base::TimeDelta::FromMicroseconds(10));
+ metrics->SetDispatchStageTimestamp(
+ EventMetrics::DispatchStage::kRendererCompositorStarted);
auto done_callback = base::BindOnce(
- [](std::unique_ptr<EventMetrics> metrics, bool handled) {
+ [](std::unique_ptr<EventMetrics> metrics,
+ base::SimpleTestTickClock* tick_clock, bool handled) {
+ tick_clock->Advance(base::TimeDelta::FromMicroseconds(10));
+ metrics->SetDispatchStageTimestamp(
+ EventMetrics::DispatchStage::kRendererCompositorFinished);
std::unique_ptr<EventMetrics> result =
handled ? std::move(metrics) : nullptr;
return result;
},
- std::move(metrics));
+ std::move(metrics), &tick_clock);
auto scoped_event_monitor =
layer_tree_host()->GetScopedEventMetricsMonitor(
std::move(done_callback));
@@ -9434,5 +9452,71 @@ class LayerTreeHostUkmSmoothnessMemoryOwnership : public LayerTreeTest {
MULTI_THREAD_TEST_F(LayerTreeHostUkmSmoothnessMemoryOwnership);
+class LayerTreeHostTestDocumentTransitionsPropagatedToMetadata
+ : public LayerTreeHostTest {
+ protected:
+ void SetupTree() override {
+ SetInitialRootBounds(gfx::Size(10, 10));
+ LayerTreeHostTest::SetupTree();
+ }
+
+ void BeginTest() override {
+ layer_tree_host()->AddDocumentTransitionRequest(
+ DocumentTransitionRequest::CreatePrepare(
+ DocumentTransitionRequest::Effect::kExplode,
+ base::TimeDelta::FromMilliseconds(123),
+ base::BindLambdaForTesting([this]() { CommitLambdaCalled(); })));
+ layer_tree_host()->AddDocumentTransitionRequest(
+ DocumentTransitionRequest::CreateStart(
+ base::BindLambdaForTesting([this]() { CommitLambdaCalled(); })));
+ }
+
+ void CommitLambdaCalled() { ++num_lambda_calls_; }
+
+ void DisplayReceivedCompositorFrameOnThread(
+ const viz::CompositorFrame& frame) override {
+ ASSERT_EQ(2u, frame.metadata.transition_directives.size());
+ const auto& save = frame.metadata.transition_directives[0];
+
+ EXPECT_EQ(save.type(),
+ viz::CompositorFrameTransitionDirective::Type::kSave);
+ EXPECT_EQ(save.effect(),
+ viz::CompositorFrameTransitionDirective::Effect::kExplode);
+ EXPECT_EQ(save.duration(), base::TimeDelta::FromMilliseconds(123));
+
+ const auto& animate = frame.metadata.transition_directives[1];
+ EXPECT_GT(animate.sequence_id(), save.sequence_id());
+ EXPECT_EQ(animate.type(),
+ viz::CompositorFrameTransitionDirective::Type::kAnimate);
+
+ EndTest();
+ }
+
+ void AfterTest() override { EXPECT_EQ(2, num_lambda_calls_); }
+
+ int num_lambda_calls_ = 0;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(
+ LayerTreeHostTestDocumentTransitionsPropagatedToMetadata);
+
+class LayerTreeHostTestDebugStateDowngrade : public LayerTreeHostTest {
+ void InitializeSettings(LayerTreeSettings* settings) override {
+ settings->initial_debug_state.show_fps_counter = true;
+ }
+
+ void BeginTest() override {
+ LayerTreeHost* host = layer_tree_host();
+ LayerTreeDebugState state = host->GetDebugState();
+ EXPECT_TRUE(state.show_fps_counter);
+ state.show_fps_counter = false;
+ host->SetDebugState(state);
+ EXPECT_FALSE(host->GetDebugState().show_fps_counter);
+ EndTest();
+ }
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestDebugStateDowngrade);
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_unittest_animation.cc b/chromium/cc/trees/layer_tree_host_unittest_animation.cc
index a3a4c36d76a..4d80dbe7f76 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_animation.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_animation.cc
@@ -10,7 +10,6 @@
#include "base/bind.h"
#include "base/metrics/statistics_recorder.h"
#include "cc/animation/animation.h"
-#include "cc/animation/animation_curve.h"
#include "cc/animation/animation_host.h"
#include "cc/animation/animation_id_provider.h"
#include "cc/animation/animation_timeline.h"
@@ -19,8 +18,6 @@
#include "cc/animation/scroll_offset_animation_curve.h"
#include "cc/animation/scroll_offset_animation_curve_factory.h"
#include "cc/animation/scroll_offset_animations.h"
-#include "cc/animation/timing_function.h"
-#include "cc/animation/transform_operations.h"
#include "cc/base/completion_event.h"
#include "cc/layers/layer.h"
#include "cc/layers/layer_impl.h"
@@ -33,6 +30,9 @@
#include "cc/trees/target_property.h"
#include "cc/trees/transform_node.h"
#include "components/viz/common/quads/compositor_frame.h"
+#include "ui/gfx/animation/keyframe/animation_curve.h"
+#include "ui/gfx/animation/keyframe/timing_function.h"
+#include "ui/gfx/transform_operations.h"
namespace cc {
namespace {
@@ -376,8 +376,9 @@ class LayerTreeHostAnimationTestAddKeyframeModelWithTimingFunction
KeyframeModel* keyframe_model =
animation_child_impl->GetKeyframeModel(TargetProperty::OPACITY);
- const FloatAnimationCurve* curve =
- keyframe_model->curve()->ToFloatAnimationCurve();
+ const gfx::FloatAnimationCurve* curve =
+ gfx::FloatAnimationCurve::ToFloatAnimationCurve(
+ keyframe_model->curve());
float start_opacity = curve->GetValue(base::TimeDelta());
float end_opacity = curve->GetValue(curve->Duration());
float linearly_interpolated_opacity =
@@ -554,9 +555,10 @@ class LayerTreeHostAnimationTestLayerAddedWithAnimation
animation_->set_animation_delegate(this);
// Any valid AnimationCurve will do here.
- std::unique_ptr<AnimationCurve> curve(new FakeFloatAnimationCurve());
+ std::unique_ptr<gfx::AnimationCurve> curve(new FakeFloatAnimationCurve());
std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create(
- std::move(curve), 1, 1, TargetProperty::OPACITY));
+ std::move(curve), 1, 1,
+ KeyframeModel::TargetPropertyId(TargetProperty::OPACITY)));
animation_->AddKeyframeModel(std::move(keyframe_model));
// We add the animation *before* attaching the layer to the tree.
@@ -764,9 +766,8 @@ class LayerTreeHostAnimationTestCheckerboardDoesntStartAnimations
MULTI_THREAD_TEST_F(
LayerTreeHostAnimationTestCheckerboardDoesntStartAnimations);
-// Verifies that scroll offset animations are only accepted when impl-scrolling
-// is supported, and that when scroll offset animations are accepted,
-// scroll offset updates are sent back to the main thread.
+// Verifies that a scroll offset animation sends scroll offset updates back to
+// the main thread.
class LayerTreeHostAnimationTestScrollOffsetChangesArePropagated
: public LayerTreeHostAnimationTest {
public:
@@ -794,13 +795,10 @@ class LayerTreeHostAnimationTestScrollOffsetChangesArePropagated
CreateEaseInOutAnimationForTesting(
gfx::ScrollOffset(500.f, 550.f)));
std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create(
- std::move(curve), 1, 0, TargetProperty::SCROLL_OFFSET));
+ std::move(curve), 1, 0,
+ KeyframeModel::TargetPropertyId(TargetProperty::SCROLL_OFFSET)));
keyframe_model->set_needs_synchronized_start_time(true);
- bool impl_scrolling_supported = proxy()->SupportsImplScrolling();
- if (impl_scrolling_supported)
- animation_child_->AddKeyframeModel(std::move(keyframe_model));
- else
- EndTest();
+ animation_child_->AddKeyframeModel(std::move(keyframe_model));
break;
}
default:
@@ -864,10 +862,11 @@ class LayerTreeHostAnimationTestScrollOffsetAnimationTakeover
}
}
- void NotifyAnimationTakeover(base::TimeTicks monotonic_time,
- int target_property,
- base::TimeTicks animation_start_time,
- std::unique_ptr<AnimationCurve> curve) override {
+ void NotifyAnimationTakeover(
+ base::TimeTicks monotonic_time,
+ int target_property,
+ base::TimeTicks animation_start_time,
+ std::unique_ptr<gfx::AnimationCurve> curve) override {
EndTest();
}
@@ -941,8 +940,9 @@ class LayerTreeHostAnimationTestScrollOffsetAnimationAdjusted
ScrollOffsetKeyframeEffect(*host_impl, scroll_layer_)
.GetKeyframeModel(TargetProperty::SCROLL_OFFSET);
DCHECK(keyframe_model);
- ScrollOffsetAnimationCurve* curve =
- keyframe_model->curve()->ToScrollOffsetAnimationCurve();
+ const ScrollOffsetAnimationCurve* curve =
+ ScrollOffsetAnimationCurve::ToScrollOffsetAnimationCurve(
+ keyframe_model->curve());
// Verifiy the initial and target position before the scroll offset
// update from MT.
@@ -966,8 +966,9 @@ class LayerTreeHostAnimationTestScrollOffsetAnimationAdjusted
ScrollOffsetKeyframeEffect(*host_impl, scroll_layer_)
.GetKeyframeModel(TargetProperty::SCROLL_OFFSET);
DCHECK(keyframe_model);
- ScrollOffsetAnimationCurve* curve =
- keyframe_model->curve()->ToScrollOffsetAnimationCurve();
+ const ScrollOffsetAnimationCurve* curve =
+ ScrollOffsetAnimationCurve::ToScrollOffsetAnimationCurve(
+ keyframe_model->curve());
// Verifiy the initial and target position after the scroll offset
// update from MT
EXPECT_EQ(KeyframeModel::RunState::STARTING, keyframe_model->run_state());
@@ -1006,7 +1007,8 @@ class LayerTreeHostPresentationDuringAnimation
ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting(
gfx::ScrollOffset(6500.f, 7500.f)));
std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create(
- std::move(curve), 1, 0, TargetProperty::SCROLL_OFFSET));
+ std::move(curve), 1, 0,
+ KeyframeModel::TargetPropertyId(TargetProperty::SCROLL_OFFSET)));
keyframe_model->set_needs_synchronized_start_time(true);
AttachAnimationsToTimeline();
@@ -1086,7 +1088,8 @@ class LayerTreeHostAnimationTestScrollOffsetAnimationRemoval
ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting(
gfx::ScrollOffset(6500.f, 7500.f)));
std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create(
- std::move(curve), 1, 0, TargetProperty::SCROLL_OFFSET));
+ std::move(curve), 1, 0,
+ KeyframeModel::TargetPropertyId(TargetProperty::SCROLL_OFFSET)));
keyframe_model->set_needs_synchronized_start_time(true);
AttachAnimationsToTimeline();
@@ -1211,7 +1214,8 @@ class LayerTreeHostAnimationTestScrollOffsetAnimationCompletion
ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting(
final_position_));
std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create(
- std::move(curve), 1, 0, TargetProperty::SCROLL_OFFSET));
+ std::move(curve), 1, 0,
+ KeyframeModel::TargetPropertyId(TargetProperty::SCROLL_OFFSET)));
keyframe_model->set_needs_synchronized_start_time(true);
AttachAnimationsToTimeline();
@@ -1421,9 +1425,9 @@ class LayerTreeHostAnimationTestPendingTreeAnimatesFirstCommit
void BeginTest() override {
// Add a translate from 6,7 to 8,9.
- TransformOperations start;
+ gfx::TransformOperations start;
start.AppendTranslate(6.f, 7.f, 0.f);
- TransformOperations end;
+ gfx::TransformOperations end;
end.AppendTranslate(8.f, 9.f, 0.f);
AddAnimatedTransformToAnimation(animation_.get(), 4.0, start, end);
@@ -2167,9 +2171,9 @@ class ImplSideInvalidationWithoutCommitTestScroll
ScrollOffsetAnimationCurveFactory::CreateEaseInOutAnimationForTesting(
gfx::ScrollOffset(500.f, 550.f)));
std::unique_ptr<KeyframeModel> keyframe_model(KeyframeModel::Create(
- std::move(curve), 1, 0, TargetProperty::SCROLL_OFFSET));
+ std::move(curve), 1, 0,
+ KeyframeModel::TargetPropertyId(TargetProperty::SCROLL_OFFSET)));
keyframe_model->set_needs_synchronized_start_time(true);
- ASSERT_TRUE(proxy()->SupportsImplScrolling());
animation_child_->AddKeyframeModel(std::move(keyframe_model));
PostSetNeedsCommitToMainThread();
}
@@ -2262,9 +2266,9 @@ class LayerTreeHostAnimationTestChangeAnimation
timeline_->DetachAnimation(animation_child_.get());
animation_->AttachElement(layer_->element_id());
- TransformOperations start;
+ gfx::TransformOperations start;
start.AppendTranslate(5.f, 5.f, 0.f);
- TransformOperations end;
+ gfx::TransformOperations end;
end.AppendTranslate(5.f, 5.f, 0.f);
AddAnimatedTransformToAnimation(animation_.get(), 1.0, start, end);
}
diff --git a/chromium/cc/trees/layer_tree_host_unittest_capture.cc b/chromium/cc/trees/layer_tree_host_unittest_capture.cc
new file mode 100644
index 00000000000..0336419a2bb
--- /dev/null
+++ b/chromium/cc/trees/layer_tree_host_unittest_capture.cc
@@ -0,0 +1,143 @@
+// 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.
+
+#include "cc/test/fake_content_layer_client.h"
+#include "cc/test/fake_picture_layer.h"
+#include "cc/test/layer_tree_test.h"
+#include "cc/test/property_tree_test_utils.h"
+#include "cc/trees/layer_tree_impl.h"
+#include "components/viz/common/quads/compositor_frame.h"
+#include "components/viz/common/surfaces/subtree_capture_id.h"
+
+namespace cc {
+namespace {
+
+constexpr viz::SubtreeCaptureId kCaptureId{22};
+
+// A base class for tests that verifies the bahvior of the layer tree when a
+// sub layer has a valid viz::SubtreeCaptureId.
+class LayerTreeHostCaptureTest : public LayerTreeTest {
+ public:
+ void SetupTree() override {
+ scoped_refptr<Layer> root = FakePictureLayer::Create(&client_);
+ root->SetBounds(gfx::Size(100, 100));
+
+ child_ = FakePictureLayer::Create(&client_);
+ child_->SetBounds(gfx::Size(50, 60));
+ child_->SetPosition(gfx::PointF(10.f, 5.5f));
+ root->AddChild(child_);
+
+ grand_child_ = FakePictureLayer::Create(&client_);
+ grand_child_->SetBounds(gfx::Size(70, 30));
+ grand_child_->SetPosition(gfx::PointF(50.f, 50.f));
+ child_->AddChild(grand_child_);
+
+ layer_tree_host()->SetRootLayer(root);
+ LayerTreeTest::SetupTree();
+ client_.set_bounds(root->bounds());
+ }
+
+ void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
+ LayerImpl* root = impl->active_tree()->root_layer();
+ LayerImpl* child = impl->active_tree()->LayerById(child_->id());
+ LayerImpl* grand_child = impl->active_tree()->LayerById(grand_child_->id());
+
+ VerifyLayerImpls(root, child, grand_child);
+ }
+
+ protected:
+ // Lets test subclasses to verify the LayerImpls of the layers in the tree.
+ virtual void VerifyLayerImpls(LayerImpl* root,
+ LayerImpl* child,
+ LayerImpl* grand_child) = 0;
+
+ FakeContentLayerClient client_;
+ scoped_refptr<Layer> child_;
+ scoped_refptr<Layer> grand_child_;
+};
+
+// -----------------------------------------------------------------------------
+// LayerTreeHostCaptureTestNoExtraRenderPassWhenNotCapturing:
+//
+// Tests that a layer tree that doesn't have a viz::SubtreeCaptureId on any of
+// its layers, draw in a single root render surface, and generates a single
+// compositor render pass.
+class LayerTreeHostCaptureTestNoExtraRenderPassWhenNotCapturing
+ : public LayerTreeHostCaptureTest {
+ public:
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ void VerifyLayerImpls(LayerImpl* root,
+ LayerImpl* child,
+ LayerImpl* grand_child) override {
+ // All layers in the tree draw in the same root render surface.
+ auto* root_surface = GetRenderSurface(root);
+ auto* child_surface = GetRenderSurface(child);
+ auto* grand_child_surface = GetRenderSurface(grand_child);
+ EXPECT_EQ(root_surface, child_surface);
+ EXPECT_EQ(root_surface, grand_child_surface);
+ EXPECT_FALSE(root_surface->CopyOfOutputRequired());
+ EXPECT_FALSE(root_surface->SubtreeCaptureId().is_valid());
+
+ EndTest();
+ }
+
+ void DisplayReceivedCompositorFrameOnThread(
+ const viz::CompositorFrame& frame) override {
+ // There should be a single compositor render pass, which has no valid
+ // SubtreeCaptureId.
+ ASSERT_EQ(frame.render_pass_list.size(), 1u);
+ EXPECT_FALSE(frame.render_pass_list.back()->subtree_capture_id.is_valid());
+ }
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(
+ LayerTreeHostCaptureTestNoExtraRenderPassWhenNotCapturing);
+
+// -----------------------------------------------------------------------------
+// LayerTreeHostCaptureTestLayerWithCaptureIdElevatesToSurface
+//
+// Tests that a layer sub tree whose root has a valid viz::SubtreeCaptureId will
+// draw into a separate render surface and a separate render pass.
+class LayerTreeHostCaptureTestLayerWithCaptureIdElevatesToSurface
+ : public LayerTreeHostCaptureTest {
+ public:
+ void BeginTest() override { child_->SetSubtreeCaptureId(kCaptureId); }
+
+ void VerifyLayerImpls(LayerImpl* root,
+ LayerImpl* child,
+ LayerImpl* grand_child) override {
+ // |child| should draw into a separate render surface from that of the root,
+ // and the |grand_child| should draw into the render surface of its parent
+ // (which is |child|'s).
+ // The |chils|'s surface should have the expected capture ID.
+ auto* root_surface = GetRenderSurface(root);
+ auto* child_surface = GetRenderSurface(child);
+ auto* grand_child_surface = GetRenderSurface(grand_child);
+ EXPECT_NE(root_surface, child_surface);
+ EXPECT_NE(root_surface, grand_child_surface);
+ EXPECT_EQ(child_surface, grand_child_surface);
+ EXPECT_EQ(kCaptureId, child_surface->SubtreeCaptureId());
+ EXPECT_TRUE(child_surface->CopyOfOutputRequired());
+
+ EndTest();
+ }
+
+ void DisplayReceivedCompositorFrameOnThread(
+ const viz::CompositorFrame& frame) override {
+ // There should be 2 render passes. The non-root render pass is associated
+ // with the layer subtree rooted at |child| and should have the expected
+ // capture ID.
+ ASSERT_EQ(frame.render_pass_list.size(), 2u);
+ EXPECT_TRUE(frame.render_pass_list.front()->subtree_capture_id.is_valid());
+ EXPECT_EQ(kCaptureId, frame.render_pass_list.front()->subtree_capture_id);
+ EXPECT_FALSE(frame.render_pass_list.back()->subtree_capture_id.is_valid());
+ }
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(
+ LayerTreeHostCaptureTestLayerWithCaptureIdElevatesToSurface);
+
+} // namespace
+} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_unittest_capture_content.cc b/chromium/cc/trees/layer_tree_host_unittest_capture_content.cc
index c7bf7b5b3cf..2423cef7446 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_capture_content.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_capture_content.cc
@@ -71,7 +71,8 @@ class LayerTreeHostCaptureContentTest : public LayerTreeTest {
root->AddChild(root_picture_layer_);
layer_tree_host()->SetRootLayer(root);
- layer_tree_host()->SetViewportVisibleRect(gfx::Rect(device_bounds_));
+ layer_tree_host()->SetVisualDeviceViewportIntersectionRect(
+ gfx::Rect(device_bounds_));
}
void VerifyCapturedContent(std::vector<FakeTextHolder>* expected_result) {
diff --git a/chromium/cc/trees/layer_tree_host_unittest_checkerimaging.cc b/chromium/cc/trees/layer_tree_host_unittest_checkerimaging.cc
index f841b4c7826..9801b1718cb 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_checkerimaging.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_checkerimaging.cc
@@ -69,7 +69,7 @@ class LayerTreeHostCheckerImagingTest : public LayerTreeTest {
.set_decoding_mode(PaintImage::DecodingMode::kAsync)
.TakePaintImage();
content_layer_client_.add_draw_image(checkerable_image, gfx::Point(0, 0),
- PaintFlags());
+ SkSamplingOptions(), PaintFlags());
layer_tree_host()->SetRootLayer(
FakePictureLayer::Create(&content_layer_client_));
diff --git a/chromium/cc/trees/layer_tree_host_unittest_context.cc b/chromium/cc/trees/layer_tree_host_unittest_context.cc
index b679607a722..648e80e7ea1 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_context.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_context.cc
@@ -1216,7 +1216,8 @@ class UIResourceLostAfterCommit : public UIResourceLostTestSimple {
switch (time_step_) {
case 1:
// The resource should have been created on LTHI after the commit.
- EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
+ EXPECT_NE(viz::kInvalidResourceId,
+ impl->ResourceIdForUIResource(ui_resource_->id()));
PostSetNeedsCommitToMainThread();
break;
case 2:
@@ -1228,7 +1229,8 @@ class UIResourceLostAfterCommit : public UIResourceLostTestSimple {
EXPECT_EQ(1, ui_resource_->lost_resource_count);
// Resource Id on the impl-side have been recreated as well. Note
// that the same UIResourceId persists after the context lost.
- EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
+ EXPECT_NE(viz::kInvalidResourceId,
+ impl->ResourceIdForUIResource(ui_resource_->id()));
PostSetNeedsCommitToMainThread();
break;
}
@@ -1319,9 +1321,11 @@ class UIResourceLostBeforeCommit : public UIResourceLostTestSimple {
case 3:
// Sequence 2 (continued):
// The previous resource should have been deleted.
- EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id0_));
+ EXPECT_EQ(viz::kInvalidResourceId,
+ impl->ResourceIdForUIResource(test_id0_));
// The second resource should have been created.
- EXPECT_NE(0u, impl->ResourceIdForUIResource(test_id1_));
+ EXPECT_NE(viz::kInvalidResourceId,
+ impl->ResourceIdForUIResource(test_id1_));
// The second resource was not actually uploaded before the context
// was lost, so it only got created once.
EXPECT_EQ(1, ui_resource_->resource_create_count);
@@ -1334,7 +1338,8 @@ class UIResourceLostBeforeCommit : public UIResourceLostTestSimple {
// No "resource lost" callbacks.
EXPECT_EQ(0, ui_resource_->lost_resource_count);
// The UI resource id should not be valid
- EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id0_));
+ EXPECT_EQ(viz::kInvalidResourceId,
+ impl->ResourceIdForUIResource(test_id0_));
break;
}
}
@@ -1394,7 +1399,8 @@ class UIResourceLostBeforeActivateTree : public UIResourceLostTest {
// The resource is not yet lost (sanity check).
EXPECT_EQ(0, ui_resource_->lost_resource_count);
// The resource should not have been created yet on the impl-side.
- EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
+ EXPECT_EQ(viz::kInvalidResourceId,
+ impl->ResourceIdForUIResource(ui_resource_->id()));
LoseContext();
break;
case 3:
@@ -1410,7 +1416,8 @@ class UIResourceLostBeforeActivateTree : public UIResourceLostTest {
// The pending requests on the impl-side should not have been processed
// since the context was lost. But we should have marked the resource as
// evicted instead.
- EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
+ EXPECT_EQ(viz::kInvalidResourceId,
+ impl->ResourceIdForUIResource(ui_resource_->id()));
EXPECT_TRUE(impl->EvictedUIResourcesExist());
break;
case 2:
@@ -1418,13 +1425,15 @@ class UIResourceLostBeforeActivateTree : public UIResourceLostTest {
// should have gotten recreated now and shouldn't be marked as evicted
// anymore.
EXPECT_EQ(1, ui_resource_->lost_resource_count);
- EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
+ EXPECT_NE(viz::kInvalidResourceId,
+ impl->ResourceIdForUIResource(ui_resource_->id()));
EXPECT_FALSE(impl->EvictedUIResourcesExist());
break;
case 4:
// The resource is deleted and should not be in the manager. Use
// test_id_ since ui_resource_ has been deleted.
- EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id_));
+ EXPECT_EQ(viz::kInvalidResourceId,
+ impl->ResourceIdForUIResource(test_id_));
break;
}
@@ -1476,9 +1485,12 @@ class UIResourceLostEviction : public UIResourceLostTestSimple {
if (!visible) {
// All resources should have been evicted.
ASSERT_EQ(0u, sii_->shared_image_count());
- EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
- EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource2_->id()));
- EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource3_->id()));
+ EXPECT_EQ(viz::kInvalidResourceId,
+ impl->ResourceIdForUIResource(ui_resource_->id()));
+ EXPECT_EQ(viz::kInvalidResourceId,
+ impl->ResourceIdForUIResource(ui_resource2_->id()));
+ EXPECT_EQ(viz::kInvalidResourceId,
+ impl->ResourceIdForUIResource(ui_resource3_->id()));
EXPECT_EQ(2, ui_resource_->resource_create_count);
EXPECT_EQ(1, ui_resource_->lost_resource_count);
// Drawing is disabled both because of the evicted resources and
@@ -1496,16 +1508,20 @@ class UIResourceLostEviction : public UIResourceLostTestSimple {
// The first two resources should have been created on LTHI after the
// commit.
ASSERT_EQ(2u, sii_->shared_image_count());
- EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
- EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource2_->id()));
+ EXPECT_NE(viz::kInvalidResourceId,
+ impl->ResourceIdForUIResource(ui_resource_->id()));
+ EXPECT_NE(viz::kInvalidResourceId,
+ impl->ResourceIdForUIResource(ui_resource2_->id()));
EXPECT_EQ(1, ui_resource_->resource_create_count);
EXPECT_EQ(0, ui_resource_->lost_resource_count);
EXPECT_TRUE(impl->CanDraw());
// Evict all UI resources. This will trigger a commit.
impl->EvictAllUIResources();
ASSERT_EQ(0u, sii_->shared_image_count());
- EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
- EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource2_->id()));
+ EXPECT_EQ(viz::kInvalidResourceId,
+ impl->ResourceIdForUIResource(ui_resource_->id()));
+ EXPECT_EQ(viz::kInvalidResourceId,
+ impl->ResourceIdForUIResource(ui_resource2_->id()));
EXPECT_EQ(1, ui_resource_->resource_create_count);
EXPECT_EQ(0, ui_resource_->lost_resource_count);
EXPECT_FALSE(impl->CanDraw());
@@ -1513,10 +1529,12 @@ class UIResourceLostEviction : public UIResourceLostTestSimple {
case 2:
// The first two resources should have been recreated.
ASSERT_EQ(2u, sii_->shared_image_count());
- EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
+ EXPECT_NE(viz::kInvalidResourceId,
+ impl->ResourceIdForUIResource(ui_resource_->id()));
EXPECT_EQ(2, ui_resource_->resource_create_count);
EXPECT_EQ(1, ui_resource_->lost_resource_count);
- EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource2_->id()));
+ EXPECT_NE(viz::kInvalidResourceId,
+ impl->ResourceIdForUIResource(ui_resource2_->id()));
EXPECT_EQ(2, ui_resource2_->resource_create_count);
EXPECT_EQ(1, ui_resource2_->lost_resource_count);
EXPECT_TRUE(impl->CanDraw());
@@ -1525,17 +1543,20 @@ class UIResourceLostEviction : public UIResourceLostTestSimple {
// The first resource should have been recreated after visibility was
// restored.
ASSERT_EQ(2u, sii_->shared_image_count());
- EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
+ EXPECT_NE(viz::kInvalidResourceId,
+ impl->ResourceIdForUIResource(ui_resource_->id()));
EXPECT_EQ(3, ui_resource_->resource_create_count);
EXPECT_EQ(2, ui_resource_->lost_resource_count);
// This resource was deleted.
- EXPECT_EQ(0u, impl->ResourceIdForUIResource(ui_resource2_->id()));
+ EXPECT_EQ(viz::kInvalidResourceId,
+ impl->ResourceIdForUIResource(ui_resource2_->id()));
EXPECT_EQ(2, ui_resource2_->resource_create_count);
EXPECT_EQ(1, ui_resource2_->lost_resource_count);
// This resource should have been created now.
- EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource3_->id()));
+ EXPECT_NE(viz::kInvalidResourceId,
+ impl->ResourceIdForUIResource(ui_resource3_->id()));
EXPECT_EQ(1, ui_resource3_->resource_create_count);
EXPECT_EQ(0, ui_resource3_->lost_resource_count);
EXPECT_TRUE(impl->CanDraw());
@@ -1565,7 +1586,8 @@ class UIResourceFreedIfLostWhileExported : public LayerTreeHostContextTest {
switch (impl->active_tree()->source_frame_number()) {
case 0:
// The UIResource has been created and a gpu resource made for it.
- EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
+ EXPECT_NE(viz::kInvalidResourceId,
+ impl->ResourceIdForUIResource(ui_resource_->id()));
EXPECT_EQ(1u, sii_->shared_image_count());
// Lose the LayerTreeFrameSink connection. The UI resource should
// be replaced and the old texture should be destroyed.
@@ -1574,7 +1596,8 @@ class UIResourceFreedIfLostWhileExported : public LayerTreeHostContextTest {
case 1:
// The UIResource has been recreated, the old texture is not kept
// around.
- EXPECT_NE(0u, impl->ResourceIdForUIResource(ui_resource_->id()));
+ EXPECT_NE(viz::kInvalidResourceId,
+ impl->ResourceIdForUIResource(ui_resource_->id()));
EXPECT_EQ(1u, sii_->shared_image_count());
MainThreadTaskRunner()->PostTask(
FROM_HERE,
@@ -1714,7 +1737,7 @@ class SoftwareTileResourceFreedIfLostWhileExported : public LayerTreeTest {
}
FakeContentLayerClient client_;
- viz::ResourceId exported_resource_id_ = 0;
+ viz::ResourceId exported_resource_id_ = viz::kInvalidResourceId;
};
SINGLE_AND_MULTI_THREAD_TEST_F(SoftwareTileResourceFreedIfLostWhileExported);
diff --git a/chromium/cc/trees/layer_tree_host_unittest_scroll.cc b/chromium/cc/trees/layer_tree_host_unittest_scroll.cc
index 26b01cbd5ab..1aa61b98e70 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_scroll.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_scroll.cc
@@ -5,10 +5,10 @@
#include "cc/trees/layer_tree_host.h"
#include "base/bind.h"
+#include "base/containers/contains.h"
#include "base/location.h"
#include "base/memory/weak_ptr.h"
#include "base/single_thread_task_runner.h"
-#include "base/stl_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "cc/animation/animation_host.h"
@@ -1729,8 +1729,17 @@ class LayerTreeHostScrollTestImplScrollUnderMainThreadScrollingParent
scoped_refptr<Layer> scroller_;
};
+// This test is flaky in the single threaded configuration, only on the
+// chromeos-amd64-generic-rel bot. https://crbug.com/1093078.
+#if defined(OS_CHROMEOS)
+// SINGLE_THREAD_TEST_F(
+// LayerTreeHostScrollTestImplScrollUnderMainThreadScrollingParent);
+MULTI_THREAD_TEST_F(
+ LayerTreeHostScrollTestImplScrollUnderMainThreadScrollingParent);
+#else
SINGLE_AND_MULTI_THREAD_TEST_F(
LayerTreeHostScrollTestImplScrollUnderMainThreadScrollingParent);
+#endif
class ThreadCheckingInputHandlerClient : public InputHandlerClient {
public:
diff --git a/chromium/cc/trees/layer_tree_impl.cc b/chromium/cc/trees/layer_tree_impl.cc
index cb9d1d174d5..1ac475f2afe 100644
--- a/chromium/cc/trees/layer_tree_impl.cc
+++ b/chromium/cc/trees/layer_tree_impl.cc
@@ -16,12 +16,12 @@
#include <utility>
#include "base/containers/adapters.h"
+#include "base/containers/contains.h"
#include "base/debug/crash_logging.h"
#include "base/debug/dump_without_crashing.h"
#include "base/json/json_writer.h"
#include "base/metrics/histogram_macros.h"
#include "base/numerics/ranges.h"
-#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "base/timer/elapsed_timer.h"
#include "base/trace_event/trace_event.h"
@@ -31,6 +31,7 @@
#include "cc/base/histograms.h"
#include "cc/base/math_util.h"
#include "cc/base/synced_property.h"
+#include "cc/document_transition/document_transition_request.h"
#include "cc/input/page_scale_animation.h"
#include "cc/input/scrollbar_animation_controller.h"
#include "cc/layers/effect_tree_layer_list_iterator.h"
@@ -660,6 +661,9 @@ void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) {
delegated_ink_metadata_->point().ToString());
target_tree->set_delegated_ink_metadata(std::move(delegated_ink_metadata_));
}
+
+ for (auto& request : TakeDocumentTransitionRequests())
+ target_tree->AddDocumentTransitionRequest(std::move(request));
}
void LayerTreeImpl::HandleTickmarksVisibilityChange() {
@@ -964,9 +968,8 @@ void LayerTreeImpl::UpdateTransformAnimation(ElementId element_id,
list_type);
if (node->has_potential_animation != has_potential_animation) {
node->has_potential_animation = has_potential_animation;
- mutator_host()->GetAnimationScales(element_id, list_type,
- &node->maximum_animation_scale,
- &node->starting_animation_scale);
+ node->maximum_animation_scale =
+ mutator_host()->MaximumScale(element_id, list_type);
transform_tree.set_needs_update(true);
set_needs_update_draw_properties();
}
@@ -1194,6 +1197,7 @@ void LayerTreeImpl::SetDeviceViewportRect(
if (device_viewport_rect == device_viewport_rect_)
return;
device_viewport_rect_ = device_viewport_rect;
+ device_viewport_rect_changed_ = true;
set_needs_update_draw_properties();
if (!IsActiveTree())
@@ -1450,6 +1454,8 @@ bool LayerTreeImpl::UpdateDrawProperties(
image_animation_controller()->UpdateStateFromDrivers();
}
+ device_viewport_rect_changed_ = false;
+
DCHECK(!needs_update_draw_properties_)
<< "CalcDrawProperties should not set_needs_update_draw_properties()";
return true;
@@ -2143,7 +2149,6 @@ static void FindClosestMatchingLayer(const gfx::PointF& screen_space_point,
LayerImpl* root_layer,
const Functor& func,
FindClosestMatchingLayerState* state) {
- base::ElapsedTimer timer;
// We want to iterate from front to back when hit testing.
for (auto* layer : base::Reversed(*root_layer->layer_tree_impl())) {
if (!func(layer))
@@ -2173,12 +2178,6 @@ static void FindClosestMatchingLayer(const gfx::PointF& screen_space_point,
state->closest_match = layer;
}
}
- if (const char* client_name = GetClientNameForMetrics()) {
- UMA_HISTOGRAM_COUNTS_1M(
- base::StringPrintf("Compositing.%s.HitTestTimeToFindClosestLayer",
- client_name),
- timer.Elapsed().InMicroseconds());
- }
}
LayerImpl* LayerTreeImpl::FindFirstScrollingLayerOrScrollbarThatIsHitByPoint(
@@ -2670,4 +2669,20 @@ std::string LayerTreeImpl::LayerListAsJson() const {
return value.ToFormattedJSON();
}
+void LayerTreeImpl::AddDocumentTransitionRequest(
+ std::unique_ptr<DocumentTransitionRequest> request) {
+ document_transition_requests_.push_back(std::move(request));
+ // We need to send the request to viz.
+ SetNeedsRedraw();
+}
+
+std::vector<std::unique_ptr<DocumentTransitionRequest>>
+LayerTreeImpl::TakeDocumentTransitionRequests() {
+ return std::move(document_transition_requests_);
+}
+
+bool LayerTreeImpl::HasDocumentTransitionRequests() const {
+ return !document_transition_requests_.empty();
+}
+
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_impl.h b/chromium/cc/trees/layer_tree_impl.h
index b1638ab1490..ec13bafda99 100644
--- a/chromium/cc/trees/layer_tree_impl.h
+++ b/chromium/cc/trees/layer_tree_impl.h
@@ -48,6 +48,7 @@ class ContextProvider;
namespace cc {
class DebugRectHistory;
+class DocumentTransitionRequest;
class DroppedFrameCounter;
class HeadsUpDisplayLayerImpl;
class ImageDecodeCache;
@@ -745,6 +746,21 @@ class CC_EXPORT LayerTreeImpl {
return events_metrics_from_main_thread_.size();
}
+ bool device_viewport_rect_changed() const {
+ return device_viewport_rect_changed_;
+ }
+
+ // Add a document transition request from the embedder.
+ void AddDocumentTransitionRequest(
+ std::unique_ptr<DocumentTransitionRequest> request);
+
+ // Returns all of the document transition requests stored so far, and empties
+ // the internal list.
+ std::vector<std::unique_ptr<DocumentTransitionRequest>>
+ TakeDocumentTransitionRequests();
+
+ bool HasDocumentTransitionRequests() const;
+
protected:
float ClampPageScaleFactorToLimits(float page_scale_factor) const;
void PushPageScaleFactorAndLimits(const float* page_scale_factor,
@@ -796,6 +812,7 @@ class CC_EXPORT LayerTreeImpl {
bool new_local_surface_id_request_ = false;
// Contains the physical rect of the device viewport, to be used in
// determining what needs to be drawn.
+ bool device_viewport_rect_changed_ = false;
gfx::Rect device_viewport_rect_;
scoped_refptr<SyncedElasticOverscroll> elastic_overscroll_;
@@ -898,6 +915,10 @@ class CC_EXPORT LayerTreeImpl {
EventMetrics::List events_metrics_from_main_thread_;
std::unique_ptr<viz::DelegatedInkMetadata> delegated_ink_metadata_;
+
+ // Document transition requests to be transferred to Viz.
+ std::vector<std::unique_ptr<DocumentTransitionRequest>>
+ document_transition_requests_;
};
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_impl_unittest.cc b/chromium/cc/trees/layer_tree_impl_unittest.cc
index 0e1e993131c..a132530bfaa 100644
--- a/chromium/cc/trees/layer_tree_impl_unittest.cc
+++ b/chromium/cc/trees/layer_tree_impl_unittest.cc
@@ -1697,7 +1697,7 @@ TEST_F(LayerTreeImplTest, HitTestingTouchHandlerRegionsForLayerThatIsNotDrawn) {
// Hit testing for a point outside the test layer should return null pointer.
// We also implicitly check that the updated screen space transform of a layer
// that is not in drawn render surface layer list (test_layer) is used during
- // hit testing (becuase the point is inside test_layer with respect to the old
+ // hit testing (because the point is inside test_layer with respect to the old
// screen space transform).
gfx::PointF test_point(24.f, 24.f);
test_layer->SetOffsetToTransformParent(gfx::Vector2dF(25.f, 25.f));
diff --git a/chromium/cc/trees/layer_tree_settings.h b/chromium/cc/trees/layer_tree_settings.h
index 3d411412c72..c02eb016dc3 100644
--- a/chromium/cc/trees/layer_tree_settings.h
+++ b/chromium/cc/trees/layer_tree_settings.h
@@ -197,10 +197,11 @@ class CC_EXPORT LayerTreeSettings {
// See crbug.com/1008483.
bool enable_transform_interop = false;
- // When enabled, the compositor specifies a frame rate preference that would
- // allow the display to run at a low refresh rate matching the playback rate
- // for videos updating onscreen.
- bool force_preferred_interval_for_video = false;
+ // Enables ThrottleDecider which produces a list of FrameSinkIds that are
+ // candidates for throttling.
+ // LayerTreeHostSingleThreadClient::FrameSinksToThrottleUpdated() will be
+ // called with candidates.
+ bool enable_compositing_based_throttling = false;
};
class CC_EXPORT LayerListSettings : public LayerTreeSettings {
diff --git a/chromium/cc/trees/mutator_host.h b/chromium/cc/trees/mutator_host.h
index d0865d0002d..6e4773a91a5 100644
--- a/chromium/cc/trees/mutator_host.h
+++ b/chromium/cc/trees/mutator_host.h
@@ -28,8 +28,8 @@ class LayerTreeMutator;
class ScrollTree;
// Used as the return value of GetAnimationScales() to indicate that there is
-// no active scale animation or the scale cannot be computed.
-const float kNotScaled = 0;
+// no active transform animation or the scale cannot be computed.
+constexpr float kInvalidScale = 0.f;
// A MutatorHost owns all the animation and mutation effects.
// There is just one MutatorHost for LayerTreeHost on main renderer thread
@@ -42,8 +42,7 @@ class MutatorHost {
public:
virtual ~MutatorHost() = default;
- virtual std::unique_ptr<MutatorHost> CreateImplInstance(
- bool supports_impl_scrolling) const = 0;
+ virtual std::unique_ptr<MutatorHost> CreateImplInstance() const = 0;
virtual void ClearMutators() = 0;
@@ -62,7 +61,6 @@ class MutatorHost {
virtual void PushPropertiesTo(MutatorHost* host_impl) = 0;
- virtual void SetSupportsScrollAnimations(bool supports_scroll_animations) = 0;
virtual void SetScrollAnimationDurationForTesting(
base::TimeDelta duration) = 0;
virtual bool NeedsTickAnimations() const = 0;
@@ -120,16 +118,11 @@ class MutatorHost {
virtual bool AnimationsPreserveAxisAlignment(ElementId element_id) const = 0;
- // Gets scales transform animations. On return, |maximum_scale| is the maximum
- // scale along any dimension at any destination in active scale animations,
- // and |starting_scale| is the maximum of starting animation scale along any
- // dimension at any destination in active scale animations. They are set to
- // kNotScaled if there is no active scale animation or the scales cannot be
- // computed.
- virtual void GetAnimationScales(ElementId element_id,
- ElementListType list_type,
- float* maximum_scale,
- float* starting_scale) const = 0;
+ // Returns the maximum scale along any dimension at any destination in active
+ // scale animations, or kInvalidScale if there is no active transform
+ // animation or the scale cannot be computed.
+ virtual float MaximumScale(ElementId element_id,
+ ElementListType list_type) const = 0;
virtual bool IsElementAnimating(ElementId element_id) const = 0;
virtual bool HasTickingKeyframeModelForTesting(
@@ -167,6 +160,11 @@ class MutatorHost {
virtual bool HasCanvasInvalidation() const = 0;
virtual bool HasJSAnimation() const = 0;
+ // Iterates through all animations and returns the minimum tick interval.
+ // Returns 0 if there is a continuous animation which should be ticked
+ // as fast as possible.
+ virtual base::TimeDelta MinimumTickInterval() const = 0;
+
using TrackedAnimationSequenceId = size_t;
struct PendingThroughputTrackerInfo {
// Id of a tracked animation sequence.
diff --git a/chromium/cc/trees/mutator_host_client.h b/chromium/cc/trees/mutator_host_client.h
index dd08f0afc1f..4a794d76bfb 100644
--- a/chromium/cc/trees/mutator_host_client.h
+++ b/chromium/cc/trees/mutator_host_client.h
@@ -61,10 +61,9 @@ class MutatorHostClient {
const PropertyAnimationState& mask,
const PropertyAnimationState& state) = 0;
- virtual void AnimationScalesChanged(ElementId element_id,
- ElementListType list_type,
- float maximum_scale,
- float starting_scale) = 0;
+ virtual void MaximumScaleChanged(ElementId element_id,
+ ElementListType list_type,
+ float maximum_scale) = 0;
virtual void ScrollOffsetAnimationFinished() = 0;
virtual gfx::ScrollOffset GetScrollOffsetForAnimation(
@@ -75,9 +74,8 @@ class MutatorHostClient {
ElementListType tree_type) = 0;
virtual void OnCustomPropertyMutated(
- ElementId element_id,
- const std::string& custom_property_name,
- PaintWorkletInput::PropertyValue custom_property_value) = 0;
+ PaintWorkletInput::PropertyKey property_key,
+ PaintWorkletInput::PropertyValue property_value) = 0;
};
} // namespace cc
diff --git a/chromium/cc/trees/occlusion_tracker.cc b/chromium/cc/trees/occlusion_tracker.cc
index b3ed41e48f5..2a88893df7a 100644
--- a/chromium/cc/trees/occlusion_tracker.cc
+++ b/chromium/cc/trees/occlusion_tracker.cc
@@ -196,9 +196,7 @@ void OcclusionTracker::FinishedRenderTarget(
// Readbacks always happen on render targets so we only need to check
// for readbacks here.
bool target_is_only_for_copy_request_or_force_render_surface =
- (finished_target_surface->HasCopyRequest() ||
- finished_target_surface->ShouldCacheRenderSurface()) &&
- is_hidden;
+ is_hidden && finished_target_surface->CopyOfOutputRequired();
// If the occlusion within the surface can not be applied to things outside of
// the surface's subtree, then clear the occlusion here so it won't be used.
diff --git a/chromium/cc/trees/property_animation_state.cc b/chromium/cc/trees/property_animation_state.cc
index 6c785231ac0..48a2f6282b7 100644
--- a/chromium/cc/trees/property_animation_state.cc
+++ b/chromium/cc/trees/property_animation_state.cc
@@ -59,7 +59,7 @@ PropertyAnimationState operator^(const PropertyAnimationState& lhs,
bool PropertyAnimationState::IsValid() const {
// currently_running must be a subset for potentially_animating.
// currently <= potentially i.e. potentially || !currently.
- TargetProperties result = potentially_animating | ~currently_running;
+ gfx::TargetProperties result = potentially_animating | ~currently_running;
return result.all();
}
diff --git a/chromium/cc/trees/property_animation_state.h b/chromium/cc/trees/property_animation_state.h
index 1b7c07a7ed7..f37b64d1bd8 100644
--- a/chromium/cc/trees/property_animation_state.h
+++ b/chromium/cc/trees/property_animation_state.h
@@ -7,6 +7,7 @@
#include "cc/cc_export.h"
#include "cc/trees/target_property.h"
+#include "ui/gfx/animation/keyframe/target_property.h"
namespace cc {
@@ -15,8 +16,8 @@ struct CC_EXPORT PropertyAnimationState {
PropertyAnimationState(const PropertyAnimationState& rhs);
~PropertyAnimationState();
- TargetProperties currently_running;
- TargetProperties potentially_animating;
+ gfx::TargetProperties currently_running;
+ gfx::TargetProperties potentially_animating;
bool operator==(const PropertyAnimationState& other) const;
bool operator!=(const PropertyAnimationState& other) const;
diff --git a/chromium/cc/trees/property_tree.cc b/chromium/cc/trees/property_tree.cc
index d9da2f91bcc..8bc3982468a 100644
--- a/chromium/cc/trees/property_tree.cc
+++ b/chromium/cc/trees/property_tree.cc
@@ -24,6 +24,7 @@
#include "cc/trees/transform_node.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "ui/gfx/geometry/vector2d_conversions.h"
+#include "ui/gfx/transform_util.h"
namespace cc {
@@ -574,7 +575,7 @@ void TransformTree::SetRootScaleAndTransform(
const gfx::Transform& device_transform) {
device_scale_factor_ = device_scale_factor;
gfx::Vector2dF device_transform_scale_components =
- MathUtil::ComputeTransform2dScaleComponents(device_transform, 1.f);
+ gfx::ComputeTransform2dScaleComponents(device_transform, 1.f);
// Not handling the rare case of different x and y device scale.
device_transform_scale_factor_ =
@@ -589,8 +590,7 @@ void TransformTree::SetRootScaleAndTransform(
gfx::Transform transform = device_transform;
transform.Scale(device_scale_factor, device_scale_factor);
gfx::Vector2dF screen_space_scale =
- MathUtil::ComputeTransform2dScaleComponents(transform,
- device_scale_factor);
+ gfx::ComputeTransform2dScaleComponents(transform, device_scale_factor);
DCHECK_NE(screen_space_scale.x(), 0.f);
DCHECK_NE(screen_space_scale.y(), 0.f);
@@ -729,20 +729,24 @@ void EffectTree::UpdateIsDrawn(EffectNode* node, EffectNode* parent_node) {
// Exceptions:
// 1) Nodes that contribute to copy requests, whether hidden or not, must be
// drawn.
- // 2) Nodes that have a backdrop filter.
- // 3) Nodes with animating screen space opacity on main thread or pending tree
+ // 2) Nodes that have a valid SubtreeCaptureId, must be drawn so that they can
+ // be captured by the FrameSinkVideoCapturer.
+ // 3) Nodes that have a backdrop filter.
+ // 4) Nodes with animating screen space opacity on main thread or pending tree
// are drawn if their parent is drawn irrespective of their opacity.
- if (node->has_copy_request || node->cache_render_surface)
+ if (node->has_copy_request || node->cache_render_surface ||
+ node->subtree_capture_id.is_valid()) {
node->is_drawn = true;
- else if (EffectiveOpacity(node) == 0.f &&
- (!node->has_potential_opacity_animation ||
- property_trees()->is_active) &&
- node->backdrop_filters.IsEmpty())
+ } else if (EffectiveOpacity(node) == 0.f &&
+ (!node->has_potential_opacity_animation ||
+ property_trees()->is_active) &&
+ node->backdrop_filters.IsEmpty()) {
node->is_drawn = false;
- else if (parent_node)
+ } else if (parent_node) {
node->is_drawn = parent_node->is_drawn;
- else
+ } else {
node->is_drawn = true;
+ }
}
void EffectTree::UpdateEffectChanged(EffectNode* node,
@@ -789,7 +793,8 @@ void EffectTree::UpdateHasMaskingChild(EffectNode* node,
void EffectTree::UpdateOnlyDrawsVisibleContent(EffectNode* node,
EffectNode* parent_node) {
- node->only_draws_visible_content = !node->has_copy_request;
+ node->only_draws_visible_content =
+ !node->has_copy_request && !node->subtree_capture_id.is_valid();
if (parent_node)
node->only_draws_visible_content &= parent_node->only_draws_visible_content;
if (!node->backdrop_filters.IsEmpty()) {
@@ -813,9 +818,8 @@ void EffectTree::UpdateSurfaceContentsScale(EffectNode* effect_node) {
layer_scale_factor *= transform_tree.page_scale_factor();
const gfx::Vector2dF old_scale = effect_node->surface_contents_scale;
- effect_node->surface_contents_scale =
- MathUtil::ComputeTransform2dScaleComponents(
- transform_tree.ToScreen(transform_node->id), layer_scale_factor);
+ effect_node->surface_contents_scale = gfx::ComputeTransform2dScaleComponents(
+ transform_tree.ToScreen(transform_node->id), layer_scale_factor);
// If surface contents scale changes, draw transforms are no longer valid.
// Invalidates the draw transform cache and updates the clip for the surface.
@@ -1949,13 +1953,11 @@ bool PropertyTrees::ElementIsAnimatingChanged(
return updated_transform;
}
-void PropertyTrees::AnimationScalesChanged(ElementId element_id,
- float maximum_scale,
- float starting_scale) {
+void PropertyTrees::MaximumAnimationScaleChanged(ElementId element_id,
+ float maximum_scale) {
if (TransformNode* transform_node =
transform_tree.FindNodeFromElementId(element_id)) {
transform_node->maximum_animation_scale = maximum_scale;
- transform_node->starting_animation_scale = starting_scale;
UpdateTransformTreeUpdateNumber();
}
}
@@ -2038,105 +2040,102 @@ std::string PropertyTrees::ToString() const {
return value.ToFormattedJSON();
}
-CombinedAnimationScale PropertyTrees::GetAnimationScales(
- int transform_node_id,
- LayerTreeImpl* layer_tree_impl) {
- AnimationScaleData* animation_scales =
- &cached_data_.animation_scales[transform_node_id];
- if (animation_scales->update_number !=
+bool PropertyTrees::AnimationScaleCacheIsInvalid(int transform_id) const {
+ DCHECK(!is_main_thread);
+ // This doesn't check if |update_number| equals to
+ // |transform_tree_update_number| because the the latter is changed by the
+ // animation itself while we want to treat the scale as valid during the
+ // animation. |update_number| is reset to kInvalidUpdateNumber when a new
+ // property tree is pushed.
+ return cached_data_.animation_scales[transform_id].update_number ==
+ kInvalidUpdateNumber;
+}
+
+float PropertyTrees::MaximumAnimationToScreenScale(int transform_id) {
+ return GetAnimationScaleData(transform_id).maximum_to_screen_scale;
+}
+
+bool PropertyTrees::AnimationAffectedByInvalidScale(int transform_id) {
+ return GetAnimationScaleData(transform_id).affected_by_invalid_scale;
+}
+
+const AnimationScaleData& PropertyTrees::GetAnimationScaleData(
+ int transform_id) {
+ DCHECK(!is_main_thread);
+
+ auto& animation_scale = cached_data_.animation_scales[transform_id];
+ if (animation_scale.update_number ==
cached_data_.transform_tree_update_number) {
- TransformNode* node = transform_tree.Node(transform_node_id);
- TransformNode* parent_node = transform_tree.parent(node);
- bool ancestor_is_animating_scale = false;
- float ancestor_maximum_target_scale = kNotScaled;
- float ancestor_starting_animation_scale = kNotScaled;
- if (parent_node) {
- CombinedAnimationScale combined_animation_scale =
- GetAnimationScales(parent_node->id, layer_tree_impl);
- ancestor_maximum_target_scale =
- combined_animation_scale.maximum_animation_scale;
- ancestor_starting_animation_scale =
- combined_animation_scale.starting_animation_scale;
- ancestor_is_animating_scale =
- cached_data_.animation_scales[parent_node->id]
- .to_screen_has_scale_animation;
- }
+ return animation_scale;
+ }
+
+ animation_scale.update_number = cached_data_.transform_tree_update_number;
+
+ TransformNode* node = transform_tree.Node(transform_id);
+ TransformNode* parent_node = transform_tree.parent(node);
+ const auto* parent_animation_scale =
+ parent_node ? &GetAnimationScaleData(parent_node->id) : nullptr;
+
+ bool ancestor_affected_by_animation_scale =
+ parent_node && parent_animation_scale->affected_by_animation_scale;
+ bool node_affected_by_animation_scale =
+ node->has_potential_animation && node->maximum_animation_scale != 1.0f;
+
+ animation_scale.affected_by_animation_scale =
+ node_affected_by_animation_scale || ancestor_affected_by_animation_scale;
+ animation_scale.affected_by_invalid_scale =
+ (parent_node && parent_animation_scale->affected_by_invalid_scale) ||
+ // Computing maximum animated scale in the presence of perspective isn't
+ // supported.
+ node->to_parent.HasPerspective() ||
+ (node->has_potential_animation &&
+ node->maximum_animation_scale == kInvalidScale);
+
+ // We don't attempt to accumulate animation scale from multiple nodes with
+ // scale animations, because of the risk of significant overestimation. For
+ // example, one node might be increasing scale from 1 to 10 at the same time
+ // as another node is decreasing scale from 10 to 1. Naively combining these
+ // scales would produce a scale of 100.
+ bool failed_for_multiple_scale_animations =
+ ancestor_affected_by_animation_scale && node_affected_by_animation_scale;
+
+ float local_maximum_scale = 1.0f;
+ if (animation_scale.affected_by_invalid_scale ||
+ failed_for_multiple_scale_animations) {
+ // Will use the parent's maximum_to_screen_scale.
+ } else if (!node->to_screen_is_potentially_animated) {
+ // No transform animations. Calculate the current to_screen scale.
+ gfx::Vector2dF to_screen_scales = gfx::ComputeTransform2dScaleComponents(
+ transform_tree.ToScreen(transform_id), kInvalidScale);
+ animation_scale.maximum_to_screen_scale =
+ std::max(to_screen_scales.x(), to_screen_scales.y());
+ return animation_scale;
+ } else if (!node->has_potential_animation) {
+ gfx::Vector2dF local_scales =
+ gfx::ComputeTransform2dScaleComponents(node->local, 1.0f);
+ local_maximum_scale = std::max(local_scales.x(), local_scales.y());
+ } else {
+ DCHECK_NE(node->maximum_animation_scale, kInvalidScale);
+ local_maximum_scale = node->maximum_animation_scale;
+ }
- bool node_is_animating_scale =
- node->maximum_animation_scale != kNotScaled &&
- node->starting_animation_scale != kNotScaled;
-
- animation_scales->to_screen_has_scale_animation =
- node_is_animating_scale || ancestor_is_animating_scale;
-
- // Once we've failed to compute a maximum animated scale at an ancestor, we
- // continue to fail.
- bool failed_at_ancestor = ancestor_is_animating_scale &&
- ancestor_maximum_target_scale == kNotScaled;
-
- // Computing maximum animated scale in the presence of non-scale/translation
- // transforms isn't supported.
- bool failed_for_non_scale_or_translation =
- !node->to_parent.IsScaleOrTranslation();
-
- // We don't attempt to accumulate animation scale from multiple nodes with
- // scale animations, because of the risk of significant overestimation. For
- // example, one node might be increasing scale from 1 to 10 at the same time
- // as another node is decreasing scale from 10 to 1. Naively combining these
- // scales would produce a scale of 100.
- bool failed_for_multiple_scale_animations =
- ancestor_is_animating_scale && node_is_animating_scale;
-
- if (failed_at_ancestor || failed_for_non_scale_or_translation ||
- failed_for_multiple_scale_animations) {
- // This ensures that descendants know we've failed to compute a maximum
- // animated scale.
- animation_scales->to_screen_has_scale_animation = true;
- animation_scales->combined_maximum_animation_target_scale = kNotScaled;
- animation_scales->combined_starting_animation_scale = kNotScaled;
- } else if (!animation_scales->to_screen_has_scale_animation) {
- animation_scales->combined_maximum_animation_target_scale = kNotScaled;
- animation_scales->combined_starting_animation_scale = kNotScaled;
- } else if (!node_is_animating_scale) {
- // An ancestor is animating scale.
- gfx::Vector2dF local_scales =
- MathUtil::ComputeTransform2dScaleComponents(node->local, kNotScaled);
- float max_local_scale = std::max(local_scales.x(), local_scales.y());
- animation_scales->combined_maximum_animation_target_scale =
- max_local_scale * ancestor_maximum_target_scale;
- animation_scales->combined_starting_animation_scale =
- max_local_scale * ancestor_starting_animation_scale;
- } else {
- gfx::Vector2dF ancestor_scales =
- parent_node
- ? MathUtil::ComputeTransform2dScaleComponents(
- transform_tree.ToScreen(parent_node->id), kNotScaled)
- : gfx::Vector2dF(1.f, 1.f);
-
- float max_ancestor_scale =
- std::max(ancestor_scales.x(), ancestor_scales.y());
- animation_scales->combined_maximum_animation_target_scale =
- max_ancestor_scale * node->maximum_animation_scale;
- animation_scales->combined_starting_animation_scale =
- max_ancestor_scale * node->starting_animation_scale;
- }
- animation_scales->update_number = cached_data_.transform_tree_update_number;
+ animation_scale.maximum_to_screen_scale = local_maximum_scale;
+ if (parent_node) {
+ animation_scale.maximum_to_screen_scale *=
+ parent_animation_scale->maximum_to_screen_scale;
}
- return CombinedAnimationScale(
- animation_scales->combined_maximum_animation_target_scale,
- animation_scales->combined_starting_animation_scale);
+
+ return animation_scale;
}
-void PropertyTrees::SetAnimationScalesForTesting(
+void PropertyTrees::SetMaximumAnimationToScreenScaleForTesting(
int transform_id,
- float maximum_animation_scale,
- float starting_animation_scale) {
- cached_data_.animation_scales[transform_id]
- .combined_maximum_animation_target_scale = maximum_animation_scale;
- cached_data_.animation_scales[transform_id]
- .combined_starting_animation_scale = starting_animation_scale;
- cached_data_.animation_scales[transform_id].update_number =
- cached_data_.transform_tree_update_number;
+ float maximum_scale,
+ bool affected_by_invalid_scale) {
+ auto& animation_scale = cached_data_.animation_scales[transform_id];
+ animation_scale.maximum_to_screen_scale = maximum_scale;
+ animation_scale.affected_by_invalid_scale = affected_by_invalid_scale;
+ animation_scale.update_number = cached_data_.transform_tree_update_number;
}
bool PropertyTrees::GetToTarget(int transform_id,
@@ -2200,7 +2199,7 @@ DrawTransformData& PropertyTrees::FetchDrawTransformsDataFromCache(
// Add an entry to the cache.
cached_data_.draw_transforms[transform_id].push_back(DrawTransformData());
DrawTransformData& data = cached_data_.draw_transforms[transform_id].back();
- data.update_number = -1;
+ data.update_number = kInvalidUpdateNumber;
data.target_id = dest_id;
return data;
}
@@ -2210,7 +2209,8 @@ ClipRectData* PropertyTrees::FetchClipRectFromCache(int clip_id,
ClipNode* clip_node = clip_tree.Node(clip_id);
for (size_t i = 0; i < clip_node->cached_clip_rects->size(); ++i) {
auto& data = clip_node->cached_clip_rects[i];
- if (data.target_id == target_id || data.target_id == -1)
+ if (data.target_id == target_id ||
+ data.target_id == EffectTree::kInvalidNodeId)
return &data;
}
clip_node->cached_clip_rects->emplace_back();
@@ -2286,13 +2286,13 @@ void PropertyTrees::ResetCachedData() {
const auto transform_count = transform_tree.nodes().size();
cached_data_.animation_scales.resize(transform_count);
for (auto& animation_scale : cached_data_.animation_scales)
- animation_scale.update_number = -1;
+ animation_scale.update_number = kInvalidUpdateNumber;
cached_data_.draw_transforms.resize(transform_count,
std::vector<DrawTransformData>(1));
for (auto& draw_transforms_for_id : cached_data_.draw_transforms) {
draw_transforms_for_id.resize(1);
- draw_transforms_for_id[0].update_number = -1;
+ draw_transforms_for_id[0].update_number = kInvalidUpdateNumber;
draw_transforms_for_id[0].target_id = EffectTree::kInvalidNodeId;
}
}
diff --git a/chromium/cc/trees/property_tree.h b/chromium/cc/trees/property_tree.h
index 8b60fde7c87..2bb36062737 100644
--- a/chromium/cc/trees/property_tree.h
+++ b/chromium/cc/trees/property_tree.h
@@ -21,7 +21,7 @@
#include "cc/input/scroll_snap_data.h"
#include "cc/paint/element_id.h"
#include "cc/paint/filter_operations.h"
-#include "cc/trees/mutator_host_client.h"
+#include "cc/trees/mutator_host.h"
#include "cc/trees/sticky_position_constraint.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/scroll_offset.h"
@@ -539,40 +539,26 @@ class CC_EXPORT ScrollTree final : public PropertyTree<ScrollNode> {
bool use_fractional_deltas);
};
+constexpr int kInvalidUpdateNumber = -1;
+
struct AnimationScaleData {
- // Variable used to invalidate cached animation scale data when transform tree
+ // Variable used to invalidate cached maximum scale data when transform tree
// updates.
- int update_number;
-
- // The maximum scale that this node's |to_target| transform will have during
- // current animations, considering only scales at keyframes not incuding the
- // starting keyframe of each animation.
- float combined_maximum_animation_target_scale;
-
- // The maximum scale that this node's |to_target| transform will have during
- // current animations, considering only the starting scale of each animation.
- float combined_starting_animation_scale;
+ int update_number = kInvalidUpdateNumber;
- bool to_screen_has_scale_animation;
-
- AnimationScaleData() {
- update_number = -1;
- combined_maximum_animation_target_scale = 0.f;
- combined_starting_animation_scale = 0.f;
- to_screen_has_scale_animation = false;
- }
-};
+ // The maximum scale that this node's |to_screen| transform will have during
+ // current animations of this node and its ancestors, or the current scale of
+ // this node's |to_screen| transform if there are no animations.
+ float maximum_to_screen_scale = kInvalidScale;
-struct CombinedAnimationScale {
- float maximum_animation_scale;
- float starting_animation_scale;
+ // Whether |maximum_to_screen_scale| is affected by any animation of this
+ // node or its ancestors. A scale animation having maximum scale of 1 is
+ // treated as not affecting |maximum_to_screen_scale|.
+ bool affected_by_animation_scale = false;
- CombinedAnimationScale(float maximum, float starting)
- : maximum_animation_scale(maximum), starting_animation_scale(starting) {}
- bool operator==(const CombinedAnimationScale& other) const {
- return maximum_animation_scale == other.maximum_animation_scale &&
- starting_animation_scale == other.starting_animation_scale;
- }
+ // Whether |maximum_to_screen_scale| is affected by any non-calculatable
+ // scale.
+ bool affected_by_invalid_scale = false;
};
struct DrawTransforms {
@@ -601,17 +587,12 @@ struct DrawTransforms {
};
struct DrawTransformData {
- int update_number;
- int target_id;
-
- DrawTransforms transforms;
+ int update_number = kInvalidUpdateNumber;
+ int target_id = EffectTree::kInvalidNodeId;
// TODO(sunxd): Move screen space transforms here if it can improve
// performance.
- DrawTransformData()
- : update_number(-1),
- target_id(EffectTree::kInvalidNodeId),
- transforms(gfx::Transform(), gfx::Transform()) {}
+ DrawTransforms transforms{gfx::Transform(), gfx::Transform()};
};
struct ConditionalClip {
@@ -620,10 +601,8 @@ struct ConditionalClip {
};
struct ClipRectData {
- int target_id;
+ int target_id = ClipTree::kInvalidNodeId;
ConditionalClip clip;
-
- ClipRectData() : target_id(-1) {}
};
struct PropertyTreesCachedData {
@@ -686,9 +665,7 @@ class CC_EXPORT PropertyTrees final {
const PropertyAnimationState& mask,
const PropertyAnimationState& state,
bool check_node_existence);
- void AnimationScalesChanged(ElementId element_id,
- float maximum_scale,
- float starting_scale);
+ void MaximumAnimationScaleChanged(ElementId element_id, float maximum_scale);
void SetInnerViewportContainerBoundsDelta(gfx::Vector2dF bounds_delta);
void SetOuterViewportContainerBoundsDelta(gfx::Vector2dF bounds_delta);
void UpdateChangeTracking();
@@ -711,11 +688,14 @@ class CC_EXPORT PropertyTrees final {
void AsValueInto(base::trace_event::TracedValue* value) const;
std::string ToString() const;
- CombinedAnimationScale GetAnimationScales(int transform_node_id,
- LayerTreeImpl* layer_tree_impl);
- void SetAnimationScalesForTesting(int transform_id,
- float maximum_animation_scale,
- float starting_animation_scale);
+ bool AnimationScaleCacheIsInvalid(int transform_id) const;
+ float MaximumAnimationToScreenScale(int transform_id);
+ bool AnimationAffectedByInvalidScale(int transform_id);
+
+ void SetMaximumAnimationToScreenScaleForTesting(
+ int transform_id,
+ float maximum_scale,
+ bool affected_by_invalid_scale);
bool GetToTarget(int transform_id,
int effect_id,
@@ -738,6 +718,8 @@ class CC_EXPORT PropertyTrees final {
gfx::Vector2dF inner_viewport_container_bounds_delta_;
gfx::Vector2dF outer_viewport_container_bounds_delta_;
+ const AnimationScaleData& GetAnimationScaleData(int transform_id);
+
// GetDrawTransforms may change the value of cached_data_.
DrawTransforms& GetDrawTransforms(int transform_id, int effect_id) const;
DrawTransformData& FetchDrawTransformsDataFromCache(int transform_id,
diff --git a/chromium/cc/trees/property_tree_builder.cc b/chromium/cc/trees/property_tree_builder.cc
index d0f5851130c..5bd4eeeae24 100644
--- a/chromium/cc/trees/property_tree_builder.cc
+++ b/chromium/cc/trees/property_tree_builder.cc
@@ -39,6 +39,7 @@ struct DataForRecursion {
int scroll_tree_parent;
int closest_ancestor_with_cached_render_surface;
int closest_ancestor_with_copy_request;
+ int closest_ancestor_being_captured;
SkColor safe_opaque_background_color;
bool animation_axis_aligned_since_render_target;
bool not_axis_aligned_since_last_clip;
@@ -137,13 +138,9 @@ bool HasPotentiallyRunningTransformAnimation(const MutatorHost& host,
layer->element_id(), layer->GetElementTypeForAnimation());
}
-void GetAnimationScales(const MutatorHost& host,
- Layer* layer,
- float* maximum_scale,
- float* starting_scale) {
- return host.GetAnimationScales(layer->element_id(),
- layer->GetElementTypeForAnimation(),
- maximum_scale, starting_scale);
+float MaximumAnimationScale(const MutatorHost& host, Layer* layer) {
+ return host.MaximumScale(layer->element_id(),
+ layer->GetElementTypeForAnimation());
}
bool AnimationsPreserveAxisAlignment(const MutatorHost& host, Layer* layer) {
@@ -287,8 +284,7 @@ bool PropertyTreeBuilderContext::AddTransformNodeIfNeeded(
node->has_potential_animation = has_potentially_animated_transform;
node->is_currently_animating = TransformIsAnimating(mutator_host_, layer);
- GetAnimationScales(mutator_host_, layer, &node->maximum_animation_scale,
- &node->starting_animation_scale);
+ node->maximum_animation_scale = MaximumAnimationScale(mutator_host_, layer);
node->scroll_offset = layer->scroll_offset();
@@ -389,6 +385,9 @@ RenderSurfaceReason ComputeRenderSurfaceReason(const MutatorHost& mutator_host,
if (layer->mirror_count())
return RenderSurfaceReason::kMirrored;
+ if (layer->subtree_capture_id().is_valid())
+ return RenderSurfaceReason::kSubtreeIsBeingCaptured;
+
return RenderSurfaceReason::kNone;
}
@@ -455,6 +454,7 @@ bool PropertyTreeBuilderContext::AddEffectNodeIfNeeded(
node->stable_id = layer->id();
node->opacity = layer->opacity();
node->blend_mode = layer->blend_mode();
+ node->subtree_capture_id = layer->subtree_capture_id();
node->cache_render_surface = layer->cache_render_surface();
node->has_copy_request = layer->HasCopyRequest();
node->filters = layer->filters();
@@ -484,6 +484,10 @@ bool PropertyTreeBuilderContext::AddEffectNodeIfNeeded(
layer->HasCopyRequest()
? node_id
: data_from_ancestor.closest_ancestor_with_copy_request;
+ node->closest_ancestor_being_captured_id =
+ layer->subtree_capture_id().is_valid()
+ ? node_id
+ : data_from_ancestor.closest_ancestor_being_captured;
if (layer->HasRoundedCorner()) {
// This is currently in the local space of the layer and hence in an invalid
@@ -518,6 +522,8 @@ bool PropertyTreeBuilderContext::AddEffectNodeIfNeeded(
node->closest_ancestor_with_cached_render_surface_id;
data_for_children->closest_ancestor_with_copy_request =
node->closest_ancestor_with_copy_request_id;
+ data_for_children->closest_ancestor_being_captured =
+ node->closest_ancestor_being_captured_id;
data_for_children->effect_tree_parent = node_id;
layer->SetEffectTreeIndex(node_id);
@@ -717,6 +723,8 @@ void PropertyTreeBuilderContext::BuildPropertyTrees() {
EffectTree::kInvalidNodeId;
data_for_recursion.closest_ancestor_with_copy_request =
EffectTree::kInvalidNodeId;
+ data_for_recursion.closest_ancestor_being_captured =
+ EffectTree::kInvalidNodeId;
data_for_recursion.compound_transform_since_render_target = gfx::Transform();
data_for_recursion.animation_axis_aligned_since_render_target = true;
data_for_recursion.not_axis_aligned_since_last_clip = false;
diff --git a/chromium/cc/trees/property_tree_builder_unittest.cc b/chromium/cc/trees/property_tree_builder_unittest.cc
index c824607608b..2576916ed38 100644
--- a/chromium/cc/trees/property_tree_builder_unittest.cc
+++ b/chromium/cc/trees/property_tree_builder_unittest.cc
@@ -7,7 +7,7 @@
#include <memory>
#include <utility>
-#include "cc/animation/keyframed_animation_curve.h"
+#include "cc/animation/filter_animation_curve.h"
#include "cc/layers/layer.h"
#include "cc/layers/layer_impl.h"
#include "cc/layers/picture_layer.h"
@@ -17,6 +17,7 @@
#include "cc/test/fake_content_layer_client.h"
#include "cc/test/layer_tree_impl_test_base.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/animation/keyframe/keyframed_animation_curve.h"
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/geometry/vector2d_conversions.h"
#include "ui/gfx/transform.h"
@@ -552,8 +553,9 @@ TEST_F(PropertyTreeBuilderTest, DelayedFilterAnimationCreatesRenderSurface) {
FilterKeyframe::Create(base::TimeDelta(), start_filters, nullptr));
curve->AddKeyframe(FilterKeyframe::Create(
base::TimeDelta::FromMilliseconds(100), end_filters, nullptr));
- std::unique_ptr<KeyframeModel> keyframe_model =
- KeyframeModel::Create(std::move(curve), 0, 1, TargetProperty::FILTER);
+ std::unique_ptr<KeyframeModel> keyframe_model = KeyframeModel::Create(
+ std::move(curve), 0, 1,
+ KeyframeModel::TargetPropertyId(TargetProperty::FILTER));
keyframe_model->set_fill_mode(KeyframeModel::FillMode::NONE);
keyframe_model->set_time_offset(base::TimeDelta::FromMilliseconds(-1000));
diff --git a/chromium/cc/trees/proxy.h b/chromium/cc/trees/proxy.h
index 5c886bb152f..44c40243afc 100644
--- a/chromium/cc/trees/proxy.h
+++ b/chromium/cc/trees/proxy.h
@@ -79,8 +79,6 @@ class CC_EXPORT Proxy {
virtual void SetPaintWorkletLayerPainter(
std::unique_ptr<PaintWorkletLayerPainter> painter) = 0;
- virtual bool SupportsImplScrolling() const = 0;
-
virtual void UpdateBrowserControlsState(BrowserControlsState constraints,
BrowserControlsState current,
bool animate) = 0;
diff --git a/chromium/cc/trees/proxy_impl.cc b/chromium/cc/trees/proxy_impl.cc
index 13cccd11026..a67c14b6b64 100644
--- a/chromium/cc/trees/proxy_impl.cc
+++ b/chromium/cc/trees/proxy_impl.cc
@@ -20,6 +20,7 @@
#include "cc/benchmarks/benchmark_instrumentation.h"
#include "cc/input/browser_controls_offset_manager.h"
#include "cc/metrics/compositor_timing_history.h"
+#include "cc/metrics/jank_injector.h"
#include "cc/paint/paint_worklet_layer_painter.h"
#include "cc/trees/compositor_commit_data.h"
#include "cc/trees/layer_tree_frame_sink.h"
@@ -250,6 +251,11 @@ bool ProxyImpl::IsInSynchronousComposite() const {
return false;
}
+void ProxyImpl::FrameSinksToThrottleUpdated(
+ const base::flat_set<viz::FrameSinkId>& ids) {
+ NOTREACHED();
+}
+
void ProxyImpl::NotifyReadyToCommitOnImpl(
CompletionEvent* completion,
LayerTreeHost* layer_tree_host,
@@ -516,13 +522,17 @@ void ProxyImpl::NotifyImageDecodeRequestFinished() {
void ProxyImpl::DidPresentCompositorFrameOnImplThread(
uint32_t frame_token,
- std::vector<LayerTreeHost::PresentationTimeCallback> callbacks,
+ PresentationTimeCallbackBuffer::PendingCallbacks activated,
const viz::FrameTimingDetails& details) {
+ auto main_thread_callbacks = std::move(activated.main_thread_callbacks);
+ host_impl_->NotifyDidPresentCompositorFrameOnImplThread(
+ frame_token, std::move(activated), details);
+
MainThreadTaskRunner()->PostTask(
- FROM_HERE,
- base::BindOnce(&ProxyMain::DidPresentCompositorFrame,
- proxy_main_weak_ptr_, frame_token, std::move(callbacks),
- details.presentation_feedback));
+ FROM_HERE, base::BindOnce(&ProxyMain::DidPresentCompositorFrame,
+ proxy_main_weak_ptr_, frame_token,
+ std::move(main_thread_callbacks),
+ details.presentation_feedback));
if (scheduler_)
scheduler_->DidPresentCompositorFrame(frame_token, details);
}
@@ -590,6 +600,11 @@ void ProxyImpl::WillNotReceiveBeginFrame() {
void ProxyImpl::ScheduledActionSendBeginMainFrame(
const viz::BeginFrameArgs& args) {
DCHECK(IsImplThread());
+
+ if (is_jank_injection_enabled_ && host_impl_->CanInjectJankOnMain()) {
+ jank_injector_.ScheduleJankIfNeeded(args, MainThreadTaskRunner());
+ }
+
benchmark_instrumentation::ScopedBeginFrameTask begin_frame_task(
benchmark_instrumentation::kSendBeginFrame,
args.frame_id.sequence_number);
@@ -805,6 +820,7 @@ base::SingleThreadTaskRunner* ProxyImpl::MainThreadTaskRunner() {
void ProxyImpl::SetSourceURL(ukm::SourceId source_id, const GURL& url) {
DCHECK(IsImplThread());
+ is_jank_injection_enabled_ = JankInjector::IsEnabled(url);
host_impl_->SetActiveURL(url, source_id);
}
diff --git a/chromium/cc/trees/proxy_impl.h b/chromium/cc/trees/proxy_impl.h
index 815935a5d41..05eb84ed3eb 100644
--- a/chromium/cc/trees/proxy_impl.h
+++ b/chromium/cc/trees/proxy_impl.h
@@ -12,6 +12,7 @@
#include "cc/base/completion_event.h"
#include "cc/base/delayed_unique_notifier.h"
#include "cc/input/browser_controls_state.h"
+#include "cc/metrics/jank_injector.h"
#include "cc/scheduler/scheduler.h"
#include "cc/trees/layer_tree_host_impl.h"
@@ -24,6 +25,7 @@ class LayerTreeHost;
class ProxyMain;
class RenderFrameMetadataObserver;
+class JankInjector;
class ScopedCompletionEvent;
// This class aggregates all the interactions that the main side of the
@@ -115,7 +117,7 @@ class CC_EXPORT ProxyImpl : public LayerTreeHostImplClient,
void NotifyImageDecodeRequestFinished() override;
void DidPresentCompositorFrameOnImplThread(
uint32_t frame_token,
- std::vector<LayerTreeHost::PresentationTimeCallback> callbacks,
+ PresentationTimeCallbackBuffer::PendingCallbacks activated,
const viz::FrameTimingDetails& details) override;
void NotifyAnimationWorkletStateChange(
AnimationWorkletMutationState state,
@@ -126,6 +128,9 @@ class CC_EXPORT ProxyImpl : public LayerTreeHostImplClient,
void DidObserveFirstScrollDelay(
base::TimeDelta first_scroll_delay,
base::TimeTicks first_scroll_timestamp) override;
+ bool IsInSynchronousComposite() const override;
+ void FrameSinksToThrottleUpdated(
+ const base::flat_set<viz::FrameSinkId>& id) override;
// SchedulerClient implementation
bool WillBeginImplFrame(const viz::BeginFrameArgs& args) override;
@@ -149,7 +154,6 @@ class CC_EXPORT ProxyImpl : public LayerTreeHostImplClient,
base::TimeTicks time) override;
void FrameIntervalUpdated(base::TimeDelta interval) override {}
bool HasCustomPropertyAnimations() const override;
- bool IsInSynchronousComposite() const override;
DrawResult DrawInternal(bool forced_draw);
@@ -178,6 +182,8 @@ class CC_EXPORT ProxyImpl : public LayerTreeHostImplClient,
bool send_compositor_frame_ack_;
+ JankInjector jank_injector_;
+
TreePriority last_raster_priority_;
TaskRunnerProvider* task_runner_provider_;
@@ -190,6 +196,8 @@ class CC_EXPORT ProxyImpl : public LayerTreeHostImplClient,
BlockedMainCommitOnly main_thread_blocked_commit_vars_unsafe_;
BlockedMainCommitOnly& blocked_main_commit();
+ bool is_jank_injection_enabled_ = false;
+
// Used to post tasks to ProxyMain on the main thread.
base::WeakPtr<ProxyMain> proxy_main_weak_ptr_;
diff --git a/chromium/cc/trees/proxy_main.cc b/chromium/cc/trees/proxy_main.cc
index 0fa28a69c06..cfafe9c81b5 100644
--- a/chromium/cc/trees/proxy_main.cc
+++ b/chromium/cc/trees/proxy_main.cc
@@ -606,10 +606,6 @@ void ProxyMain::SetPaintWorkletLayerPainter(
base::Unretained(proxy_impl_.get()), std::move(painter)));
}
-bool ProxyMain::SupportsImplScrolling() const {
- return true;
-}
-
bool ProxyMain::MainFrameWillHappenForTesting() {
DCHECK(IsMainThread());
bool main_frame_will_happen = false;
diff --git a/chromium/cc/trees/proxy_main.h b/chromium/cc/trees/proxy_main.h
index d5bc7291989..186de9d07b6 100644
--- a/chromium/cc/trees/proxy_main.h
+++ b/chromium/cc/trees/proxy_main.h
@@ -5,6 +5,9 @@
#ifndef CC_TREES_PROXY_MAIN_H_
#define CC_TREES_PROXY_MAIN_H_
+#include <memory>
+#include <vector>
+
#include "cc/cc_export.h"
#include "cc/input/browser_controls_state.h"
#include "cc/trees/layer_tree_host.h"
@@ -89,7 +92,6 @@ class CC_EXPORT ProxyMain : public Proxy {
bool CommitRequested() const override;
void Start() override;
void Stop() override;
- bool SupportsImplScrolling() const override;
void SetMutator(std::unique_ptr<LayerTreeMutator> mutator) override;
void SetPaintWorkletLayerPainter(
std::unique_ptr<PaintWorkletLayerPainter> painter) override;
diff --git a/chromium/cc/trees/render_frame_metadata.cc b/chromium/cc/trees/render_frame_metadata.cc
index 268b1bf8877..0efa3496688 100644
--- a/chromium/cc/trees/render_frame_metadata.cc
+++ b/chromium/cc/trees/render_frame_metadata.cc
@@ -29,6 +29,7 @@ bool RenderFrameMetadata::operator==(const RenderFrameMetadata& other) const {
is_scroll_offset_at_top == other.is_scroll_offset_at_top &&
selection == other.selection &&
is_mobile_optimized == other.is_mobile_optimized &&
+ delegated_ink_metadata == other.delegated_ink_metadata &&
device_scale_factor == other.device_scale_factor &&
viewport_size_in_pixels == other.viewport_size_in_pixels &&
page_scale_factor == other.page_scale_factor &&
diff --git a/chromium/cc/trees/render_frame_metadata.h b/chromium/cc/trees/render_frame_metadata.h
index b1d8efd6413..589a022fe40 100644
--- a/chromium/cc/trees/render_frame_metadata.h
+++ b/chromium/cc/trees/render_frame_metadata.h
@@ -20,6 +20,31 @@
namespace cc {
+// Contains information to assist in making a decision about forwarding
+// pointerevents to viz for use in a delegated ink trail.
+struct DelegatedInkBrowserMetadata {
+ public:
+ DelegatedInkBrowserMetadata() = default;
+ explicit DelegatedInkBrowserMetadata(bool hovering)
+ : delegated_ink_is_hovering(hovering) {}
+
+ bool operator==(const DelegatedInkBrowserMetadata& other) const {
+ return delegated_ink_is_hovering == other.delegated_ink_is_hovering;
+ }
+
+ bool operator!=(const DelegatedInkBrowserMetadata& other) const {
+ return !operator==(other);
+ }
+
+ // Flag used to indicate the state of the hovering on the pointerevent that
+ // the delegated ink metadata was created from. If this state does not match
+ // the point under consideration to send to viz, it won't be sent. As soon
+ // as it matches again the point will be sent, regardless of if the renderer
+ // has processed the point that didn't match yet or not. It is true when
+ // hovering, false otherwise.
+ bool delegated_ink_is_hovering;
+};
+
class CC_EXPORT RenderFrameMetadata {
public:
RenderFrameMetadata();
@@ -55,10 +80,12 @@ class CC_EXPORT RenderFrameMetadata {
// are the same).
bool is_mobile_optimized = false;
- // Flag used to notify the browser process to start or stop forwarding points
- // to viz for use in a delegated ink trail. True the entire time points should
- // be forwarded, and forwarding stops as soon as it is false again.
- bool has_delegated_ink_metadata = false;
+ // Existence of this flag informs the browser process to start forwarding
+ // points to viz for use in a delegated ink trail. It contains more
+ // information to be used in making the forwarding decision. It exists the
+ // entire time points could be forwarded, and forwarding must stop as soon as
+ // it is null.
+ base::Optional<DelegatedInkBrowserMetadata> delegated_ink_metadata;
// The device scale factor used to generate a CompositorFrame.
float device_scale_factor = 1.f;
diff --git a/chromium/cc/trees/single_thread_proxy.cc b/chromium/cc/trees/single_thread_proxy.cc
index f2050b82334..628454e3b90 100644
--- a/chromium/cc/trees/single_thread_proxy.cc
+++ b/chromium/cc/trees/single_thread_proxy.cc
@@ -523,11 +523,19 @@ void SingleThreadProxy::NotifyImageDecodeRequestFinished() {
void SingleThreadProxy::DidPresentCompositorFrameOnImplThread(
uint32_t frame_token,
- std::vector<LayerTreeHost::PresentationTimeCallback> callbacks,
+ PresentationTimeCallbackBuffer::PendingCallbacks callbacks,
const viz::FrameTimingDetails& details) {
- layer_tree_host_->DidPresentCompositorFrame(frame_token, std::move(callbacks),
- details.presentation_feedback);
-
+ std::vector<LayerTreeHost::PresentationTimeCallback> main_thread_callbacks =
+ std::move(callbacks.main_thread_callbacks);
+ DebugScopedSetImplThread impl(task_runner_provider_);
+ host_impl_->NotifyDidPresentCompositorFrameOnImplThread(
+ frame_token, std::move(callbacks), details);
+ {
+ DebugScopedSetMainThread main(task_runner_provider_);
+ layer_tree_host_->DidPresentCompositorFrame(
+ frame_token, std::move(main_thread_callbacks),
+ details.presentation_feedback);
+ }
if (scheduler_on_impl_thread_) {
scheduler_on_impl_thread_->DidPresentCompositorFrame(frame_token, details);
}
@@ -547,7 +555,26 @@ void SingleThreadProxy::NotifyPaintWorkletStateChange(
void SingleThreadProxy::NotifyThroughputTrackerResults(
CustomTrackerResults results) {
- layer_tree_host_->NotifyThroughputTrackerResults(std::move(results));
+ DCHECK(task_runner_provider_->IsImplThread());
+ // This method is called from ImplThread side so post a task to
+ // MainThread. This is necessary because the throughput tracker callbacks are
+ // supposed to be executed on MainThread side, which may invok compositor's
+ // method that expected to be executed on MainThread.
+ task_runner_provider_->MainThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ &SingleThreadProxy::NotifyThroughputTrackerResultsOnMainThread,
+ weak_factory_.GetWeakPtr(), std::move(results)));
+}
+
+bool SingleThreadProxy::IsInSynchronousComposite() const {
+ return inside_synchronous_composite_;
+}
+
+void SingleThreadProxy::FrameSinksToThrottleUpdated(
+ const base::flat_set<viz::FrameSinkId>& ids) {
+ DebugScopedSetMainThread main(task_runner_provider_);
+ single_thread_client_->FrameSinksToThrottleUpdated(ids);
}
void SingleThreadProxy::RequestBeginMainFrameNotExpected(bool new_state) {
@@ -557,10 +584,6 @@ void SingleThreadProxy::RequestBeginMainFrameNotExpected(bool new_state) {
}
}
-bool SingleThreadProxy::IsInSynchronousComposite() const {
- return inside_synchronous_composite_;
-}
-
void SingleThreadProxy::CompositeImmediatelyForTest(
base::TimeTicks frame_begin_time,
bool raster) {
@@ -640,10 +663,6 @@ void SingleThreadProxy::CompositeImmediatelyForTest(
}
}
-bool SingleThreadProxy::SupportsImplScrolling() const {
- return false;
-}
-
bool SingleThreadProxy::ShouldComposite() const {
DCHECK(task_runner_provider_->IsImplThread());
return host_impl_->visible() && host_impl_->CanDraw();
@@ -963,6 +982,7 @@ void SingleThreadProxy::ScheduledActionPerformImplSideInvalidation() {
void SingleThreadProxy::DidFinishImplFrame(
const viz::BeginFrameArgs& last_activated_args) {
+ DebugScopedSetImplThread impl(task_runner_provider_);
host_impl_->DidFinishImplFrame(last_activated_args);
#if DCHECK_IS_ON()
DCHECK(inside_impl_frame_)
@@ -985,4 +1005,9 @@ void SingleThreadProxy::DidReceiveCompositorFrameAck() {
layer_tree_host_->DidReceiveCompositorFrameAck();
}
+void SingleThreadProxy::NotifyThroughputTrackerResultsOnMainThread(
+ CustomTrackerResults results) {
+ layer_tree_host_->NotifyThroughputTrackerResults(std::move(results));
+}
+
} // namespace cc
diff --git a/chromium/cc/trees/single_thread_proxy.h b/chromium/cc/trees/single_thread_proxy.h
index 8b0960dbd4f..246df6800cb 100644
--- a/chromium/cc/trees/single_thread_proxy.h
+++ b/chromium/cc/trees/single_thread_proxy.h
@@ -10,6 +10,7 @@
#include <vector>
#include "base/cancelable_callback.h"
+#include "base/containers/flat_set.h"
#include "base/time/time.h"
#include "cc/scheduler/scheduler.h"
#include "cc/trees/layer_tree_host_impl.h"
@@ -62,7 +63,6 @@ class CC_EXPORT SingleThreadProxy : public Proxy,
void SetMutator(std::unique_ptr<LayerTreeMutator> mutator) override;
void SetPaintWorkletLayerPainter(
std::unique_ptr<PaintWorkletLayerPainter> painter) override;
- bool SupportsImplScrolling() const override;
bool MainFrameWillHappenForTesting() override;
void SetSourceURL(ukm::SourceId source_id, const GURL& url) override {
// Single-threaded mode is only for browser compositing and for renderers in
@@ -132,7 +132,7 @@ class CC_EXPORT SingleThreadProxy : public Proxy,
void NotifyImageDecodeRequestFinished() override;
void DidPresentCompositorFrameOnImplThread(
uint32_t frame_token,
- std::vector<LayerTreeHost::PresentationTimeCallback> callbacks,
+ PresentationTimeCallbackBuffer::PendingCallbacks callbacks,
const viz::FrameTimingDetails& details) override;
void NotifyAnimationWorkletStateChange(
AnimationWorkletMutationState state,
@@ -141,6 +141,8 @@ class CC_EXPORT SingleThreadProxy : public Proxy,
Scheduler::PaintWorkletState state) override;
void NotifyThroughputTrackerResults(CustomTrackerResults results) override;
bool IsInSynchronousComposite() const override;
+ void FrameSinksToThrottleUpdated(
+ const base::flat_set<viz::FrameSinkId>& ids) override;
void RequestNewLayerTreeFrameSink();
@@ -178,6 +180,7 @@ class CC_EXPORT SingleThreadProxy : public Proxy,
void IssueImageDecodeFinishedCallbacks();
void DidReceiveCompositorFrameAck();
+ void NotifyThroughputTrackerResultsOnMainThread(CustomTrackerResults results);
// Accessed on main thread only.
LayerTreeHost* layer_tree_host_;
diff --git a/chromium/cc/trees/target_property.cc b/chromium/cc/trees/target_property.cc
index ed206255730..96f8c3bd7cd 100644
--- a/chromium/cc/trees/target_property.cc
+++ b/chromium/cc/trees/target_property.cc
@@ -4,16 +4,19 @@
#include "cc/trees/target_property.h"
+#include "ui/gfx/animation/keyframe/target_property.h"
+
namespace cc {
-static_assert(TargetProperty::LAST_TARGET_PROPERTY < kMaxTargetPropertyIndex,
+static_assert(TargetProperty::LAST_TARGET_PROPERTY <
+ gfx::kMaxTargetPropertyIndex,
"The number of cc target properties has exceeded the capacity of"
" TargetProperties");
// bitset will use a multiple of the architecture int size, which is at least 32
// bits so make it explicit to have as many properties as fit into the memory
// used.
-static_assert(kMaxTargetPropertyIndex % (8 * sizeof(uint32_t)) == 0,
+static_assert(gfx::kMaxTargetPropertyIndex % (8 * sizeof(uint32_t)) == 0,
"The maximum number of target properties should be a multiple of "
"sizeof(uint32_t)");
diff --git a/chromium/cc/trees/target_property.h b/chromium/cc/trees/target_property.h
index 407090f27c4..a60b371119c 100644
--- a/chromium/cc/trees/target_property.h
+++ b/chromium/cc/trees/target_property.h
@@ -5,14 +5,10 @@
#ifndef CC_TREES_TARGET_PROPERTY_H_
#define CC_TREES_TARGET_PROPERTY_H_
-#include <bitset>
-
#include "base/containers/flat_map.h"
namespace cc {
-static constexpr size_t kMaxTargetPropertyIndex = 32u;
-
namespace TargetProperty {
// Must be zero-based as this will be stored in a bitset.
@@ -24,6 +20,9 @@ enum Type {
BACKGROUND_COLOR,
BOUNDS,
CSS_CUSTOM_PROPERTY,
+ // This is used for the set of properties whose animation use paint worklet
+ // infra. The value of the animation represents its progress.
+ NATIVE_PROPERTY,
BACKDROP_FILTER,
// These sentinels must be last
FIRST_TARGET_PROPERTY = TRANSFORM,
@@ -32,9 +31,6 @@ enum Type {
} // namespace TargetProperty
-// A set of target properties.
-using TargetProperties = std::bitset<kMaxTargetPropertyIndex>;
-
// A map of target property to ElementId.
// flat_map was chosen because there are expected to be relatively few entries
// in the map. For low number of entries, flat_map is known to perform better
diff --git a/chromium/cc/trees/throttle_decider.cc b/chromium/cc/trees/throttle_decider.cc
new file mode 100644
index 00000000000..305d0dd3881
--- /dev/null
+++ b/chromium/cc/trees/throttle_decider.cc
@@ -0,0 +1,92 @@
+// Copyright 2021 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/throttle_decider.h"
+
+#include <vector>
+
+#include "components/viz/common/quads/compositor_render_pass_draw_quad.h"
+#include "components/viz/common/quads/surface_draw_quad.h"
+#include "components/viz/common/surfaces/surface_range.h"
+
+namespace cc {
+
+ThrottleDecider::ThrottleDecider() = default;
+
+ThrottleDecider::~ThrottleDecider() = default;
+
+void ThrottleDecider::Prepare() {
+ last_ids_.swap(ids_);
+ id_to_pass_map_.clear();
+ ids_.clear();
+}
+
+void ThrottleDecider::ProcessRenderPass(
+ const viz::CompositorRenderPass& render_pass) {
+ bool foreground_blurred =
+ render_pass.filters.HasFilterOfType(FilterOperation::BLUR);
+ std::vector<gfx::RectF> blur_backdrop_filter_bounds;
+ for (viz::QuadList::ConstIterator it = render_pass.quad_list.begin();
+ it != render_pass.quad_list.end(); ++it) {
+ const viz::DrawQuad* quad = *it;
+ if (quad->material == viz::DrawQuad::Material::kCompositorRenderPass) {
+ // If the quad render pass has a blur backdrop filter without a mask, add
+ // the filter bounds to the bounds list.
+ const auto* render_pass_quad =
+ viz::CompositorRenderPassDrawQuad::MaterialCast(quad);
+ auto found = id_to_pass_map_.find(render_pass_quad->render_pass_id);
+ if (found == id_to_pass_map_.end()) {
+ // It is possible that this function is called when the render passes in
+ // a frame haven't been cleaned up yet. A RPDQ can possibly refer to an
+ // invalid render pass.
+ continue;
+ }
+ const auto& child_rp = *found->second;
+ if (child_rp.backdrop_filters.HasFilterOfType(FilterOperation::BLUR) &&
+ render_pass_quad->resources
+ .ids[viz::RenderPassDrawQuadInternal::kMaskResourceIdIndex] ==
+ viz::kInvalidResourceId) {
+ gfx::RectF blur_bounds(child_rp.output_rect);
+ if (child_rp.backdrop_filter_bounds)
+ blur_bounds.Intersect(child_rp.backdrop_filter_bounds->rect());
+ quad->shared_quad_state->quad_to_target_transform.TransformRect(
+ &blur_bounds);
+ if (quad->shared_quad_state->is_clipped) {
+ blur_bounds.Intersect(gfx::RectF(quad->shared_quad_state->clip_rect));
+ }
+ blur_backdrop_filter_bounds.push_back(blur_bounds);
+ }
+ } else if (quad->material == viz::DrawQuad::Material::kSurfaceContent) {
+ bool inside_backdrop_filter_bounds = false;
+ if (!foreground_blurred && !blur_backdrop_filter_bounds.empty()) {
+ gfx::RectF rect_in_target_space(quad->visible_rect);
+ quad->shared_quad_state->quad_to_target_transform.TransformRect(
+ &rect_in_target_space);
+ if (quad->shared_quad_state->is_clipped) {
+ rect_in_target_space.Intersect(
+ gfx::RectF(quad->shared_quad_state->clip_rect));
+ }
+
+ for (const gfx::RectF& blur_bounds : blur_backdrop_filter_bounds) {
+ if (blur_bounds.Contains(rect_in_target_space)) {
+ inside_backdrop_filter_bounds = true;
+ break;
+ }
+ }
+ }
+ const auto* surface_quad = viz::SurfaceDrawQuad::MaterialCast(quad);
+ const viz::SurfaceRange& range = surface_quad->surface_range;
+ DCHECK(range.IsValid());
+ if (foreground_blurred || inside_backdrop_filter_bounds)
+ ids_.insert(range.end().frame_sink_id());
+ }
+ }
+ id_to_pass_map_.emplace(render_pass.id, &render_pass);
+}
+
+bool ThrottleDecider::HasThrottlingChanged() const {
+ return ids_ != last_ids_;
+}
+
+} // namespace cc
diff --git a/chromium/cc/trees/throttle_decider.h b/chromium/cc/trees/throttle_decider.h
new file mode 100644
index 00000000000..d41479a423c
--- /dev/null
+++ b/chromium/cc/trees/throttle_decider.h
@@ -0,0 +1,48 @@
+// Copyright 2021 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_THROTTLE_DECIDER_H_
+#define CC_TREES_THROTTLE_DECIDER_H_
+
+#include "base/containers/flat_map.h"
+#include "base/containers/flat_set.h"
+#include "cc/cc_export.h"
+#include "components/viz/common/quads/compositor_render_pass.h"
+#include "components/viz/common/surfaces/frame_sink_id.h"
+
+namespace cc {
+
+// This class is used to decide if any frame sinks in a render pass list
+// satisfies the compositing-based criteria to be throttled.
+class CC_EXPORT ThrottleDecider {
+ public:
+ ThrottleDecider();
+ ~ThrottleDecider();
+ ThrottleDecider(const ThrottleDecider&) = delete;
+ ThrottleDecider& operator=(const ThrottleDecider&) = delete;
+
+ // This function should be called at the beginning of each time when a render
+ // pass list is about to be processed.
+ void Prepare();
+ // Go through the quads in |render_pass| and decide for each embedded surface
+ // in SurfaceDrawQuad if it can be throttled. This is a simple version where
+ // intersection calculation of surface/quad rects are confined to the render
+ // pass's constituent quads.
+ void ProcessRenderPass(const viz::CompositorRenderPass& render_pass);
+ bool HasThrottlingChanged() const;
+ const base::flat_set<viz::FrameSinkId>& ids() const { return ids_; }
+
+ private:
+ base::flat_map<viz::CompositorRenderPassId, const viz::CompositorRenderPass*>
+ id_to_pass_map_;
+ // Ids of frame sinks that are qualified for throttling.
+ base::flat_set<viz::FrameSinkId> ids_;
+ // Ids of frame sinks that were qualified for throttling from last
+ // compositing.
+ base::flat_set<viz::FrameSinkId> last_ids_;
+};
+
+} // namespace cc
+
+#endif // CC_TREES_THROTTLE_DECIDER_H_
diff --git a/chromium/cc/trees/throttle_decider_unittest.cc b/chromium/cc/trees/throttle_decider_unittest.cc
new file mode 100644
index 00000000000..ebb1102d1d5
--- /dev/null
+++ b/chromium/cc/trees/throttle_decider_unittest.cc
@@ -0,0 +1,111 @@
+// Copyright 2021 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/throttle_decider.h"
+#include "components/viz/common/quads/compositor_render_pass_draw_quad.h"
+#include "components/viz/common/quads/surface_draw_quad.h"
+#include "components/viz/common/surfaces/local_surface_id.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+
+class ThrottleDeciderTest : public ::testing::Test {
+ protected:
+ void RunThrottleDecider(const viz::CompositorRenderPassList& render_passes) {
+ throttle_decider_.Prepare();
+ for (auto& render_pass : render_passes) {
+ throttle_decider_.ProcessRenderPass(*render_pass.get());
+ }
+ }
+ const base::flat_set<viz::FrameSinkId>& GetFrameSinksToThrottle() const {
+ return throttle_decider_.ids();
+ }
+ ThrottleDecider throttle_decider_;
+};
+
+TEST_F(ThrottleDeciderTest, BackdropFilter) {
+ // Create two render passes. The first render pass has a blur backdrop filter.
+ // The second render pass has two quads: a RPDQ referencing the first render
+ // pass and a surface quad.
+ viz::CompositorRenderPassList render_passes;
+ render_passes.push_back(viz::CompositorRenderPass::Create());
+ render_passes.push_back(viz::CompositorRenderPass::Create());
+
+ gfx::Rect render_pass_rect(0, 0, 100, 100);
+ gfx::Rect quad_rect(0, 0, 100, 100);
+ viz::CompositorRenderPassId id1{1u};
+ viz::CompositorRenderPassId id2{2u};
+
+ render_passes[0]->SetNew(id1, render_pass_rect, gfx::Rect(),
+ gfx::Transform());
+ render_passes[0]->backdrop_filters.Append(
+ FilterOperation::CreateBlurFilter(5.0));
+ render_passes[1]->SetNew(id2, render_pass_rect, gfx::Rect(),
+ gfx::Transform());
+
+ auto* rpdq =
+ render_passes[1]
+ ->CreateAndAppendDrawQuad<viz::CompositorRenderPassDrawQuad>();
+ rpdq->material = viz::DrawQuad::Material::kCompositorRenderPass;
+ rpdq->render_pass_id = id1;
+ viz::SharedQuadState sqs1;
+ rpdq->shared_quad_state = &sqs1;
+ rpdq->rect = quad_rect;
+
+ viz::FrameSinkId frame_sink_id{10, 10};
+ auto* surface_quad =
+ render_passes[1]->CreateAndAppendDrawQuad<viz::SurfaceDrawQuad>();
+ viz::SharedQuadState sqs2;
+ surface_quad->shared_quad_state = &sqs2;
+ surface_quad->material = viz::DrawQuad::Material::kSurfaceContent;
+ surface_quad->surface_range = viz::SurfaceRange(
+ base::nullopt,
+ viz::SurfaceId(frame_sink_id, viz::LocalSurfaceId(
+ 1u, base::UnguessableToken::Create())));
+ surface_quad->rect = quad_rect;
+ surface_quad->visible_rect = quad_rect;
+
+ base::flat_set<viz::FrameSinkId> expected_frame_sinks{frame_sink_id};
+ // The surface quad (0,0 100x100) is entirely behind the backdrop filter on
+ // the rpdq (0,0 100x100) so it can be throttled.
+ RunThrottleDecider(render_passes);
+ EXPECT_EQ(GetFrameSinksToThrottle(), expected_frame_sinks);
+
+ // Put the backdrop filter within bounds (0,10 50x50).
+ render_passes[0]->backdrop_filter_bounds =
+ base::Optional<gfx::RRectF>(gfx::RRectF(0.0f, 10.0f, 50.0f, 50.0f, 1.0f));
+ // The surface quad (0,0 100x100) is partially behind the backdrop filter on
+ // the rpdq (0,10 50x50) so it should not be throttled.
+ RunThrottleDecider(render_passes);
+ EXPECT_TRUE(GetFrameSinksToThrottle().empty());
+
+ // Transform the surface quad to (0,10 50x50).
+ gfx::Transform transform;
+ transform.Translate(0, 10);
+ transform.Scale(0.5f, 0.5f);
+ sqs2.quad_to_target_transform = transform;
+ // The surface quad (0,10 50x50) is entirely behind the backdrop filter on the
+ // rpdq (0,10 50x50) so it can be throttled.
+ RunThrottleDecider(render_passes);
+ EXPECT_EQ(GetFrameSinksToThrottle(), expected_frame_sinks);
+
+ // Add a mask to the backdrop filter.
+ rpdq->resources.ids[viz::RenderPassDrawQuadInternal::kMaskResourceIdIndex] =
+ viz::ResourceId::FromUnsafeValue(1u);
+
+ // As the mask would make the backdrop filter to be ignored, the surface
+ // should not be throttled.
+ RunThrottleDecider(render_passes);
+ EXPECT_TRUE(GetFrameSinksToThrottle().empty());
+
+ // Add a foreground filter to the second render pass.
+ render_passes[1]->filters.Append(FilterOperation::CreateBlurFilter(5.0f));
+ // The surface quad is being blurred by the foreground filter so it can be
+ // throttled.
+ RunThrottleDecider(render_passes);
+ EXPECT_EQ(GetFrameSinksToThrottle(), expected_frame_sinks);
+}
+
+} // namespace cc
diff --git a/chromium/cc/trees/transform_node.cc b/chromium/cc/trees/transform_node.cc
index 4d58a3c71fb..1c91fcae2fc 100644
--- a/chromium/cc/trees/transform_node.cc
+++ b/chromium/cc/trees/transform_node.cc
@@ -35,8 +35,7 @@ TransformNode::TransformNode()
delegates_to_parent_for_backface(false),
will_change_transform(false),
node_or_ancestors_will_change_transform(false),
- maximum_animation_scale(kNotScaled),
- starting_animation_scale(kNotScaled) {}
+ maximum_animation_scale(kInvalidScale) {}
TransformNode::TransformNode(const TransformNode&) = default;
@@ -74,7 +73,6 @@ bool TransformNode::operator==(const TransformNode& other) const {
scroll_offset == other.scroll_offset &&
snap_amount == other.snap_amount &&
maximum_animation_scale == other.maximum_animation_scale &&
- starting_animation_scale == other.starting_animation_scale &&
visible_frame_element_id == other.visible_frame_element_id;
}
#endif // DCHECK_IS_ON()
diff --git a/chromium/cc/trees/transform_node.h b/chromium/cc/trees/transform_node.h
index 577a79dec15..71d8e98f459 100644
--- a/chromium/cc/trees/transform_node.h
+++ b/chromium/cc/trees/transform_node.h
@@ -122,10 +122,10 @@ struct CC_EXPORT TransformNode {
// otherwise we may need it to undo the snapping next frame.
gfx::Vector2dF snap_amount;
- // See MutatorHost::GetAnimationScales() for their meanings. Updated by
- // PropertyTrees::AnimationScalesChanged().
+ // From MutatorHost::GetMaximuimAnimationScale(). Updated by
+ // PropertyTrees::MaximumAnimationScaleChanged() and
+ // LayerTreeImpl::UpdateTransformAnimation().
float maximum_animation_scale;
- float starting_animation_scale;
// Set to the element ID of containing document if this transform node is the
// root of a visible frame subtree.
diff --git a/chromium/cc/trees/tree_synchronizer.cc b/chromium/cc/trees/tree_synchronizer.cc
index 5c5a70d2020..26f56297145 100644
--- a/chromium/cc/trees/tree_synchronizer.cc
+++ b/chromium/cc/trees/tree_synchronizer.cc
@@ -9,10 +9,10 @@
#include <set>
#include "base/check_op.h"
+#include "base/containers/contains.h"
#include "base/containers/flat_set.h"
#include "base/debug/crash_logging.h"
#include "base/debug/dump_without_crashing.h"
-#include "base/stl_util.h"
#include "base/trace_event/trace_event.h"
#include "cc/layers/layer.h"
#include "cc/layers/layer_collections.h"
diff --git a/chromium/cc/trees/tree_synchronizer_unittest.cc b/chromium/cc/trees/tree_synchronizer_unittest.cc
index 88f747398b9..5981ff8f314 100644
--- a/chromium/cc/trees/tree_synchronizer_unittest.cc
+++ b/chromium/cc/trees/tree_synchronizer_unittest.cc
@@ -11,9 +11,9 @@
#include <utility>
#include <vector>
+#include "base/containers/contains.h"
#include "base/format_macros.h"
#include "base/memory/ptr_util.h"
-#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "base/threading/thread_task_runner_handle.h"
#include "cc/animation/animation_host.h"
@@ -728,22 +728,34 @@ TEST_F(TreeSynchronizerTest, RefreshPropertyTreesCachedData) {
host_impl->ActivateSyncTree();
// This arbitrarily set the animation scale for transform_layer and see if it
- // is
- // refreshed when pushing layer trees.
- host_impl->active_tree()->property_trees()->SetAnimationScalesForTesting(
- transform_layer->transform_tree_index(), 10.f, 10.f);
+ // is refreshed when pushing layer trees.
+ float maximum_animation_scale = 123.f;
+ bool animation_affected_by_invalid_scale = true;
+ host_impl->active_tree()
+ ->property_trees()
+ ->SetMaximumAnimationToScreenScaleForTesting(
+ transform_layer->transform_tree_index(), maximum_animation_scale,
+ animation_affected_by_invalid_scale);
EXPECT_EQ(
- CombinedAnimationScale(10.f, 10.f),
- host_impl->active_tree()->property_trees()->GetAnimationScales(
- transform_layer->transform_tree_index(), host_impl->active_tree()));
+ maximum_animation_scale,
+ host_impl->active_tree()->property_trees()->MaximumAnimationToScreenScale(
+ transform_layer->transform_tree_index()));
+ EXPECT_TRUE(host_impl->active_tree()
+ ->property_trees()
+ ->AnimationAffectedByInvalidScale(
+ transform_layer->transform_tree_index()));
host_impl->CreatePendingTree();
host_->CommitAndCreatePendingTree();
host_impl->ActivateSyncTree();
EXPECT_EQ(
- CombinedAnimationScale(kNotScaled, kNotScaled),
- host_impl->active_tree()->property_trees()->GetAnimationScales(
- transform_layer->transform_tree_index(), host_impl->active_tree()));
+ 2.0f,
+ host_impl->active_tree()->property_trees()->MaximumAnimationToScreenScale(
+ transform_layer->transform_tree_index()));
+ EXPECT_FALSE(host_impl->active_tree()
+ ->property_trees()
+ ->AnimationAffectedByInvalidScale(
+ transform_layer->transform_tree_index()));
}
TEST_F(TreeSynchronizerTest, RoundedScrollDeltasOnCommit) {
diff --git a/chromium/cc/trees/ukm_manager.cc b/chromium/cc/trees/ukm_manager.cc
index b3761e46d3d..f75f67c74c4 100644
--- a/chromium/cc/trees/ukm_manager.cc
+++ b/chromium/cc/trees/ukm_manager.cc
@@ -177,7 +177,10 @@ void UkmManager::RecordCompositorLatencyUKM(
CompositorFrameReporter::FrameReportType report_type,
const std::vector<CompositorFrameReporter::StageData>& stage_history,
const CompositorFrameReporter::ActiveTrackers& active_trackers,
- const viz::FrameTimingDetails& viz_breakdown) const {
+ const CompositorFrameReporter::ProcessedBlinkBreakdown&
+ processed_blink_breakdown,
+ const CompositorFrameReporter::ProcessedVizBreakdown&
+ processed_viz_breakdown) const {
using StageType = CompositorFrameReporter::StageType;
ukm::builders::Graphics_Smoothness_Latency builder(source_id_);
@@ -186,7 +189,7 @@ void UkmManager::RecordCompositorLatencyUKM(
builder.SetMissedFrame(true);
}
- // Record each stage
+ // Record each stage.
for (const CompositorFrameReporter::StageData& stage : stage_history) {
switch (stage.stage_type) {
#define CASE_FOR_STAGE(name) \
@@ -199,52 +202,68 @@ void UkmManager::RecordCompositorLatencyUKM(
CASE_FOR_STAGE(EndCommitToActivation);
CASE_FOR_STAGE(Activation);
CASE_FOR_STAGE(EndActivateToSubmitCompositorFrame);
+ CASE_FOR_STAGE(SubmitCompositorFrameToPresentationCompositorFrame);
CASE_FOR_STAGE(TotalLatency);
#undef CASE_FOR_STAGE
- // Break out kSubmitCompositorFrameToPresentationCompositorFrame to report
- // the viz breakdown.
- case StageType::kSubmitCompositorFrameToPresentationCompositorFrame:
- builder.SetSubmitCompositorFrameToPresentationCompositorFrame(
- (stage.end_time - stage.start_time).InMicroseconds());
- if (viz_breakdown.received_compositor_frame_timestamp.is_null())
- break;
- builder
- .SetSubmitCompositorFrameToPresentationCompositorFrame_SubmitToReceiveCompositorFrame(
- (viz_breakdown.received_compositor_frame_timestamp -
- stage.start_time)
- .InMicroseconds());
- if (viz_breakdown.draw_start_timestamp.is_null())
- break;
- builder
- .SetSubmitCompositorFrameToPresentationCompositorFrame_ReceivedCompositorFrameToStartDraw(
- (viz_breakdown.draw_start_timestamp -
- viz_breakdown.received_compositor_frame_timestamp)
- .InMicroseconds());
- if (viz_breakdown.swap_timings.is_null())
- break;
- builder
- .SetSubmitCompositorFrameToPresentationCompositorFrame_StartDrawToSwapStart(
- (viz_breakdown.swap_timings.swap_start -
- viz_breakdown.draw_start_timestamp)
- .InMicroseconds());
- builder
- .SetSubmitCompositorFrameToPresentationCompositorFrame_SwapStartToSwapEnd(
- (viz_breakdown.swap_timings.swap_end -
- viz_breakdown.swap_timings.swap_start)
- .InMicroseconds());
- builder
- .SetSubmitCompositorFrameToPresentationCompositorFrame_SwapEndToPresentationCompositorFrame(
- (viz_breakdown.presentation_feedback.timestamp -
- viz_breakdown.swap_timings.swap_end)
- .InMicroseconds());
+ default:
+ NOTREACHED();
+ break;
+ }
+ }
+
+ // Record Blink breakdowns.
+ for (auto it = processed_blink_breakdown.CreateIterator(); it.IsValid();
+ it.Advance()) {
+ switch (it.GetBreakdown()) {
+#define CASE_FOR_BLINK_BREAKDOWN(name) \
+ case CompositorFrameReporter::BlinkBreakdown::k##name: \
+ builder.SetSendBeginMainFrameToCommit_##name( \
+ it.GetLatency().InMicroseconds()); \
+ break;
+ CASE_FOR_BLINK_BREAKDOWN(HandleInputEvents);
+ CASE_FOR_BLINK_BREAKDOWN(Animate);
+ CASE_FOR_BLINK_BREAKDOWN(StyleUpdate);
+ CASE_FOR_BLINK_BREAKDOWN(LayoutUpdate);
+ CASE_FOR_BLINK_BREAKDOWN(Prepaint);
+ CASE_FOR_BLINK_BREAKDOWN(CompositingInputs);
+ CASE_FOR_BLINK_BREAKDOWN(CompositingAssignments);
+ CASE_FOR_BLINK_BREAKDOWN(Paint);
+ CASE_FOR_BLINK_BREAKDOWN(CompositeCommit);
+ CASE_FOR_BLINK_BREAKDOWN(UpdateLayers);
+ CASE_FOR_BLINK_BREAKDOWN(BeginMainSentToStarted);
+#undef CASE_FOR_BLINK_BREAKDOWN
+ default:
+ NOTREACHED();
break;
+ }
+ }
+
+ // Record Viz breakdowns.
+ for (auto it = processed_viz_breakdown.CreateIterator(false); it.IsValid();
+ it.Advance()) {
+ switch (it.GetBreakdown()) {
+#define CASE_FOR_VIZ_BREAKDOWN(name) \
+ case CompositorFrameReporter::VizBreakdown::k##name: \
+ builder.SetSubmitCompositorFrameToPresentationCompositorFrame_##name( \
+ it.GetDuration().InMicroseconds()); \
+ break;
+ CASE_FOR_VIZ_BREAKDOWN(SubmitToReceiveCompositorFrame);
+ CASE_FOR_VIZ_BREAKDOWN(ReceivedCompositorFrameToStartDraw);
+ CASE_FOR_VIZ_BREAKDOWN(StartDrawToSwapStart);
+ CASE_FOR_VIZ_BREAKDOWN(SwapStartToSwapEnd);
+ CASE_FOR_VIZ_BREAKDOWN(SwapEndToPresentationCompositorFrame);
+ CASE_FOR_VIZ_BREAKDOWN(SwapStartToBufferAvailable);
+ CASE_FOR_VIZ_BREAKDOWN(BufferAvailableToBufferReady);
+ CASE_FOR_VIZ_BREAKDOWN(BufferReadyToLatch);
+ CASE_FOR_VIZ_BREAKDOWN(LatchToSwapEnd);
+#undef CASE_FOR_VIZ_BREAKDOWN
default:
NOTREACHED();
break;
}
}
- // Record the active trackers
+ // Record the active trackers.
for (size_t type = 0; type < active_trackers.size(); ++type) {
if (!active_trackers.test(type))
continue;
@@ -278,7 +297,10 @@ void UkmManager::RecordCompositorLatencyUKM(
void UkmManager::RecordEventLatencyUKM(
const EventMetrics::List& events_metrics,
const std::vector<CompositorFrameReporter::StageData>& stage_history,
- const viz::FrameTimingDetails& viz_breakdown) const {
+ const CompositorFrameReporter::ProcessedBlinkBreakdown&
+ processed_blink_breakdown,
+ const CompositorFrameReporter::ProcessedVizBreakdown&
+ processed_viz_breakdown) const {
using StageType = CompositorFrameReporter::StageType;
for (const auto& event_metrics : events_metrics) {
@@ -286,46 +308,162 @@ void UkmManager::RecordEventLatencyUKM(
builder.SetEventType(static_cast<int64_t>(event_metrics->type()));
+ base::TimeTicks generated_timestamp =
+ event_metrics->GetDispatchStageTimestamp(
+ EventMetrics::DispatchStage::kGenerated);
+
if (event_metrics->scroll_type()) {
builder.SetScrollInputType(
static_cast<int64_t>(*event_metrics->scroll_type()));
- if (!viz_breakdown.swap_timings.is_null()) {
+ if (event_metrics->ShouldReportScrollingTotalLatency() &&
+ !processed_viz_breakdown.swap_start().is_null()) {
builder.SetTotalLatencyToSwapBegin(
- (viz_breakdown.swap_timings.swap_start -
- event_metrics->time_stamp())
+ (processed_viz_breakdown.swap_start() - generated_timestamp)
.InMicroseconds());
}
}
- // It is possible for an event to arrive in the compositor in the middle of
- // a frame (e.g. the browser received the event *after* renderer received a
- // begin-impl, and the event reached the compositor before that frame
+ // Record event dispatch metrics.
+ EventMetrics::DispatchStage dispatch_stage =
+ EventMetrics::DispatchStage::kGenerated;
+ base::TimeTicks dispatch_timestamp = generated_timestamp;
+ while (dispatch_stage != EventMetrics::DispatchStage::kMaxValue) {
+ DCHECK(!dispatch_timestamp.is_null());
+ int dispatch_index = static_cast<int>(dispatch_stage);
+
+ // Find the end dispatch stage.
+ auto end_stage =
+ static_cast<EventMetrics::DispatchStage>(dispatch_index + 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;
+
+ const int64_t dispatch_latency =
+ (end_timestamp - dispatch_timestamp).InMicroseconds();
+ switch (dispatch_stage) {
+ case EventMetrics::DispatchStage::kGenerated:
+ DCHECK_EQ(end_stage,
+ EventMetrics::DispatchStage::kArrivedInRendererCompositor);
+ builder.SetGenerationToRendererCompositor(dispatch_latency);
+ break;
+ case EventMetrics::DispatchStage::kArrivedInRendererCompositor:
+ switch (end_stage) {
+ case EventMetrics::DispatchStage::kRendererCompositorStarted:
+ builder.SetRendererCompositorQueueingDelay(dispatch_latency);
+ break;
+ case EventMetrics::DispatchStage::kRendererMainStarted:
+ builder.SetRendererCompositorToMain(dispatch_latency);
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ break;
+ case EventMetrics::DispatchStage::kRendererCompositorStarted:
+ DCHECK_EQ(end_stage,
+ EventMetrics::DispatchStage::kRendererCompositorFinished);
+ builder.SetRendererCompositorProcessing(dispatch_latency);
+ break;
+ case EventMetrics::DispatchStage::kRendererCompositorFinished:
+ DCHECK_EQ(end_stage,
+ EventMetrics::DispatchStage::kRendererMainStarted);
+ builder.SetRendererCompositorToMain(dispatch_latency);
+ break;
+ case EventMetrics::DispatchStage::kRendererMainStarted:
+ DCHECK_EQ(end_stage,
+ EventMetrics::DispatchStage::kRendererMainFinished);
+ builder.SetRendererMainProcessing(dispatch_latency);
+ break;
+ case EventMetrics::DispatchStage::kRendererMainFinished:
+ NOTREACHED();
+ break;
+ }
+
+ dispatch_stage = end_stage;
+ dispatch_timestamp = end_timestamp;
+ }
+
+ // It is possible for an event to be handled on the renderer in the middle
+ // of a frame (e.g. the browser received the event *after* renderer received
+ // a begin-impl, and the event was handled on the renderer before that frame
// ended). To handle such cases, find the first stage that happens after the
- // event's arrival in the browser.
+ // event's processing finished on the renderer.
auto stage_it = std::find_if(
stage_history.begin(), stage_history.end(),
- [&event_metrics](const CompositorFrameReporter::StageData& stage) {
- return stage.start_time > event_metrics->time_stamp();
+ [dispatch_timestamp](const CompositorFrameReporter::StageData& stage) {
+ return stage.start_time > dispatch_timestamp;
});
// TODO(crbug.com/1079116): Ideally, at least the start time of
// SubmitCompositorFrameToPresentationCompositorFrame stage should be
- // greater than the event time stamp, but apparently, this is not always the
- // case (see crbug.com/1093698). For now, skip to the next event in such
- // cases. Hopefully, the work to reduce discrepancies between the new
- // EventLatency and the old Event.Latency metrics would fix this issue. If
- // not, we need to reconsider investigating this issue.
+ // greater than the final event dispatch timestamp, but apparently, this is
+ // not always the case (see crbug.com/1093698). For now, skip to the next
+ // event in such cases. Hopefully, the work to reduce discrepancies between
+ // the new EventLatency and the old Event.Latency metrics would fix this
+ // issue. If not, we need to reconsider investigating this issue.
if (stage_it == stage_history.end())
continue;
- builder.SetBrowserToRendererCompositor(
- (stage_it->start_time - event_metrics->time_stamp()).InMicroseconds());
+ switch (dispatch_stage) {
+ case EventMetrics::DispatchStage::kRendererCompositorFinished:
+ switch (stage_it->stage_type) {
+#define CASE_FOR_STAGE(stage_name, metrics_suffix) \
+ case StageType::k##stage_name: \
+ builder.SetRendererCompositorFinishedTo##metrics_suffix( \
+ (stage_it->start_time - dispatch_timestamp).InMicroseconds()); \
+ break;
+ CASE_FOR_STAGE(BeginImplFrameToSendBeginMainFrame, BeginImplFrame);
+ CASE_FOR_STAGE(SendBeginMainFrameToCommit, SendBeginMainFrame);
+ CASE_FOR_STAGE(Commit, Commit);
+ CASE_FOR_STAGE(EndCommitToActivation, EndCommit);
+ CASE_FOR_STAGE(Activation, Activation);
+ CASE_FOR_STAGE(EndActivateToSubmitCompositorFrame, EndActivate);
+ CASE_FOR_STAGE(SubmitCompositorFrameToPresentationCompositorFrame,
+ SubmitCompositorFrame);
+#undef CASE_FOR_STAGE
+ default:
+ NOTREACHED();
+ break;
+ }
+ break;
+ case EventMetrics::DispatchStage::kRendererMainFinished:
+ switch (stage_it->stage_type) {
+#define CASE_FOR_STAGE(stage_name, metrics_suffix) \
+ case StageType::k##stage_name: \
+ builder.SetRendererMainFinishedTo##metrics_suffix( \
+ (stage_it->start_time - dispatch_timestamp).InMicroseconds()); \
+ break;
+ CASE_FOR_STAGE(BeginImplFrameToSendBeginMainFrame, BeginImplFrame);
+ CASE_FOR_STAGE(SendBeginMainFrameToCommit, SendBeginMainFrame);
+ CASE_FOR_STAGE(Commit, Commit);
+ CASE_FOR_STAGE(EndCommitToActivation, EndCommit);
+ CASE_FOR_STAGE(Activation, Activation);
+ CASE_FOR_STAGE(EndActivateToSubmitCompositorFrame, EndActivate);
+ CASE_FOR_STAGE(SubmitCompositorFrameToPresentationCompositorFrame,
+ SubmitCompositorFrame);
+#undef CASE_FOR_STAGE
+ default:
+ NOTREACHED();
+ break;
+ }
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
for (; stage_it != stage_history.end(); ++stage_it) {
// Total latency is calculated since the event timestamp.
const base::TimeTicks start_time =
stage_it->stage_type == StageType::kTotalLatency
- ? event_metrics->time_stamp()
+ ? generated_timestamp
: stage_it->start_time;
switch (stage_it->stage_type) {
@@ -348,6 +486,58 @@ void UkmManager::RecordEventLatencyUKM(
}
}
+ // Record Blink breakdowns.
+ for (auto it = processed_blink_breakdown.CreateIterator(); it.IsValid();
+ it.Advance()) {
+ switch (it.GetBreakdown()) {
+#define CASE_FOR_BLINK_BREAKDOWN(name) \
+ case CompositorFrameReporter::BlinkBreakdown::k##name: \
+ builder.SetSendBeginMainFrameToCommit_##name( \
+ it.GetLatency().InMicroseconds()); \
+ break;
+ CASE_FOR_BLINK_BREAKDOWN(HandleInputEvents);
+ CASE_FOR_BLINK_BREAKDOWN(Animate);
+ CASE_FOR_BLINK_BREAKDOWN(StyleUpdate);
+ CASE_FOR_BLINK_BREAKDOWN(LayoutUpdate);
+ CASE_FOR_BLINK_BREAKDOWN(Prepaint);
+ CASE_FOR_BLINK_BREAKDOWN(CompositingInputs);
+ CASE_FOR_BLINK_BREAKDOWN(CompositingAssignments);
+ CASE_FOR_BLINK_BREAKDOWN(Paint);
+ CASE_FOR_BLINK_BREAKDOWN(CompositeCommit);
+ CASE_FOR_BLINK_BREAKDOWN(UpdateLayers);
+ CASE_FOR_BLINK_BREAKDOWN(BeginMainSentToStarted);
+#undef CASE_FOR_BLINK_BREAKDOWN
+ default:
+ NOTREACHED();
+ break;
+ }
+ }
+
+ // Record Viz breakdowns.
+ for (auto it = processed_viz_breakdown.CreateIterator(false); it.IsValid();
+ it.Advance()) {
+ switch (it.GetBreakdown()) {
+#define CASE_FOR_VIZ_BREAKDOWN(name) \
+ case CompositorFrameReporter::VizBreakdown::k##name: \
+ builder.SetSubmitCompositorFrameToPresentationCompositorFrame_##name( \
+ it.GetDuration().InMicroseconds()); \
+ break;
+ CASE_FOR_VIZ_BREAKDOWN(SubmitToReceiveCompositorFrame);
+ CASE_FOR_VIZ_BREAKDOWN(ReceivedCompositorFrameToStartDraw);
+ CASE_FOR_VIZ_BREAKDOWN(StartDrawToSwapStart);
+ CASE_FOR_VIZ_BREAKDOWN(SwapStartToSwapEnd);
+ CASE_FOR_VIZ_BREAKDOWN(SwapEndToPresentationCompositorFrame);
+ CASE_FOR_VIZ_BREAKDOWN(SwapStartToBufferAvailable);
+ CASE_FOR_VIZ_BREAKDOWN(BufferAvailableToBufferReady);
+ CASE_FOR_VIZ_BREAKDOWN(BufferReadyToLatch);
+ CASE_FOR_VIZ_BREAKDOWN(LatchToSwapEnd);
+#undef CASE_FOR_VIZ_BREAKDOWN
+ default:
+ NOTREACHED();
+ break;
+ }
+ }
+
builder.Record(recorder_.get());
}
}
diff --git a/chromium/cc/trees/ukm_manager.h b/chromium/cc/trees/ukm_manager.h
index b51147f71c3..03f82915e0e 100644
--- a/chromium/cc/trees/ukm_manager.h
+++ b/chromium/cc/trees/ukm_manager.h
@@ -12,7 +12,6 @@
#include "cc/metrics/compositor_frame_reporter.h"
#include "cc/metrics/event_metrics.h"
#include "cc/metrics/frame_sequence_metrics.h"
-#include "components/viz/common/frame_timing_details.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "url/gurl.h"
@@ -57,12 +56,18 @@ class CC_EXPORT UkmManager {
CompositorFrameReporter::FrameReportType report_type,
const std::vector<CompositorFrameReporter::StageData>& stage_history,
const CompositorFrameReporter::ActiveTrackers& active_trackers,
- const viz::FrameTimingDetails& viz_breakdown) const;
+ const CompositorFrameReporter::ProcessedBlinkBreakdown&
+ processed_blink_breakdown,
+ const CompositorFrameReporter::ProcessedVizBreakdown&
+ processed_viz_breakdown) const;
void RecordEventLatencyUKM(
const EventMetrics::List& events_metrics,
const std::vector<CompositorFrameReporter::StageData>& stage_history,
- const viz::FrameTimingDetails& viz_breakdown) const;
+ const CompositorFrameReporter::ProcessedBlinkBreakdown&
+ processed_blink_breakdown,
+ const CompositorFrameReporter::ProcessedVizBreakdown&
+ processed_viz_breakdown) const;
ukm::UkmRecorder* recorder_for_testing() { return recorder_.get(); }
diff --git a/chromium/cc/trees/ukm_manager_unittest.cc b/chromium/cc/trees/ukm_manager_unittest.cc
index 6449021af38..4f7aabe28f0 100644
--- a/chromium/cc/trees/ukm_manager_unittest.cc
+++ b/chromium/cc/trees/ukm_manager_unittest.cc
@@ -4,10 +4,13 @@
#include "cc/trees/ukm_manager.h"
+#include <algorithm>
#include <utility>
#include <vector>
+#include "base/test/simple_test_tick_clock.h"
#include "base/time/time.h"
+#include "cc/metrics/begin_main_frame_metrics.h"
#include "cc/metrics/compositor_frame_reporter.h"
#include "cc/metrics/event_metrics.h"
#include "components/ukm/test_ukm_recorder.h"
@@ -42,10 +45,36 @@ const char kScrollInputType[] = "ScrollInputType";
// Names of compositor stages and substages used in compositor/event latency UKM
// metrics.
-const char kBrowserToRendererCompositor[] = "BrowserToRendererCompositor";
+const char kGenerationToRendererCompositor[] = "GenerationToRendererCompositor";
+const char kRendererCompositorQueueingDelay[] =
+ "RendererCompositorQueueingDelay";
+const char kRendererCompositorProcessing[] = "RendererCompositorProcessing";
+const char kRendererCompositorToMain[] = "RendererCompositorToMain";
+const char kRendererMainProcessing[] = "RendererMainProcessing";
+const char kRendererMainFinishedToBeginImplFrame[] =
+ "RendererMainFinishedToBeginImplFrame";
const char kBeginImplFrameToSendBeginMainFrame[] =
"BeginImplFrameToSendBeginMainFrame";
const char kSendBeginMainFrameToCommit[] = "SendBeginMainFrameToCommit";
+const char kBlinkBreakdownHandleInputEvents[] =
+ "SendBeginMainFrameToCommit.HandleInputEvents";
+const char kBlinkBreakdownAnimate[] = "SendBeginMainFrameToCommit.Animate";
+const char kBlinkBreakdownStyleUpdate[] =
+ "SendBeginMainFrameToCommit.StyleUpdate";
+const char kBlinkBreakdownLayoutUpdate[] =
+ "SendBeginMainFrameToCommit.LayoutUpdate";
+const char kBlinkBreakdownPrepaint[] = "SendBeginMainFrameToCommit.Prepaint";
+const char kBlinkBreakdownCompositingInputs[] =
+ "SendBeginMainFrameToCommit.CompositingInputs";
+const char kBlinkBreakdownCompositingAssignments[] =
+ "SendBeginMainFrameToCommit.CompositingAssignments";
+const char kBlinkBreakdownPaint[] = "SendBeginMainFrameToCommit.Paint";
+const char kBlinkBreakdownCompositeCommit[] =
+ "SendBeginMainFrameToCommit.CompositeCommit";
+const char kBlinkBreakdownUpdateLayers[] =
+ "SendBeginMainFrameToCommit.UpdateLayers";
+const char kBlinkBreakdownBeginMainSentToStarted[] =
+ "SendBeginMainFrameToCommit.BeginMainSentToStarted";
const char kCommit[] = "Commit";
const char kEndCommitToActivation[] = "EndCommitToActivation";
const char kActivation[] = "Activation";
@@ -63,6 +92,16 @@ const char kVizBreakdownStartDrawToSwapStart[] =
"SubmitCompositorFrameToPresentationCompositorFrame.StartDrawToSwapStart";
const char kVizBreakdownSwapStartToSwapEnd[] =
"SubmitCompositorFrameToPresentationCompositorFrame.SwapStartToSwapEnd";
+const char kVizBreakdownSwapStartToBufferAvailable[] =
+ "SubmitCompositorFrameToPresentationCompositorFrame."
+ "SwapStartToBufferAvailable";
+const char kVizBreakdownBufferAvailableToBufferReady[] =
+ "SubmitCompositorFrameToPresentationCompositorFrame."
+ "BufferAvailableToBufferReady";
+const char kVizBreakdownBufferReadyToLatch[] =
+ "SubmitCompositorFrameToPresentationCompositorFrame.BufferReadyToLatch";
+const char kVizBreakdownLatchToSwapEnd[] =
+ "SubmitCompositorFrameToPresentationCompositorFrame.LatchToSwapEnd";
const char kVizBreakdownSwapEndToPresentationCompositorFrame[] =
"SubmitCompositorFrameToPresentationCompositorFrame."
"SwapEndToPresentationCompositorFrame";
@@ -96,8 +135,105 @@ class UkmManagerTest : public testing::Test {
~UkmManagerTest() override = default;
protected:
+ base::TimeTicks AdvanceNowByMs(int advance_ms) {
+ test_tick_clock_.Advance(base::TimeDelta::FromMicroseconds(advance_ms));
+ return test_tick_clock_.NowTicks();
+ }
+
+ std::unique_ptr<EventMetrics> CreateEventMetrics(
+ ui::EventType type,
+ base::Optional<EventMetrics::ScrollUpdateType> scroll_update_type,
+ base::Optional<ui::ScrollInputType> scroll_input_type) {
+ base::TimeTicks event_time = AdvanceNowByMs(10);
+ AdvanceNowByMs(10);
+ std::unique_ptr<EventMetrics> metrics = EventMetrics::CreateForTesting(
+ type, scroll_update_type, scroll_input_type, event_time,
+ &test_tick_clock_);
+ if (metrics) {
+ AdvanceNowByMs(10);
+ metrics->SetDispatchStageTimestamp(
+ EventMetrics::DispatchStage::kRendererCompositorStarted);
+ AdvanceNowByMs(10);
+ metrics->SetDispatchStageTimestamp(
+ EventMetrics::DispatchStage::kRendererCompositorFinished);
+ AdvanceNowByMs(10);
+ metrics->SetDispatchStageTimestamp(
+ EventMetrics::DispatchStage::kRendererMainStarted);
+ AdvanceNowByMs(10);
+ metrics->SetDispatchStageTimestamp(
+ EventMetrics::DispatchStage::kRendererMainFinished);
+ }
+ return metrics;
+ }
+
+ struct DispatchTimestamps {
+ base::TimeTicks generated;
+ base::TimeTicks arrived_in_renderer;
+ base::TimeTicks renderer_compositor_started;
+ base::TimeTicks renderer_compositor_finished;
+ base::TimeTicks renderer_main_started;
+ base::TimeTicks renderer_main_finished;
+ };
+ std::vector<DispatchTimestamps> GetEventDispatchTimestamps(
+ const EventMetrics::List& events_metrics) {
+ std::vector<DispatchTimestamps> event_times;
+ event_times.reserve(events_metrics.size());
+ std::transform(
+ events_metrics.cbegin(), events_metrics.cend(),
+ std::back_inserter(event_times), [](const auto& event_metrics) {
+ return DispatchTimestamps{
+ event_metrics->GetDispatchStageTimestamp(
+ EventMetrics::DispatchStage::kGenerated),
+ event_metrics->GetDispatchStageTimestamp(
+ EventMetrics::DispatchStage::kArrivedInRendererCompositor),
+ event_metrics->GetDispatchStageTimestamp(
+ EventMetrics::DispatchStage::kRendererCompositorStarted),
+ event_metrics->GetDispatchStageTimestamp(
+ EventMetrics::DispatchStage::kRendererCompositorFinished),
+ event_metrics->GetDispatchStageTimestamp(
+ EventMetrics::DispatchStage::kRendererMainStarted),
+ event_metrics->GetDispatchStageTimestamp(
+ EventMetrics::DispatchStage::kRendererMainFinished),
+ };
+ });
+ return event_times;
+ }
+
+ BeginMainFrameMetrics BuildBlinkBreakdown() {
+ BeginMainFrameMetrics breakdown;
+ breakdown.handle_input_events = base::TimeDelta::FromMicroseconds(10);
+ breakdown.animate = base::TimeDelta::FromMicroseconds(9);
+ breakdown.style_update = base::TimeDelta::FromMicroseconds(8);
+ breakdown.layout_update = base::TimeDelta::FromMicroseconds(7);
+ breakdown.compositing_inputs = base::TimeDelta::FromMicroseconds(6);
+ breakdown.prepaint = base::TimeDelta::FromMicroseconds(5);
+ breakdown.compositing_assignments = base::TimeDelta::FromMicroseconds(4);
+ breakdown.paint = base::TimeDelta::FromMicroseconds(3);
+ breakdown.composite_commit = base::TimeDelta::FromMicroseconds(2);
+ breakdown.update_layers = base::TimeDelta::FromMicroseconds(1);
+
+ // Advance now by the sum of the breakdowns.
+ AdvanceNowByMs(10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1);
+
+ return breakdown;
+ }
+
+ viz::FrameTimingDetails BuildVizBreakdown() {
+ viz::FrameTimingDetails breakdown;
+ breakdown.received_compositor_frame_timestamp = AdvanceNowByMs(1);
+ breakdown.draw_start_timestamp = AdvanceNowByMs(2);
+ breakdown.swap_timings.swap_start = AdvanceNowByMs(3);
+ breakdown.presentation_feedback.available_timestamp = AdvanceNowByMs(1);
+ breakdown.presentation_feedback.ready_timestamp = AdvanceNowByMs(1);
+ breakdown.presentation_feedback.latch_timestamp = AdvanceNowByMs(1);
+ breakdown.swap_timings.swap_end = AdvanceNowByMs(1);
+ breakdown.presentation_feedback.timestamp = AdvanceNowByMs(5);
+ return breakdown;
+ }
+
ukm::TestUkmRecorder* test_ukm_recorder_;
std::unique_ptr<UkmManager> manager_;
+ base::SimpleTestTickClock test_tick_clock_;
};
TEST_F(UkmManagerTest, Basic) {
@@ -185,34 +321,19 @@ INSTANTIATE_TEST_SUITE_P(
CompositorFrameReporter::FrameReportType::kCompositorOnlyFrame));
TEST_P(UkmManagerCompositorLatencyTest, CompositorLatency) {
- base::TimeTicks now = base::TimeTicks::Now();
-
- const base::TimeTicks begin_impl_time =
- (now += base::TimeDelta::FromMicroseconds(10));
- const base::TimeTicks begin_main_time =
- (now += base::TimeDelta::FromMicroseconds(10));
- const base::TimeTicks begin_commit_time =
- (now += base::TimeDelta::FromMicroseconds(10));
- const base::TimeTicks end_commit_time =
- (now += base::TimeDelta::FromMicroseconds(10));
- const base::TimeTicks begin_activate_time =
- (now += base::TimeDelta::FromMicroseconds(10));
- const base::TimeTicks end_activate_time =
- (now += base::TimeDelta::FromMicroseconds(10));
- const base::TimeTicks submit_time =
- (now += base::TimeDelta::FromMicroseconds(10));
-
- viz::FrameTimingDetails viz_breakdown;
- viz_breakdown.received_compositor_frame_timestamp =
- (now += base::TimeDelta::FromMicroseconds(1));
- viz_breakdown.draw_start_timestamp =
- (now += base::TimeDelta::FromMicroseconds(2));
- viz_breakdown.swap_timings.swap_start =
- (now += base::TimeDelta::FromMicroseconds(3));
- viz_breakdown.swap_timings.swap_end =
- (now += base::TimeDelta::FromMicroseconds(4));
- viz_breakdown.presentation_feedback.timestamp =
- (now += base::TimeDelta::FromMicroseconds(5));
+ const base::TimeTicks begin_impl_time = AdvanceNowByMs(10);
+ const base::TimeTicks begin_main_time = AdvanceNowByMs(10);
+ const base::TimeTicks begin_main_start_time = AdvanceNowByMs(10);
+
+ BeginMainFrameMetrics blink_breakdown = BuildBlinkBreakdown();
+
+ const base::TimeTicks begin_commit_time = AdvanceNowByMs(10);
+ const base::TimeTicks end_commit_time = AdvanceNowByMs(10);
+ const base::TimeTicks begin_activate_time = AdvanceNowByMs(10);
+ const base::TimeTicks end_activate_time = AdvanceNowByMs(10);
+ const base::TimeTicks submit_time = AdvanceNowByMs(10);
+
+ viz::FrameTimingDetails viz_breakdown = BuildVizBreakdown();
std::vector<CompositorFrameReporter::StageData> stage_history = {
{
@@ -268,8 +389,13 @@ TEST_P(UkmManagerCompositorLatencyTest, CompositorLatency) {
active_trackers.set(
static_cast<size_t>(FrameSequenceTrackerType::kCompositorAnimation));
- manager_->RecordCompositorLatencyUKM(report_type(), stage_history,
- active_trackers, viz_breakdown);
+ CompositorFrameReporter::ProcessedBlinkBreakdown processed_blink_breakdown(
+ begin_main_time, begin_main_start_time, blink_breakdown);
+ CompositorFrameReporter::ProcessedVizBreakdown processed_viz_breakdown(
+ submit_time, viz_breakdown);
+ manager_->RecordCompositorLatencyUKM(
+ report_type(), stage_history, active_trackers, processed_blink_breakdown,
+ processed_viz_breakdown);
const auto& entries =
test_ukm_recorder_->GetEntriesByName(kCompositorLatency);
@@ -293,6 +419,37 @@ TEST_P(UkmManagerCompositorLatencyTest, CompositorLatency) {
entry, kSendBeginMainFrameToCommit,
(begin_commit_time - begin_main_time).InMicroseconds());
test_ukm_recorder_->ExpectEntryMetric(
+ entry, kBlinkBreakdownHandleInputEvents,
+ blink_breakdown.handle_input_events.InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kBlinkBreakdownAnimate, blink_breakdown.animate.InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kBlinkBreakdownStyleUpdate,
+ blink_breakdown.style_update.InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kBlinkBreakdownLayoutUpdate,
+ blink_breakdown.layout_update.InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kBlinkBreakdownPrepaint,
+ blink_breakdown.prepaint.InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kBlinkBreakdownCompositingInputs,
+ blink_breakdown.compositing_inputs.InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kBlinkBreakdownCompositingAssignments,
+ blink_breakdown.compositing_assignments.InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(entry, kBlinkBreakdownPaint,
+ blink_breakdown.paint.InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kBlinkBreakdownCompositeCommit,
+ blink_breakdown.composite_commit.InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kBlinkBreakdownUpdateLayers,
+ blink_breakdown.update_layers.InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kBlinkBreakdownBeginMainSentToStarted,
+ (begin_main_start_time - begin_main_time).InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
entry, kCommit, (end_commit_time - begin_commit_time).InMicroseconds());
test_ukm_recorder_->ExpectEntryMetric(
entry, kEndCommitToActivation,
@@ -326,6 +483,26 @@ TEST_P(UkmManagerCompositorLatencyTest, CompositorLatency) {
viz_breakdown.swap_timings.swap_start)
.InMicroseconds());
test_ukm_recorder_->ExpectEntryMetric(
+ entry, kVizBreakdownSwapStartToBufferAvailable,
+ (viz_breakdown.presentation_feedback.available_timestamp -
+ viz_breakdown.swap_timings.swap_start)
+ .InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kVizBreakdownBufferAvailableToBufferReady,
+ (viz_breakdown.presentation_feedback.ready_timestamp -
+ viz_breakdown.presentation_feedback.available_timestamp)
+ .InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kVizBreakdownBufferReadyToLatch,
+ (viz_breakdown.presentation_feedback.latch_timestamp -
+ viz_breakdown.presentation_feedback.ready_timestamp)
+ .InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kVizBreakdownLatchToSwapEnd,
+ (viz_breakdown.swap_timings.swap_end -
+ viz_breakdown.presentation_feedback.latch_timestamp)
+ .InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
entry, kVizBreakdownSwapEndToPresentationCompositorFrame,
(viz_breakdown.presentation_feedback.timestamp -
viz_breakdown.swap_timings.swap_end)
@@ -346,52 +523,62 @@ TEST_P(UkmManagerCompositorLatencyTest, CompositorLatency) {
}
TEST_F(UkmManagerTest, EventLatency) {
- base::TimeTicks now = base::TimeTicks::Now();
-
- const base::TimeTicks event_time = now;
std::unique_ptr<EventMetrics> event_metrics_ptrs[] = {
- EventMetrics::Create(ui::ET_GESTURE_SCROLL_BEGIN, base::nullopt,
- event_time, ui::ScrollInputType::kWheel),
- EventMetrics::Create(ui::ET_GESTURE_SCROLL_UPDATE,
- EventMetrics::ScrollUpdateType::kStarted, event_time,
- ui::ScrollInputType::kWheel),
- EventMetrics::Create(ui::ET_GESTURE_SCROLL_UPDATE,
- EventMetrics::ScrollUpdateType::kContinued,
- event_time, ui::ScrollInputType::kWheel),
+ CreateEventMetrics(ui::ET_GESTURE_SCROLL_BEGIN, base::nullopt,
+ ui::ScrollInputType::kWheel),
+ CreateEventMetrics(ui::ET_GESTURE_SCROLL_UPDATE,
+ EventMetrics::ScrollUpdateType::kStarted,
+ ui::ScrollInputType::kWheel),
+ CreateEventMetrics(ui::ET_GESTURE_SCROLL_UPDATE,
+ EventMetrics::ScrollUpdateType::kContinued,
+ ui::ScrollInputType::kWheel),
};
EXPECT_THAT(event_metrics_ptrs, ::testing::Each(::testing::NotNull()));
EventMetrics::List events_metrics(
std::make_move_iterator(std::begin(event_metrics_ptrs)),
std::make_move_iterator(std::end(event_metrics_ptrs)));
+ std::vector<DispatchTimestamps> event_dispatch_times =
+ GetEventDispatchTimestamps(events_metrics);
+
+ const base::TimeTicks begin_impl_time = AdvanceNowByMs(10);
+ const base::TimeTicks begin_main_time = AdvanceNowByMs(10);
+ const base::TimeTicks begin_main_start_time = AdvanceNowByMs(10);
+
+ BeginMainFrameMetrics blink_breakdown = BuildBlinkBreakdown();
+
+ const base::TimeTicks begin_commit_time = AdvanceNowByMs(10);
+ const base::TimeTicks end_commit_time = AdvanceNowByMs(10);
+ const base::TimeTicks begin_activate_time = AdvanceNowByMs(10);
+ const base::TimeTicks end_activate_time = AdvanceNowByMs(10);
+ const base::TimeTicks submit_time = AdvanceNowByMs(10);
- const base::TimeTicks begin_impl_time =
- (now += base::TimeDelta::FromMicroseconds(10));
- const base::TimeTicks end_activate_time =
- (now += base::TimeDelta::FromMicroseconds(10));
- const base::TimeTicks submit_time =
- (now += base::TimeDelta::FromMicroseconds(10));
-
- viz::FrameTimingDetails viz_breakdown;
- viz_breakdown.received_compositor_frame_timestamp =
- (now += base::TimeDelta::FromMicroseconds(1));
- viz_breakdown.draw_start_timestamp =
- (now += base::TimeDelta::FromMicroseconds(2));
- viz_breakdown.swap_timings.swap_start =
- (now += base::TimeDelta::FromMicroseconds(3));
- viz_breakdown.swap_timings.swap_end =
- (now += base::TimeDelta::FromMicroseconds(4));
- viz_breakdown.presentation_feedback.timestamp =
- (now += base::TimeDelta::FromMicroseconds(5));
-
- const base::TimeTicks swap_start_time = viz_breakdown.swap_timings.swap_start;
- const base::TimeTicks present_time =
- viz_breakdown.presentation_feedback.timestamp;
+ viz::FrameTimingDetails viz_breakdown = BuildVizBreakdown();
std::vector<CompositorFrameReporter::StageData> stage_history = {
{
CompositorFrameReporter::StageType::
kBeginImplFrameToSendBeginMainFrame,
begin_impl_time,
+ begin_main_time,
+ },
+ {
+ CompositorFrameReporter::StageType::kSendBeginMainFrameToCommit,
+ begin_main_time,
+ begin_commit_time,
+ },
+ {
+ CompositorFrameReporter::StageType::kCommit,
+ begin_commit_time,
+ end_commit_time,
+ },
+ {
+ CompositorFrameReporter::StageType::kEndCommitToActivation,
+ end_commit_time,
+ begin_activate_time,
+ },
+ {
+ CompositorFrameReporter::StageType::kActivation,
+ begin_activate_time,
end_activate_time,
},
{
@@ -404,16 +591,22 @@ TEST_F(UkmManagerTest, EventLatency) {
CompositorFrameReporter::StageType::
kSubmitCompositorFrameToPresentationCompositorFrame,
submit_time,
- present_time,
+ viz_breakdown.presentation_feedback.timestamp,
},
{
CompositorFrameReporter::StageType::kTotalLatency,
- event_time,
- present_time,
+ begin_impl_time,
+ viz_breakdown.presentation_feedback.timestamp,
},
};
- manager_->RecordEventLatencyUKM(events_metrics, stage_history, viz_breakdown);
+ CompositorFrameReporter::ProcessedBlinkBreakdown processed_blink_breakdown(
+ begin_main_time, begin_main_start_time, blink_breakdown);
+ CompositorFrameReporter::ProcessedVizBreakdown processed_viz_breakdown(
+ submit_time, viz_breakdown);
+ manager_->RecordEventLatencyUKM(events_metrics, stage_history,
+ processed_blink_breakdown,
+ processed_viz_breakdown);
const auto& entries = test_ukm_recorder_->GetEntriesByName(kEventLatency);
EXPECT_EQ(3u, entries.size());
@@ -431,28 +624,185 @@ TEST_F(UkmManagerTest, EventLatency) {
static_cast<int64_t>(*event_metrics->scroll_type()));
test_ukm_recorder_->ExpectEntryMetric(
- entry, kBrowserToRendererCompositor,
- (begin_impl_time - event_time).InMicroseconds());
+ entry, kGenerationToRendererCompositor,
+ (event_dispatch_times[i].arrived_in_renderer -
+ event_dispatch_times[i].generated)
+ .InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kRendererCompositorQueueingDelay,
+ (event_dispatch_times[i].renderer_compositor_started -
+ event_dispatch_times[i].arrived_in_renderer)
+ .InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kRendererCompositorProcessing,
+ (event_dispatch_times[i].renderer_compositor_finished -
+ event_dispatch_times[i].renderer_compositor_started)
+ .InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kRendererCompositorToMain,
+ (event_dispatch_times[i].renderer_main_started -
+ event_dispatch_times[i].renderer_compositor_finished)
+ .InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kRendererMainProcessing,
+ (event_dispatch_times[i].renderer_main_finished -
+ event_dispatch_times[i].renderer_main_started)
+ .InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kRendererMainFinishedToBeginImplFrame,
+ (begin_impl_time - event_dispatch_times[i].renderer_main_finished)
+ .InMicroseconds());
test_ukm_recorder_->ExpectEntryMetric(
entry, kBeginImplFrameToSendBeginMainFrame,
- (end_activate_time - begin_impl_time).InMicroseconds());
- EXPECT_FALSE(
- test_ukm_recorder_->EntryHasMetric(entry, kSendBeginMainFrameToCommit));
- EXPECT_FALSE(test_ukm_recorder_->EntryHasMetric(entry, kCommit));
- EXPECT_FALSE(
- test_ukm_recorder_->EntryHasMetric(entry, kEndCommitToActivation));
- EXPECT_FALSE(test_ukm_recorder_->EntryHasMetric(entry, kActivation));
+ (begin_main_time - begin_impl_time).InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kSendBeginMainFrameToCommit,
+ (begin_commit_time - begin_main_time).InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kBlinkBreakdownHandleInputEvents,
+ blink_breakdown.handle_input_events.InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kBlinkBreakdownAnimate,
+ blink_breakdown.animate.InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kBlinkBreakdownStyleUpdate,
+ blink_breakdown.style_update.InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kBlinkBreakdownLayoutUpdate,
+ blink_breakdown.layout_update.InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kBlinkBreakdownPrepaint,
+ blink_breakdown.prepaint.InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kBlinkBreakdownCompositingInputs,
+ blink_breakdown.compositing_inputs.InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kBlinkBreakdownCompositingAssignments,
+ blink_breakdown.compositing_assignments.InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kBlinkBreakdownPaint, blink_breakdown.paint.InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kBlinkBreakdownCompositeCommit,
+ blink_breakdown.composite_commit.InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kBlinkBreakdownUpdateLayers,
+ blink_breakdown.update_layers.InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kBlinkBreakdownBeginMainSentToStarted,
+ (begin_main_start_time - begin_main_time).InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kCommit, (end_commit_time - begin_commit_time).InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kEndCommitToActivation,
+ (begin_activate_time - end_commit_time).InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kActivation,
+ (end_activate_time - begin_activate_time).InMicroseconds());
test_ukm_recorder_->ExpectEntryMetric(
entry, kEndActivateToSubmitCompositorFrame,
(submit_time - end_activate_time).InMicroseconds());
test_ukm_recorder_->ExpectEntryMetric(
entry, kSubmitCompositorFrameToPresentationCompositorFrame,
- (present_time - submit_time).InMicroseconds());
+ (viz_breakdown.presentation_feedback.timestamp - submit_time)
+ .InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kVizBreakdownSubmitToReceiveCompositorFrame,
+ (viz_breakdown.received_compositor_frame_timestamp - submit_time)
+ .InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kVizBreakdownReceivedCompositorFrameToStartDraw,
+ (viz_breakdown.draw_start_timestamp -
+ viz_breakdown.received_compositor_frame_timestamp)
+ .InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kVizBreakdownStartDrawToSwapStart,
+ (viz_breakdown.swap_timings.swap_start -
+ viz_breakdown.draw_start_timestamp)
+ .InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kVizBreakdownSwapStartToSwapEnd,
+ (viz_breakdown.swap_timings.swap_end -
+ viz_breakdown.swap_timings.swap_start)
+ .InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kVizBreakdownSwapStartToBufferAvailable,
+ (viz_breakdown.presentation_feedback.available_timestamp -
+ viz_breakdown.swap_timings.swap_start)
+ .InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kVizBreakdownBufferAvailableToBufferReady,
+ (viz_breakdown.presentation_feedback.ready_timestamp -
+ viz_breakdown.presentation_feedback.available_timestamp)
+ .InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kVizBreakdownBufferReadyToLatch,
+ (viz_breakdown.presentation_feedback.latch_timestamp -
+ viz_breakdown.presentation_feedback.ready_timestamp)
+ .InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kVizBreakdownLatchToSwapEnd,
+ (viz_breakdown.swap_timings.swap_end -
+ viz_breakdown.presentation_feedback.latch_timestamp)
+ .InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kVizBreakdownSwapEndToPresentationCompositorFrame,
+ (viz_breakdown.presentation_feedback.timestamp -
+ viz_breakdown.swap_timings.swap_end)
+ .InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kVizBreakdownSubmitToReceiveCompositorFrame,
+ (viz_breakdown.received_compositor_frame_timestamp - submit_time)
+ .InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kVizBreakdownReceivedCompositorFrameToStartDraw,
+ (viz_breakdown.draw_start_timestamp -
+ viz_breakdown.received_compositor_frame_timestamp)
+ .InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kVizBreakdownStartDrawToSwapStart,
+ (viz_breakdown.swap_timings.swap_start -
+ viz_breakdown.draw_start_timestamp)
+ .InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kVizBreakdownSwapStartToSwapEnd,
+ (viz_breakdown.swap_timings.swap_end -
+ viz_breakdown.swap_timings.swap_start)
+ .InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kVizBreakdownSwapStartToBufferAvailable,
+ (viz_breakdown.presentation_feedback.available_timestamp -
+ viz_breakdown.swap_timings.swap_start)
+ .InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kVizBreakdownBufferAvailableToBufferReady,
+ (viz_breakdown.presentation_feedback.ready_timestamp -
+ viz_breakdown.presentation_feedback.available_timestamp)
+ .InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kVizBreakdownBufferReadyToLatch,
+ (viz_breakdown.presentation_feedback.latch_timestamp -
+ viz_breakdown.presentation_feedback.ready_timestamp)
+ .InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kVizBreakdownLatchToSwapEnd,
+ (viz_breakdown.swap_timings.swap_end -
+ viz_breakdown.presentation_feedback.latch_timestamp)
+ .InMicroseconds());
+ test_ukm_recorder_->ExpectEntryMetric(
+ entry, kVizBreakdownSwapEndToPresentationCompositorFrame,
+ (viz_breakdown.presentation_feedback.timestamp -
+ viz_breakdown.swap_timings.swap_end)
+ .InMicroseconds());
test_ukm_recorder_->ExpectEntryMetric(
entry, kTotalLatencyToSwapBegin,
- (swap_start_time - event_time).InMicroseconds());
+ (viz_breakdown.swap_timings.swap_start -
+ event_dispatch_times[i].generated)
+ .InMicroseconds());
test_ukm_recorder_->ExpectEntryMetric(
- entry, kTotalLatency, (present_time - event_time).InMicroseconds());
+ entry, kTotalLatency,
+ (viz_breakdown.presentation_feedback.timestamp -
+ event_dispatch_times[i].generated)
+ .InMicroseconds());
}
}