summaryrefslogtreecommitdiffstats
path: root/chromium/cc
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2023-02-13 16:03:23 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2023-05-26 11:26:35 +0000
commit813d9ae984a99e739b99cf694a9d5b24d0a6b7a7 (patch)
tree60c14d40d77a3c702c8a72887662d97c0b8f3e99 /chromium/cc
parenteb596ba9fe579987eb93f6b4021ca156885b48c2 (diff)
BASELINE: Update Chromium to 110.0.5481.111
Change-Id: I2b5f5ed66fee2a6f8da61c9b17fd1b25bb5b3a4e Reviewed-on: https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/464348 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/cc')
-rw-r--r--chromium/cc/BUILD.gn22
-rw-r--r--chromium/cc/DEPS1
-rw-r--r--chromium/cc/animation/README.md38
-rw-r--r--chromium/cc/animation/animation_host_perftest.cc5
-rw-r--r--chromium/cc/animation/element_animations_unittest.cc194
-rw-r--r--chromium/cc/animation/scroll_timeline.h4
-rw-r--r--chromium/cc/base/devtools_instrumentation.cc6
-rw-r--r--chromium/cc/base/devtools_instrumentation.h2
-rw-r--r--chromium/cc/base/features.cc14
-rw-r--r--chromium/cc/base/features.h11
-rw-r--r--chromium/cc/base/float_quad_unittest.cc62
-rw-r--r--chromium/cc/base/math_util.cc20
-rw-r--r--chromium/cc/base/math_util.h18
-rw-r--r--chromium/cc/base/math_util_unittest.cc33
-rw-r--r--chromium/cc/base/region.cc12
-rw-r--r--chromium/cc/base/region.h4
-rw-r--r--chromium/cc/base/unique_notifier_unittest.cc8
-rw-r--r--chromium/cc/benchmarks/benchmark_instrumentation.cc9
-rw-r--r--chromium/cc/benchmarks/benchmark_instrumentation.h5
-rw-r--r--chromium/cc/benchmarks/invalidation_benchmark.cc6
-rw-r--r--chromium/cc/benchmarks/micro_benchmark_controller.cc9
-rw-r--r--chromium/cc/benchmarks/micro_benchmark_controller_unittest.cc4
-rw-r--r--chromium/cc/document_transition/document_transition_shared_element_id.cc54
-rw-r--r--chromium/cc/input/browser_controls_offset_manager.cc26
-rw-r--r--chromium/cc/input/browser_controls_offset_manager.h18
-rw-r--r--chromium/cc/input/browser_controls_offset_manager_unittest.cc60
-rw-r--r--chromium/cc/input/input_handler.cc183
-rw-r--r--chromium/cc/input/input_handler.h6
-rw-r--r--chromium/cc/input/page_scale_animation.cc1
-rw-r--r--chromium/cc/input/scrollbar_controller.cc3
-rw-r--r--chromium/cc/input/scroller_size_metrics.h16
-rw-r--r--chromium/cc/layers/append_quads_data.h4
-rw-r--r--chromium/cc/layers/document_transition_content_layer.cc42
-rw-r--r--chromium/cc/layers/document_transition_content_layer.h49
-rw-r--r--chromium/cc/layers/document_transition_content_layer_impl.h58
-rw-r--r--chromium/cc/layers/effect_tree_layer_list_iterator.h6
-rw-r--r--chromium/cc/layers/heads_up_display_layer_impl.cc9
-rw-r--r--chromium/cc/layers/layer.cc8
-rw-r--r--chromium/cc/layers/layer.h5
-rw-r--r--chromium/cc/layers/layer_impl.h10
-rw-r--r--chromium/cc/layers/layer_perftest.cc5
-rw-r--r--chromium/cc/layers/layer_unittest.cc236
-rw-r--r--chromium/cc/layers/picture_layer_impl.cc21
-rw-r--r--chromium/cc/layers/picture_layer_impl_perftest.cc6
-rw-r--r--chromium/cc/layers/picture_layer_unittest.cc10
-rw-r--r--chromium/cc/layers/render_surface_impl.cc29
-rw-r--r--chromium/cc/layers/render_surface_impl.h8
-rw-r--r--chromium/cc/layers/scrollbar_layer_unittest.cc7
-rw-r--r--chromium/cc/layers/texture_layer.cc11
-rw-r--r--chromium/cc/layers/texture_layer.h4
-rw-r--r--chromium/cc/layers/texture_layer_impl.cc9
-rw-r--r--chromium/cc/layers/texture_layer_impl.h4
-rw-r--r--chromium/cc/layers/texture_layer_unittest.cc112
-rw-r--r--chromium/cc/layers/video_layer_impl.cc6
-rw-r--r--chromium/cc/layers/view_transition_content_layer.cc41
-rw-r--r--chromium/cc/layers/view_transition_content_layer.h49
-rw-r--r--chromium/cc/layers/view_transition_content_layer_impl.cc (renamed from chromium/cc/layers/document_transition_content_layer_impl.cc)38
-rw-r--r--chromium/cc/layers/view_transition_content_layer_impl.h58
-rw-r--r--chromium/cc/metrics/compositor_frame_reporter.cc14
-rw-r--r--chromium/cc/metrics/compositor_frame_reporter.h4
-rw-r--r--chromium/cc/metrics/custom_metrics_recorder.h9
-rw-r--r--chromium/cc/metrics/dropped_frame_counter.cc6
-rw-r--r--chromium/cc/metrics/dropped_frame_counter_unittest.cc5
-rw-r--r--chromium/cc/metrics/event_metrics.cc7
-rw-r--r--chromium/cc/metrics/event_metrics.h1
-rw-r--r--chromium/cc/metrics/frame_sequence_metrics.h3
-rw-r--r--chromium/cc/paint/BUILD.gn5
-rw-r--r--chromium/cc/paint/discardable_image_map.cc18
-rw-r--r--chromium/cc/paint/discardable_image_map_unittest.cc10
-rw-r--r--chromium/cc/paint/display_item_list.cc69
-rw-r--r--chromium/cc/paint/display_item_list.h31
-rw-r--r--chromium/cc/paint/display_item_list_unittest.cc4
-rw-r--r--chromium/cc/paint/filter_operation.cc91
-rw-r--r--chromium/cc/paint/filter_operation.h28
-rw-r--r--chromium/cc/paint/filter_operations.cc18
-rw-r--r--chromium/cc/paint/filter_operations_unittest.cc48
-rw-r--r--chromium/cc/paint/image_transfer_cache_entry.cc83
-rw-r--r--chromium/cc/paint/oop_pixeltest.cc97
-rw-r--r--chromium/cc/paint/paint_filter.cc303
-rw-r--r--chromium/cc/paint/paint_filter.h38
-rw-r--r--chromium/cc/paint/paint_filter_unittest.cc5
-rw-r--r--chromium/cc/paint/paint_flags.cc3
-rw-r--r--chromium/cc/paint/paint_image.h16
-rw-r--r--chromium/cc/paint/paint_op.cc2864
-rw-r--r--chromium/cc/paint/paint_op.h1055
-rw-r--r--chromium/cc/paint/paint_op_buffer.cc3126
-rw-r--r--chromium/cc/paint/paint_op_buffer.h1298
-rw-r--r--chromium/cc/paint/paint_op_buffer_fuzzer.cc8
-rw-r--r--chromium/cc/paint/paint_op_buffer_iterator.cc136
-rw-r--r--chromium/cc/paint/paint_op_buffer_iterator.h218
-rw-r--r--chromium/cc/paint/paint_op_buffer_serializer.cc49
-rw-r--r--chromium/cc/paint/paint_op_buffer_serializer.h12
-rw-r--r--chromium/cc/paint/paint_op_buffer_unittest.cc679
-rw-r--r--chromium/cc/paint/paint_op_perftest.cc4
-rw-r--r--chromium/cc/paint/paint_op_reader.cc66
-rw-r--r--chromium/cc/paint/paint_op_reader.h6
-rw-r--r--chromium/cc/paint/paint_op_writer.cc52
-rw-r--r--chromium/cc/paint/paint_op_writer.h4
-rw-r--r--chromium/cc/paint/paint_record.cc22
-rw-r--r--chromium/cc/paint/paint_record.h14
-rw-r--r--chromium/cc/paint/paint_recorder.cc62
-rw-r--r--chromium/cc/paint/paint_recorder.h57
-rw-r--r--chromium/cc/paint/paint_shader.cc86
-rw-r--r--chromium/cc/paint/paint_shader.h15
-rw-r--r--chromium/cc/paint/paint_shader_unittest.cc2
-rw-r--r--chromium/cc/paint/record_paint_canvas.cc292
-rw-r--r--chromium/cc/paint/record_paint_canvas.h129
-rw-r--r--chromium/cc/paint/render_surface_filters.cc9
-rw-r--r--chromium/cc/paint/scoped_raster_flags_unittest.cc2
-rw-r--r--chromium/cc/paint/skia_paint_canvas_unittest.cc2
-rw-r--r--chromium/cc/paint/skottie_mru_resource_provider.cc20
-rw-r--r--chromium/cc/paint/skottie_mru_resource_provider_unittest.cc15
-rw-r--r--chromium/cc/paint/skottie_text_property_value.cc2
-rw-r--r--chromium/cc/paint/solid_color_analyzer.cc3
-rw-r--r--chromium/cc/paint/solid_color_analyzer_unittest.cc166
-rw-r--r--chromium/cc/paint/target_color_params.h15
-rw-r--r--chromium/cc/paint/transfer_cache_fuzzer.cc2
-rw-r--r--chromium/cc/paint/transfer_cache_unittest.cc4
-rw-r--r--chromium/cc/raster/gpu_raster_buffer_provider.cc6
-rw-r--r--chromium/cc/raster/raster_buffer_provider.cc2
-rw-r--r--chromium/cc/raster/raster_buffer_provider_perftest.cc2
-rw-r--r--chromium/cc/raster/raster_buffer_provider_unittest.cc16
-rw-r--r--chromium/cc/raster/scoped_gpu_raster_unittest.cc5
-rw-r--r--chromium/cc/raster/staging_buffer_pool.cc5
-rw-r--r--chromium/cc/raster/staging_buffer_pool_unittest.cc8
-rw-r--r--chromium/cc/raster/task.h5
-rw-r--r--chromium/cc/raster/task_graph_runner.h1
-rw-r--r--chromium/cc/raster/task_graph_work_queue.cc8
-rw-r--r--chromium/cc/resources/resource_pool.cc34
-rw-r--r--chromium/cc/resources/resource_pool.h7
-rw-r--r--chromium/cc/resources/resource_pool_unittest.cc12
-rw-r--r--chromium/cc/resources/scoped_ui_resource.h1
-rw-r--r--chromium/cc/resources/ui_resource_bitmap.h1
-rw-r--r--chromium/cc/resources/ui_resource_client.h1
-rw-r--r--chromium/cc/resources/ui_resource_manager.cc2
-rw-r--r--chromium/cc/resources/ui_resource_manager.h3
-rw-r--r--chromium/cc/resources/ui_resource_request.h1
-rw-r--r--chromium/cc/scheduler/scheduler.cc55
-rw-r--r--chromium/cc/scheduler/scheduler.h7
-rw-r--r--chromium/cc/scheduler/scheduler_settings.h1
-rw-r--r--chromium/cc/scheduler/scheduler_state_machine.h7
-rw-r--r--chromium/cc/tiles/checker_image_tracker_unittest.cc6
-rw-r--r--chromium/cc/tiles/gpu_image_decode_cache.cc149
-rw-r--r--chromium/cc/tiles/gpu_image_decode_cache.h31
-rw-r--r--chromium/cc/tiles/gpu_image_decode_cache_perftest.cc2
-rw-r--r--chromium/cc/tiles/gpu_image_decode_cache_unittest.cc846
-rw-r--r--chromium/cc/tiles/image_controller.cc42
-rw-r--r--chromium/cc/tiles/image_controller.h5
-rw-r--r--chromium/cc/tiles/image_controller_unittest.cc12
-rw-r--r--chromium/cc/tiles/image_decode_cache.cc11
-rw-r--r--chromium/cc/tiles/image_decode_cache.h50
-rw-r--r--chromium/cc/tiles/picture_layer_tiling_set.cc6
-rw-r--r--chromium/cc/tiles/picture_layer_tiling_set_unittest.cc2
-rw-r--r--chromium/cc/tiles/raster_tile_priority_queue_all.cc91
-rw-r--r--chromium/cc/tiles/raster_tile_priority_queue_all.h2
-rw-r--r--chromium/cc/tiles/software_image_decode_cache.cc28
-rw-r--r--chromium/cc/tiles/software_image_decode_cache.h13
-rw-r--r--chromium/cc/tiles/software_image_decode_cache_unittest.cc625
-rw-r--r--chromium/cc/tiles/software_image_decode_cache_unittest_combinations.cc13
-rw-r--r--chromium/cc/tiles/tile_manager_unittest.cc147
-rw-r--r--chromium/cc/trees/commit_state.h20
-rw-r--r--chromium/cc/trees/de_jelly_state.cc187
-rw-r--r--chromium/cc/trees/de_jelly_state.h52
-rw-r--r--chromium/cc/trees/draw_properties_unittest.cc64
-rw-r--r--chromium/cc/trees/draw_property_utils.cc67
-rw-r--r--chromium/cc/trees/effect_node.cc4
-rw-r--r--chromium/cc/trees/effect_node.h12
-rw-r--r--chromium/cc/trees/image_animation_controller_unittest.cc7
-rw-r--r--chromium/cc/trees/latency_info_swap_promise.cc6
-rw-r--r--chromium/cc/trees/latency_info_swap_promise.h4
-rw-r--r--chromium/cc/trees/layer_tree_frame_sink.cc2
-rw-r--r--chromium/cc/trees/layer_tree_frame_sink_client.h1
-rw-r--r--chromium/cc/trees/layer_tree_host.cc56
-rw-r--r--chromium/cc/trees/layer_tree_host.h32
-rw-r--r--chromium/cc/trees/layer_tree_host_client.h8
-rw-r--r--chromium/cc/trees/layer_tree_host_impl.cc326
-rw-r--r--chromium/cc/trees/layer_tree_host_impl.h36
-rw-r--r--chromium/cc/trees/layer_tree_host_impl_unittest.cc204
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_filters.cc9
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc12
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest.cc148
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_animation.cc9
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_context.cc3
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc7
-rw-r--r--chromium/cc/trees/layer_tree_impl.cc84
-rw-r--r--chromium/cc/trees/layer_tree_impl.h37
-rw-r--r--chromium/cc/trees/layer_tree_impl_unittest.cc10
-rw-r--r--chromium/cc/trees/layer_tree_settings.h10
-rw-r--r--chromium/cc/trees/occlusion.cc2
-rw-r--r--chromium/cc/trees/occlusion_tracker.cc17
-rw-r--r--chromium/cc/trees/paint_holding_commit_trigger.cc4
-rw-r--r--chromium/cc/trees/paint_holding_commit_trigger.h10
-rw-r--r--chromium/cc/trees/paint_holding_reason.h2
-rw-r--r--chromium/cc/trees/presentation_time_callback_buffer.cc68
-rw-r--r--chromium/cc/trees/presentation_time_callback_buffer.h90
-rw-r--r--chromium/cc/trees/presentation_time_callback_buffer_unittest.cc314
-rw-r--r--chromium/cc/trees/property_tree.cc49
-rw-r--r--chromium/cc/trees/property_tree.h7
-rw-r--r--chromium/cc/trees/property_tree_builder.cc4
-rw-r--r--chromium/cc/trees/property_tree_builder_unittest.cc2
-rw-r--r--chromium/cc/trees/property_tree_unittest.cc6
-rw-r--r--chromium/cc/trees/proxy.h1
-rw-r--r--chromium/cc/trees/proxy_impl.cc33
-rw-r--r--chromium/cc/trees/proxy_impl.h7
-rw-r--r--chromium/cc/trees/proxy_main.cc44
-rw-r--r--chromium/cc/trees/proxy_main.h8
-rw-r--r--chromium/cc/trees/raster_context_provider_wrapper.cc36
-rw-r--r--chromium/cc/trees/raster_context_provider_wrapper.h2
-rw-r--r--chromium/cc/trees/render_frame_metadata_observer.h2
-rw-r--r--chromium/cc/trees/single_thread_proxy.cc37
-rw-r--r--chromium/cc/trees/single_thread_proxy.h2
-rw-r--r--chromium/cc/trees/swap_promise.h4
-rw-r--r--chromium/cc/trees/swap_promise_manager.cc4
-rw-r--r--chromium/cc/trees/swap_promise_manager_unittest.cc4
-rw-r--r--chromium/cc/trees/tree_synchronizer.cc1
-rw-r--r--chromium/cc/trees/tree_synchronizer_unittest.cc7
-rw-r--r--chromium/cc/trees/viewport_property_ids.h1
-rw-r--r--chromium/cc/view_transition/README.md (renamed from chromium/cc/document_transition/README.md)2
-rw-r--r--chromium/cc/view_transition/view_transition_request.cc (renamed from chromium/cc/document_transition/document_transition_request.cc)68
-rw-r--r--chromium/cc/view_transition/view_transition_request.h (renamed from chromium/cc/document_transition/document_transition_request.h)43
-rw-r--r--chromium/cc/view_transition/view_transition_request_unittest.cc (renamed from chromium/cc/document_transition/document_transition_request_unittest.cc)16
-rw-r--r--chromium/cc/view_transition/view_transition_shared_element_id.cc51
-rw-r--r--chromium/cc/view_transition/view_transition_shared_element_id.h (renamed from chromium/cc/document_transition/document_transition_shared_element_id.h)30
223 files changed, 9445 insertions, 8332 deletions
diff --git a/chromium/cc/BUILD.gn b/chromium/cc/BUILD.gn
index bc0b076cbc5..30e89fd178b 100644
--- a/chromium/cc/BUILD.gn
+++ b/chromium/cc/BUILD.gn
@@ -33,10 +33,6 @@ 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",
- "document_transition/document_transition_shared_element_id.cc",
- "document_transition/document_transition_shared_element_id.h",
"input/actively_scrolling_type.h",
"input/browser_controls_offset_manager.cc",
"input/browser_controls_offset_manager.h",
@@ -81,10 +77,6 @@ cc_component("cc") {
"layers/content_layer_client.h",
"layers/deadline_policy.cc",
"layers/deadline_policy.h",
- "layers/document_transition_content_layer.cc",
- "layers/document_transition_content_layer.h",
- "layers/document_transition_content_layer_impl.cc",
- "layers/document_transition_content_layer_impl.h",
"layers/draw_mode.h",
"layers/draw_properties.cc",
"layers/draw_properties.h",
@@ -163,6 +155,10 @@ cc_component("cc") {
"layers/video_layer.h",
"layers/video_layer_impl.cc",
"layers/video_layer_impl.h",
+ "layers/view_transition_content_layer.cc",
+ "layers/view_transition_content_layer.h",
+ "layers/view_transition_content_layer_impl.cc",
+ "layers/view_transition_content_layer_impl.h",
"layers/viewport.cc",
"layers/viewport.h",
"metrics/average_lag_tracker.cc",
@@ -354,8 +350,6 @@ cc_component("cc") {
"trees/compositor_mode.h",
"trees/damage_tracker.cc",
"trees/damage_tracker.h",
- "trees/de_jelly_state.cc",
- "trees/de_jelly_state.h",
"trees/debug_rect_history.cc",
"trees/debug_rect_history.h",
"trees/draw_property_utils.cc",
@@ -443,6 +437,10 @@ cc_component("cc") {
"trees/viewport_layers.cc",
"trees/viewport_layers.h",
"trees/viewport_property_ids.h",
+ "view_transition/view_transition_request.cc",
+ "view_transition/view_transition_request.h",
+ "view_transition/view_transition_shared_element_id.cc",
+ "view_transition/view_transition_shared_element_id.h",
]
public_deps = [
@@ -566,6 +564,7 @@ cc_test_static_library("test_support") {
"test/mock_layer_tree_mutator.h",
"test/mock_occlusion_tracker.h",
"test/paint_op_helper.h",
+ "test/paint_op_matchers.h",
"test/pixel_comparator.cc",
"test/pixel_comparator.h",
"test/pixel_test.cc",
@@ -676,7 +675,6 @@ cc_test("cc_unittests") {
sources = [
"base/delayed_unique_notifier_unittest.cc",
- "base/float_quad_unittest.cc",
"base/histograms_unittest.cc",
"base/index_rect_unittest.cc",
"base/list_container_unittest.cc",
@@ -690,7 +688,6 @@ 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",
@@ -825,6 +822,7 @@ cc_test("cc_unittests") {
"trees/throttle_decider_unittest.cc",
"trees/tree_synchronizer_unittest.cc",
"trees/ukm_manager_unittest.cc",
+ "view_transition/view_transition_request_unittest.cc",
# Animation test files.
"animation/animation_host_unittest.cc",
diff --git a/chromium/cc/DEPS b/chromium/cc/DEPS
index ae56e384462..d823169cce5 100644
--- a/chromium/cc/DEPS
+++ b/chromium/cc/DEPS
@@ -38,7 +38,6 @@ include_rules = [
"+third_party/skia/include/private/chromium/SkChromeRemoteGlyphCache.h",
"+third_party/skia/modules/skottie/include",
"+third_party/skia/modules/skresources/include",
- "+third_party/skia/src/effects/imagefilters/SkRuntimeImageFilter.h",
"+third_party/perfetto/protos/perfetto/trace/track_event",
"+ui/base",
"+ui/events/types",
diff --git a/chromium/cc/animation/README.md b/chromium/cc/animation/README.md
index 8b719218976..4c3328ef0fb 100644
--- a/chromium/cc/animation/README.md
+++ b/chromium/cc/animation/README.md
@@ -175,37 +175,25 @@ The lifetime of a newly started cc::Animation is roughly the following:
cc::Animation via [blink::Animation::CreateCompositorAnimation][] (attaching
the animation to the cc::AnimationTimeline resulting in it being later pushed).
The KeyframeEffects are constructed via [blink::Animation::StartAnimationOnCompositor][].
-1. [AnimationHost::RegisterKeyframeEffectForElement][] creates a
+1. [cc::AnimationHost::RegisterAnimationForElement][] creates a
cc::ElementAnimations for the target `element_id` if one does not already
exist. This ElementAnimations instance is shared by all animations with
- the same target and tracks the existence of the target.
-1. During the commit, [cc::ElementAnimations::ElementRegistered][] is called on the
- main thread's AnimationHost either:
- - Before BlinkGenPropertyTrees, when a layer with the target `element_id` is
- registered.
- - After BlinkGenPropertyTrees, after a property tree node with the target
- `element_id` is created on the main thread LayerTreeHost's `property_trees_`.
- This begins ticking the attached KeyframeEffects and tracks that the element
- exists in the active layer / property tree.
-1. [cc::LayerTreeHost::FinishCommitOnImplThread][] calls
- [cc::AnimationHost::PushPropertiesTo][] which results in
+ the same target.
+1. During the commit, [cc::LayerTreeHostImpl::FinishCommit][] calls
+ [cc::LayerTreeImpl::PullPropertiesFrom][] which results in
[cc::AnimationTimeline::PushAttachedAnimationsToImplThread][] creating a
cc::Animation on the compositor thread's AnimationTimeline for each animation
missing from the compositor thread.
1. [cc::Animation::PushPropertiesTo][] is called on every animation on the timeline.
When the `element_id` is pushed by [cc::KeyframeEffect::PushPropertiesTo][]
- [cc::Animation::AttachElementForKeyframeEffect][] creates a compositor side
- cc::ElementAnimations instance to track the existence of the element on the
- compositor. Since animations are pushed after the layer and property trees,
+ [cc::AnimationHost::RegisterAnimationForElement][] creates a compositor side
+ cc::ElementAnimations instance. Since animations are pushed after the layer and property trees,
the element should already exist on the pending tree. This will result in the
animation being added to the ticking animations list.
1. Now the animation is ticking, meaning that [cc::Animation::Tick][] will be called
every frame and update the pending property tree nodes.
1. When the pending tree is activated,
- [cc::AnimationHost::ActivateAnimations][] updates the keyframe effects and
- [cc::ElementAnimations::ElementRegistered][]
- is called for the newly added element id on the active tree, setting
- `has_element_in_active_list_`.
+ [cc::AnimationHost::ActivateAnimations][] updates the keyframe effects.
1. Subsequent animation ticks will now update the property nodes on the active
tree.
@@ -216,17 +204,15 @@ The lifetime of a newly started cc::Animation is roughly the following:
[blink::Animation::PreCommit]: https://cs.chromium.org/search?q=function:blink::PendingAnimations::Update+%5C-%5C>PreCommit%5C(&g=0&l=57
[blink::Animation::CreateCompositorAnimation]: https://cs.chromium.org/search?q=function:blink::Animation::CreateCompositorAnimation+%5E%5B+%5D*AttachCompositorTimeline
[blink::Animation::StartAnimationOnCompositor]: https://cs.chromium.org/search?q=function:blink::Animation::StartAnimationOnCompositor+%5C-%5C>StartAnimationOnCompositor
-[AnimationHost::RegisterKeyframeEffectForElement]: https://cs.chromium.org/search?q=function:cc::AnimationHost::RegisterKeyframeEffectForElement+ElementAnimations::Create
-[cc::ElementAnimations::ElementRegistered]: https://cs.chromium.org/search?q=function:cc::ElementAnimations::ElementRegistered+%5C!has_element_in_any_list
-[cc::LayerTreeHost::FinishCommitOnImplThread]: https://cs.chromium.org/search?q=cc::LayerTreeHost::FinishCommitOnImplThread+file:%5C.cc
-[cc::AnimationHost::PushPropertiesTo]: https://cs.chromium.org/search/?q=function:cc::LayerTreeHost::FinishCommitOnImplThread+%5C-%5C>PushPropertiesTo
+[cc::AnimationHost::RegisterAnimationForElement]: https://cs.chromium.org/search?q=function:cc::AnimationHost::RegisterAnimationForElement+ElementAnimations::Create
+[cc::LayerTreeHostImpl::FinishCommit]: https://cs.chromium.org/search?q=cc::LayerTreeHostImpl::FinishCommit+file:%5C.cc
+[cc::LayerTreeImpl::PullPropertiesFrom]: https://cs.chromium.org/search/?q=function:cc::LayerTreeHostImpl::FinishCommit+%5C-%5C>PullPropertiesFrom
[cc::AnimationTimeline::PushAttachedAnimationsToImplThread]: https://cs.chromium.org/search?q=function:cc::AnimationTimeline::PushAttachedAnimationsToImplThread+animation%5C-%5C>CreateImplInstance
[cc::Animation::PushPropertiesTo]: https://cs.chromium.org/search?q=cc::Animation::PushPropertiesTo+file:%5C.cc
[cc::KeyframeEffect::PushPropertiesTo]: https://cs.chromium.org/search?q=cc::KeyframeEffect::PushPropertiesTo+file:%5C.cc
-[cc::Animation::AttachElementForKeyframeEffect]: https://cs.chromium.org/search?q=cc::Animation::AttachElementForKeyframeEffect+file:%5C.cc
+[cc::AnimationHost::RegisterAnimationForElement]: https://cs.chromium.org/search?q=cc::AnimationHost::RegisterAnimationForElement+file:%5C.cc
[cc::Animation::Tick]: https://cs.chromium.org/search?q=cc::Animation::Tick+file:%5C.cc
-[cc::AnimationHost::ActivateAnimations]: https://cs.chromium.org/search?q=cc::AnimationHost::ActivateAnimations+ActivateKeyframeEffects
-[cc::ElementAnimations::ElementRegistered]: https://cs.chromium.org/search?q=cc::ElementAnimations::ElementRegistered+file:%5C.cc
+[cc::AnimationHost::ActivateAnimations]: https://cs.chromium.org/search?q=cc::AnimationHost::ActivateAnimations+ActivateKeyframeModels
[KeyframeEffect]: https://cs.chromium.org/chromium/src/cc/animation/keyframe_effect.h
[PropertyToElementIdMap]: https://cs.chromium.org/chromium/src/cc/trees/target_property.h?type=cs&g=0&l=42
diff --git a/chromium/cc/animation/animation_host_perftest.cc b/chromium/cc/animation/animation_host_perftest.cc
index 67055d193f7..efb8a96b4cb 100644
--- a/chromium/cc/animation/animation_host_perftest.cc
+++ b/chromium/cc/animation/animation_host_perftest.cc
@@ -5,7 +5,7 @@
#include "base/memory/raw_ptr.h"
#include "cc/animation/animation_host.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/task/single_thread_task_runner.h"
#include "base/timer/lap_timer.h"
#include "cc/animation/animation.h"
#include "cc/animation/animation_id_provider.h"
@@ -36,7 +36,8 @@ class AnimationHostPerfTest : public testing::Test {
layer_tree_host_ = FakeLayerTreeHost::Create(
&fake_client_, &task_graph_runner_, animation_host_.get(), settings);
layer_tree_host_->InitializeSingleThreaded(
- &single_thread_client_, base::ThreadTaskRunnerHandle::Get());
+ &single_thread_client_,
+ base::SingleThreadTaskRunner::GetCurrentDefault());
root_layer_ = Layer::Create();
layer_tree_host_->SetRootLayer(root_layer_);
diff --git a/chromium/cc/animation/element_animations_unittest.cc b/chromium/cc/animation/element_animations_unittest.cc
index 246445c77b3..2935fe49222 100644
--- a/chromium/cc/animation/element_animations_unittest.cc
+++ b/chromium/cc/animation/element_animations_unittest.cc
@@ -771,10 +771,9 @@ TEST_F(ElementAnimationsTest, TrivialTransition) {
auto events = CreateEventsForTesting();
- std::unique_ptr<KeyframeModel> to_add(
- CreateKeyframeModel(std::unique_ptr<gfx::AnimationCurve>(
- new FakeFloatTransition(1.0, 0.f, 1.f)),
- 1, TargetProperty::OPACITY));
+ std::unique_ptr<KeyframeModel> to_add =
+ CreateKeyframeModel(std::make_unique<FakeFloatTransition>(1.0, 0.f, 1.f),
+ 1, TargetProperty::OPACITY);
int keyframe_model_id = to_add->id();
EXPECT_FALSE(
@@ -1355,10 +1354,9 @@ TEST_F(ElementAnimationsTest,
auto events = CreateEventsForTesting();
- std::unique_ptr<KeyframeModel> to_add(
- CreateKeyframeModel(std::unique_ptr<gfx::AnimationCurve>(
- new FakeFloatTransition(1.0, 0.f, 1.f)),
- 1, TargetProperty::OPACITY));
+ std::unique_ptr<KeyframeModel> to_add =
+ CreateKeyframeModel(std::make_unique<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();
@@ -1400,14 +1398,10 @@ TEST_F(ElementAnimationsTest, TrivialQueuing) {
int animation1_id = 1;
int animation2_id = 2;
animation_->AddKeyframeModel(KeyframeModel::Create(
- std::unique_ptr<gfx::AnimationCurve>(
- new FakeFloatTransition(1.0, 0.f, 1.f)),
- animation1_id, 1,
+ std::make_unique<FakeFloatTransition>(1.0, 0.f, 1.f), animation1_id, 1,
KeyframeModel::TargetPropertyId(TargetProperty::OPACITY)));
animation_->AddKeyframeModel(KeyframeModel::Create(
- std::unique_ptr<gfx::AnimationCurve>(
- new FakeFloatTransition(1.0, 1.f, 0.5f)),
- animation2_id, 2,
+ std::make_unique<FakeFloatTransition>(1.0, 1.f, 0.5f), animation2_id, 2,
KeyframeModel::TargetPropertyId(TargetProperty::OPACITY)));
animation_->Tick(kInitialTickTime);
@@ -1462,18 +1456,16 @@ TEST_F(ElementAnimationsTest, Interrupt) {
auto events = CreateEventsForTesting();
animation_->AddKeyframeModel(
- CreateKeyframeModel(std::unique_ptr<gfx::AnimationCurve>(
- new FakeFloatTransition(1.0, 0.f, 1.f)),
+ CreateKeyframeModel(std::make_unique<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<gfx::AnimationCurve>(
- new FakeFloatTransition(1.0, 1.f, 0.5f)),
- 2, TargetProperty::OPACITY));
+ std::unique_ptr<KeyframeModel> to_add =
+ CreateKeyframeModel(std::make_unique<FakeFloatTransition>(1.0, 1.f, 0.5f),
+ 2, TargetProperty::OPACITY);
animation_->AbortKeyframeModelsWithProperty(TargetProperty::OPACITY, false);
animation_->AddKeyframeModel(std::move(to_add));
@@ -1497,15 +1489,14 @@ TEST_F(ElementAnimationsTest, ScheduleTogetherWhenAPropertyIsBlocked) {
auto events = CreateEventsForTesting();
- animation_->AddKeyframeModel(CreateKeyframeModel(
- std::unique_ptr<gfx::AnimationCurve>(new FakeTransformTransition(1)), 1,
- TargetProperty::TRANSFORM));
- animation_->AddKeyframeModel(CreateKeyframeModel(
- std::unique_ptr<gfx::AnimationCurve>(new FakeTransformTransition(1)), 2,
- TargetProperty::TRANSFORM));
animation_->AddKeyframeModel(
- CreateKeyframeModel(std::unique_ptr<gfx::AnimationCurve>(
- new FakeFloatTransition(1.0, 0.f, 1.f)),
+ CreateKeyframeModel(std::make_unique<FakeTransformTransition>(1), 1,
+ TargetProperty::TRANSFORM));
+ animation_->AddKeyframeModel(
+ CreateKeyframeModel(std::make_unique<FakeTransformTransition>(1), 2,
+ TargetProperty::TRANSFORM));
+ animation_->AddKeyframeModel(
+ CreateKeyframeModel(std::make_unique<FakeFloatTransition>(1.0, 0.f, 1.f),
2, TargetProperty::OPACITY));
animation_->Tick(kInitialTickTime);
@@ -1533,16 +1524,14 @@ TEST_F(ElementAnimationsTest, ScheduleTogetherWithAnAnimWaiting) {
auto events = CreateEventsForTesting();
- animation_->AddKeyframeModel(CreateKeyframeModel(
- std::unique_ptr<gfx::AnimationCurve>(new FakeTransformTransition(2)), 1,
- TargetProperty::TRANSFORM));
animation_->AddKeyframeModel(
- CreateKeyframeModel(std::unique_ptr<gfx::AnimationCurve>(
- new FakeFloatTransition(1.0, 0.f, 1.f)),
+ CreateKeyframeModel(std::make_unique<FakeTransformTransition>(2), 1,
+ TargetProperty::TRANSFORM));
+ animation_->AddKeyframeModel(
+ CreateKeyframeModel(std::make_unique<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)),
+ CreateKeyframeModel(std::make_unique<FakeFloatTransition>(1.0, 1.f, 0.5f),
2, TargetProperty::OPACITY));
// Animations with id 1 should both start now.
@@ -1574,10 +1563,9 @@ TEST_F(ElementAnimationsTest, TrivialLooping) {
auto events = CreateEventsForTesting();
- std::unique_ptr<KeyframeModel> to_add(
- CreateKeyframeModel(std::unique_ptr<gfx::AnimationCurve>(
- new FakeFloatTransition(1.0, 0.f, 1.f)),
- 1, TargetProperty::OPACITY));
+ std::unique_ptr<KeyframeModel> to_add =
+ CreateKeyframeModel(std::make_unique<FakeFloatTransition>(1.0, 0.f, 1.f),
+ 1, TargetProperty::OPACITY);
to_add->set_iterations(3);
animation_->AddKeyframeModel(std::move(to_add));
@@ -1619,10 +1607,9 @@ TEST_F(ElementAnimationsTest, InfiniteLooping) {
auto events = CreateEventsForTesting();
- std::unique_ptr<KeyframeModel> to_add(
- CreateKeyframeModel(std::unique_ptr<gfx::AnimationCurve>(
- new FakeFloatTransition(1.0, 0.f, 1.f)),
- 1, TargetProperty::OPACITY));
+ std::unique_ptr<KeyframeModel> to_add =
+ CreateKeyframeModel(std::make_unique<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));
@@ -1664,8 +1651,7 @@ TEST_F(ElementAnimationsTest, PauseResume) {
auto events = CreateEventsForTesting();
animation_->AddKeyframeModel(
- CreateKeyframeModel(std::unique_ptr<gfx::AnimationCurve>(
- new FakeFloatTransition(1.0, 0.f, 1.f)),
+ CreateKeyframeModel(std::make_unique<FakeFloatTransition>(1.0, 0.f, 1.f),
1, TargetProperty::OPACITY));
animation_->Tick(kInitialTickTime);
@@ -1710,17 +1696,14 @@ TEST_F(ElementAnimationsTest, AbortAGroupedAnimation) {
const int keyframe_model_id = 2;
animation_->AddKeyframeModel(KeyframeModel::Create(
- std::unique_ptr<gfx::AnimationCurve>(new FakeTransformTransition(1)), 1,
- 1, KeyframeModel::TargetPropertyId(TargetProperty::TRANSFORM)));
+ std::make_unique<FakeTransformTransition>(1), 1, 1,
+ KeyframeModel::TargetPropertyId(TargetProperty::TRANSFORM)));
animation_->AddKeyframeModel(KeyframeModel::Create(
- std::unique_ptr<gfx::AnimationCurve>(
- new FakeFloatTransition(2.0, 0.f, 1.f)),
- keyframe_model_id, 1,
- KeyframeModel::TargetPropertyId(TargetProperty::OPACITY)));
+ std::make_unique<FakeFloatTransition>(2.0, 0.f, 1.f), keyframe_model_id,
+ 1, KeyframeModel::TargetPropertyId(TargetProperty::OPACITY)));
animation_->AddKeyframeModel(KeyframeModel::Create(
- std::unique_ptr<gfx::AnimationCurve>(
- new FakeFloatTransition(1.0, 1.f, 0.75f)),
- 3, 2, KeyframeModel::TargetPropertyId(TargetProperty::OPACITY)));
+ std::make_unique<FakeFloatTransition>(1.0, 1.f, 0.75f), 3, 2,
+ KeyframeModel::TargetPropertyId(TargetProperty::OPACITY)));
animation_->Tick(kInitialTickTime);
animation_->UpdateState(true, events.get());
@@ -1754,10 +1737,9 @@ TEST_F(ElementAnimationsTest, PushUpdatesWhenSynchronizedStartTimeNeeded) {
auto events = CreateEventsForTesting();
- std::unique_ptr<KeyframeModel> to_add(
- CreateKeyframeModel(std::unique_ptr<gfx::AnimationCurve>(
- new FakeFloatTransition(2.0, 0.f, 1.f)),
- 0, TargetProperty::OPACITY));
+ std::unique_ptr<KeyframeModel> to_add =
+ CreateKeyframeModel(std::make_unique<FakeFloatTransition>(2.0, 0.f, 1.f),
+ 0, TargetProperty::OPACITY);
to_add->set_needs_synchronized_start_time(true);
animation_->AddKeyframeModel(std::move(to_add));
@@ -1787,19 +1769,18 @@ TEST_F(ElementAnimationsTest, SkipUpdateState) {
auto events = CreateEventsForTesting();
- std::unique_ptr<KeyframeModel> first_keyframe_model(CreateKeyframeModel(
- std::unique_ptr<gfx::AnimationCurve>(new FakeTransformTransition(1)), 1,
- TargetProperty::TRANSFORM));
+ std::unique_ptr<KeyframeModel> first_keyframe_model =
+ CreateKeyframeModel(std::make_unique<FakeTransformTransition>(1), 1,
+ TargetProperty::TRANSFORM);
first_keyframe_model->set_is_controlling_instance_for_test(true);
animation_->AddKeyframeModel(std::move(first_keyframe_model));
animation_->Tick(kInitialTickTime);
animation_->UpdateState(true, events.get());
- std::unique_ptr<KeyframeModel> second_keyframe_model(
- CreateKeyframeModel(std::unique_ptr<gfx::AnimationCurve>(
- new FakeFloatTransition(1.0, 0.f, 1.f)),
- 2, TargetProperty::OPACITY));
+ std::unique_ptr<KeyframeModel> second_keyframe_model =
+ CreateKeyframeModel(std::make_unique<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));
@@ -1836,8 +1817,7 @@ TEST_F(ElementAnimationsTest, InactiveObserverGetsTicked) {
const int id = 1;
animation_impl_->AddKeyframeModel(
- CreateKeyframeModel(std::unique_ptr<gfx::AnimationCurve>(
- new FakeFloatTransition(1.0, 0.5f, 1.f)),
+ CreateKeyframeModel(std::make_unique<FakeFloatTransition>(1.0, 0.5f, 1.f),
id, TargetProperty::OPACITY));
animation_impl_->GetKeyframeModel(TargetProperty::OPACITY)
->set_affects_active_elements(false);
@@ -1900,22 +1880,20 @@ 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<gfx::AnimationCurve>(new FakeTransformTransition(1.0)), 1,
- 1, KeyframeModel::TargetPropertyId(TargetProperty::TRANSFORM)));
+ std::make_unique<FakeTransformTransition>(1.0), 1, 1,
+ KeyframeModel::TargetPropertyId(TargetProperty::TRANSFORM)));
animation_->AddKeyframeModel(KeyframeModel::Create(
- std::unique_ptr<gfx::AnimationCurve>(
- new FakeFloatTransition(1.0, 0.f, 1.f)),
- 2, 2, KeyframeModel::TargetPropertyId(TargetProperty::OPACITY)));
+ std::make_unique<FakeFloatTransition>(1.0, 0.f, 1.f), 2, 2,
+ KeyframeModel::TargetPropertyId(TargetProperty::OPACITY)));
animation_->AddKeyframeModel(KeyframeModel::Create(
- std::unique_ptr<gfx::AnimationCurve>(new FakeTransformTransition(1.0)), 3,
- 3, KeyframeModel::TargetPropertyId(TargetProperty::TRANSFORM)));
+ std::make_unique<FakeTransformTransition>(1.0), 3, 3,
+ KeyframeModel::TargetPropertyId(TargetProperty::TRANSFORM)));
animation_->AddKeyframeModel(KeyframeModel::Create(
- std::unique_ptr<gfx::AnimationCurve>(new FakeTransformTransition(2.0)), 4,
- 4, KeyframeModel::TargetPropertyId(TargetProperty::TRANSFORM)));
+ std::make_unique<FakeTransformTransition>(2.0), 4, 4,
+ KeyframeModel::TargetPropertyId(TargetProperty::TRANSFORM)));
animation_->AddKeyframeModel(KeyframeModel::Create(
- std::unique_ptr<gfx::AnimationCurve>(
- new FakeFloatTransition(1.0, 0.f, 1.f)),
- 5, 5, KeyframeModel::TargetPropertyId(TargetProperty::OPACITY)));
+ std::make_unique<FakeFloatTransition>(1.0, 0.f, 1.f), 5, 5,
+ KeyframeModel::TargetPropertyId(TargetProperty::OPACITY)));
animation_->Tick(kInitialTickTime);
animation_->UpdateState(true, nullptr);
@@ -2142,16 +2120,15 @@ TEST_F(ElementAnimationsTest, FinishedEventsForGroup) {
const int group_id = 1;
// Add two animations with the same group id but different durations.
- std::unique_ptr<KeyframeModel> first_keyframe_model(KeyframeModel::Create(
- std::unique_ptr<gfx::AnimationCurve>(new FakeTransformTransition(2.0)), 1,
- group_id, KeyframeModel::TargetPropertyId(TargetProperty::TRANSFORM)));
+ std::unique_ptr<KeyframeModel> first_keyframe_model = KeyframeModel::Create(
+ std::make_unique<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<gfx::AnimationCurve>(
- new FakeFloatTransition(1.0, 0.f, 1.f)),
- 2, group_id, KeyframeModel::TargetPropertyId(TargetProperty::OPACITY)));
+ std::unique_ptr<KeyframeModel> second_keyframe_model = KeyframeModel::Create(
+ std::make_unique<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));
@@ -2197,16 +2174,15 @@ TEST_F(ElementAnimationsTest, FinishedAndAbortedEventsForGroup) {
auto events = CreateEventsForTesting();
// Add two animations with the same group id.
- std::unique_ptr<KeyframeModel> first_keyframe_model(CreateKeyframeModel(
- std::unique_ptr<gfx::AnimationCurve>(new FakeTransformTransition(1.0)), 1,
- TargetProperty::TRANSFORM));
+ std::unique_ptr<KeyframeModel> first_keyframe_model =
+ CreateKeyframeModel(std::make_unique<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<gfx::AnimationCurve>(
- new FakeFloatTransition(1.0, 0.f, 1.f)),
- 1, TargetProperty::OPACITY));
+ std::unique_ptr<KeyframeModel> second_keyframe_model =
+ CreateKeyframeModel(std::make_unique<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));
@@ -2245,8 +2221,7 @@ TEST_F(ElementAnimationsTest, MaximumAnimationScaleNotScaled) {
element_id_, ElementListType::ACTIVE));
animation_impl_->AddKeyframeModel(
- CreateKeyframeModel(std::unique_ptr<gfx::AnimationCurve>(
- new FakeFloatTransition(1.0, 0.f, 1.f)),
+ CreateKeyframeModel(std::make_unique<FakeFloatTransition>(1.0, 0.f, 1.f),
1, TargetProperty::OPACITY));
// Opacity animations aren't non-translation transforms.
@@ -3736,10 +3711,9 @@ TEST_F(ElementAnimationsTest, TestIsCurrentlyAnimatingProperty) {
AttachTimelineAnimationLayer();
// Create an animation that initially affects only pending elements.
- std::unique_ptr<KeyframeModel> keyframe_model(
- CreateKeyframeModel(std::unique_ptr<gfx::AnimationCurve>(
- new FakeFloatTransition(1.0, 0.f, 1.f)),
- 1, TargetProperty::OPACITY));
+ std::unique_ptr<KeyframeModel> keyframe_model =
+ CreateKeyframeModel(std::make_unique<FakeFloatTransition>(1.0, 0.f, 1.f),
+ 1, TargetProperty::OPACITY);
keyframe_model->set_affects_active_elements(false);
animation_->AddKeyframeModel(std::move(keyframe_model));
@@ -3807,10 +3781,9 @@ 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<gfx::AnimationCurve>(
- new FakeFloatTransition(1.0, 0.f, 1.f)),
- 1, TargetProperty::OPACITY));
+ std::unique_ptr<KeyframeModel> keyframe_model =
+ CreateKeyframeModel(std::make_unique<FakeFloatTransition>(1.0, 0.f, 1.f),
+ 1, TargetProperty::OPACITY);
keyframe_model->set_fill_mode(KeyframeModel::FillMode::NONE);
keyframe_model->set_time_offset(base::Milliseconds(-2000));
keyframe_model->set_affects_active_elements(false);
@@ -3889,8 +3862,7 @@ 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<gfx::AnimationCurve>(
- new FakeFloatTransition(1.0, 1.f, 0.5f)),
+ CreateKeyframeModel(std::make_unique<FakeFloatTransition>(1.0, 1.f, 0.5f),
1, TargetProperty::OPACITY));
ASSERT_EQ(1u, host_->ticking_animations_for_testing().size());
animation_->keyframe_effect()->RemoveFromTicking();
@@ -3899,8 +3871,7 @@ TEST_F(ElementAnimationsTest, RemoveAndReAddAnimationToTicking) {
// Ensure that adding a new animation will correctly update the ticking
// animations list.
animation_->AddKeyframeModel(
- CreateKeyframeModel(std::unique_ptr<gfx::AnimationCurve>(
- new FakeFloatTransition(1.0, 1.f, 0.5f)),
+ CreateKeyframeModel(std::make_unique<FakeFloatTransition>(1.0, 1.f, 0.5f),
2, TargetProperty::OPACITY));
EXPECT_EQ(1u, host_->ticking_animations_for_testing().size());
}
@@ -3913,12 +3884,11 @@ TEST_F(ElementAnimationsTest, FinishedKeyframeModelsNotCopiedToImpl) {
CreateImplTimelineAndAnimation();
animation_->AddKeyframeModel(KeyframeModel::Create(
- std::unique_ptr<gfx::AnimationCurve>(new FakeTransformTransition(1.0)), 1,
- 1, KeyframeModel::TargetPropertyId(TargetProperty::TRANSFORM)));
+ std::make_unique<FakeTransformTransition>(1.0), 1, 1,
+ KeyframeModel::TargetPropertyId(TargetProperty::TRANSFORM)));
animation_->AddKeyframeModel(KeyframeModel::Create(
- std::unique_ptr<gfx::AnimationCurve>(
- new FakeFloatTransition(2.0, 0.f, 1.f)),
- 2, 2, KeyframeModel::TargetPropertyId(TargetProperty::OPACITY)));
+ std::make_unique<FakeFloatTransition>(2.0, 0.f, 1.f), 2, 2,
+ KeyframeModel::TargetPropertyId(TargetProperty::OPACITY)));
// Finish the first keyframe model.
animation_->Tick(kInitialTickTime);
diff --git a/chromium/cc/animation/scroll_timeline.h b/chromium/cc/animation/scroll_timeline.h
index 21ca2c8a684..5b3c513da9c 100644
--- a/chromium/cc/animation/scroll_timeline.h
+++ b/chromium/cc/animation/scroll_timeline.h
@@ -43,6 +43,10 @@ class CC_ANIMATION_EXPORT ScrollTimeline : public AnimationTimeline {
bool operator==(const ScrollOffsets& other) const {
return start == other.start && end == other.end;
}
+ bool operator!=(const ScrollOffsets& other) const {
+ return !(*this == other);
+ }
+
double start = 0;
double end = 0;
};
diff --git a/chromium/cc/base/devtools_instrumentation.cc b/chromium/cc/base/devtools_instrumentation.cc
index 0f5c4633a4f..9e53639d50d 100644
--- a/chromium/cc/base/devtools_instrumentation.cc
+++ b/chromium/cc/base/devtools_instrumentation.cc
@@ -73,9 +73,6 @@ ScopedImageUploadTask::~ScopedImageUploadTask() {
auto duration = base::TimeTicks::Now() - start_time_;
const char* histogram_name = nullptr;
switch (image_type_) {
- case ImageType::kJxl:
- histogram_name = "Renderer4.ImageUploadTaskDurationUs.Jxl";
- break;
case ImageType::kAvif:
histogram_name = "Renderer4.ImageUploadTaskDurationUs.Avif";
break;
@@ -125,9 +122,6 @@ ScopedImageDecodeTask::~ScopedImageDecodeTask() {
auto duration = base::TimeTicks::Now() - start_time_;
const char* histogram_name = nullptr;
switch (image_type_) {
- case ImageType::kJxl:
- histogram_name = "Renderer4.ImageUploadTaskDurationUs.Jxl";
- break;
case ImageType::kAvif:
histogram_name = "Renderer4.ImageDecodeTaskDurationUs.Avif";
break;
diff --git a/chromium/cc/base/devtools_instrumentation.h b/chromium/cc/base/devtools_instrumentation.h
index aa063634b70..409a9106a45 100644
--- a/chromium/cc/base/devtools_instrumentation.h
+++ b/chromium/cc/base/devtools_instrumentation.h
@@ -72,7 +72,7 @@ class CC_BASE_EXPORT ScopedLayerTask {
class CC_BASE_EXPORT ScopedImageTask {
public:
- enum ImageType { kJxl, kAvif, kBmp, kGif, kIco, kJpeg, kPng, kWebP, kOther };
+ enum ImageType { kAvif, kBmp, kGif, kIco, kJpeg, kPng, kWebP, kOther };
explicit ScopedImageTask(ImageType image_type)
: image_type_(image_type), start_time_(base::TimeTicks::Now()) {}
diff --git a/chromium/cc/base/features.cc b/chromium/cc/base/features.cc
index 188e7077047..93665eef3d1 100644
--- a/chromium/cc/base/features.cc
+++ b/chromium/cc/base/features.cc
@@ -78,7 +78,7 @@ BASE_FEATURE(kSlidingWindowForDroppedFrameCounter,
BASE_FEATURE(kNormalPriorityImageDecoding,
"NormalPriorityImageDecoding",
- base::FEATURE_DISABLED_BY_DEFAULT);
+ base::FEATURE_ENABLED_BY_DEFAULT);
BASE_FEATURE(kSkipCommitsIfNotSynchronizingCompositorState,
"SkipCommitsIfNotSynchronizingCompositorState",
@@ -92,4 +92,16 @@ BASE_FEATURE(kUpdateBrowserControlsWithoutProxy,
"UpdateBrowserControlsWithoutProxy",
base::FEATURE_DISABLED_BY_DEFAULT);
+BASE_FEATURE(kRasterTilePriorityQueue,
+ "RasterTilePriorityQueue",
+ base::FEATURE_DISABLED_BY_DEFAULT);
+
+BASE_FEATURE(kUIEnableSharedImageCacheForGpu,
+ "UIEnableSharedImageCacheForGpu",
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ base::FEATURE_ENABLED_BY_DEFAULT);
+#else
+ base::FEATURE_DISABLED_BY_DEFAULT);
+#endif
+
} // namespace features
diff --git a/chromium/cc/base/features.h b/chromium/cc/base/features.h
index 00a0aac4a5a..e092b3e43db 100644
--- a/chromium/cc/base/features.h
+++ b/chromium/cc/base/features.h
@@ -86,6 +86,17 @@ CC_BASE_EXPORT BASE_DECLARE_FEATURE(kUseDMSAAForTiles);
// compositor thread. Previously this proxied through the renderer main thread.
CC_BASE_EXPORT BASE_DECLARE_FEATURE(kUpdateBrowserControlsWithoutProxy);
+// Fix the SMOOTHNESS_TAKES_PRIORITY queue priorities used in
+// RasterTilePriorityQueueAll::GetNextQueues(). By fixing the bug which fails to
+// schedule raster tasks for Pending SOON tiles, it reduces checkerboarding and
+// improves the rendering.desktop tough_scrolling benchmark.
+CC_BASE_EXPORT BASE_DECLARE_FEATURE(kRasterTilePriorityQueue);
+
+// Enables shared image cache for gpu used by CC instances instantiated for UI.
+// TODO(https://crbug.com/c/1378251): this shall also be possible to use by
+// renderers.
+CC_BASE_EXPORT BASE_DECLARE_FEATURE(kUIEnableSharedImageCacheForGpu);
+
} // namespace features
#endif // CC_BASE_FEATURES_H_
diff --git a/chromium/cc/base/float_quad_unittest.cc b/chromium/cc/base/float_quad_unittest.cc
deleted file mode 100644
index 313bcc3ae5f..00000000000
--- a/chromium/cc/base/float_quad_unittest.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2011 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/base/math_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/geometry/quad_f.h"
-#include "ui/gfx/geometry/rect_f.h"
-#include "ui/gfx/geometry/transform.h"
-
-namespace cc {
-namespace {
-
-// TODO(danakj) Move this test to ui/gfx/ when we don't need MathUtil::MapQuad.
-TEST(FloatQuadTest, IsRectilinearTest) {
- const int kNumRectilinear = 8;
- gfx::Transform rectilinear_trans[kNumRectilinear];
- rectilinear_trans[1].Rotate(90.f);
- rectilinear_trans[2].Rotate(180.f);
- rectilinear_trans[3].Rotate(270.f);
- rectilinear_trans[4].Skew(0.00000000001f, 0.0f);
- rectilinear_trans[5].Skew(0.0f, 0.00000000001f);
- rectilinear_trans[6].Scale(0.00001f, 0.00001f);
- rectilinear_trans[6].Rotate(180.f);
- rectilinear_trans[7].Scale(100000.f, 100000.f);
- rectilinear_trans[7].Rotate(180.f);
-
- gfx::QuadF original(
- gfx::RectF(0.01010101f, 0.01010101f, 100.01010101f, 100.01010101f));
-
- for (int i = 0; i < kNumRectilinear; ++i) {
- bool clipped = false;
- gfx::QuadF quad =
- MathUtil::MapQuad(rectilinear_trans[i], original, &clipped);
- ASSERT_TRUE(!clipped) << "case " << i;
- EXPECT_TRUE(quad.IsRectilinear()) << "case " << i;
- }
-
- const int kNumNonRectilinear = 10;
- gfx::Transform non_rectilinear_trans[kNumNonRectilinear];
- non_rectilinear_trans[0].Rotate(359.9999f);
- non_rectilinear_trans[1].Rotate(0.0000001f);
- non_rectilinear_trans[2].Rotate(89.9999f);
- non_rectilinear_trans[3].Rotate(90.00001f);
- non_rectilinear_trans[4].Rotate(179.9999f);
- non_rectilinear_trans[5].Rotate(180.00001f);
- non_rectilinear_trans[6].Rotate(269.9999f);
- non_rectilinear_trans[7].Rotate(270.0001f);
- non_rectilinear_trans[8].Skew(0.00001f, 0.0f);
- non_rectilinear_trans[9].Skew(0.0f, 0.00001f);
-
- for (int i = 0; i < kNumNonRectilinear; ++i) {
- bool clipped = false;
- gfx::QuadF quad =
- MathUtil::MapQuad(non_rectilinear_trans[i], original, &clipped);
- ASSERT_TRUE(!clipped) << "case " << i;
- EXPECT_FALSE(quad.IsRectilinear()) << "case " << i;
- }
-}
-
-} // namespace
-} // namespace cc
diff --git a/chromium/cc/base/math_util.cc b/chromium/cc/base/math_util.cc
index e650c6b2744..d011b435718 100644
--- a/chromium/cc/base/math_util.cc
+++ b/chromium/cc/base/math_util.cc
@@ -330,11 +330,9 @@ gfx::RectF MathUtil::ProjectClippedRect(const gfx::Transform& transform,
gfx::QuadF MathUtil::InverseMapQuadToLocalSpace(
const gfx::Transform& device_transform,
const gfx::QuadF& device_quad) {
- gfx::Transform inverse_device_transform(gfx::Transform::kSkipInitialization);
- DCHECK(device_transform.IsInvertible());
DCHECK(device_transform.IsFlat());
- bool did_invert = device_transform.GetInverse(&inverse_device_transform);
- DCHECK(did_invert);
+ gfx::Transform inverse_device_transform =
+ device_transform.GetCheckedInverse();
bool clipped = false;
gfx::QuadF local_quad =
MathUtil::MapQuad(inverse_device_transform, device_quad, &clipped);
@@ -784,21 +782,21 @@ bool MathUtil::FromValue(const base::Value* raw_value, gfx::Rect* out_rect) {
if (!raw_value->is_list())
return false;
- base::Value::ConstListView list_view = raw_value->GetListDeprecated();
+ const base::Value::List& list = raw_value->GetList();
- if (list_view.size() != 4)
+ if (list.size() != 4)
return false;
- for (const auto& val : list_view) {
+ for (const auto& val : list) {
if (!val.is_int()) {
return false;
}
}
- int x = list_view[0].GetInt();
- int y = list_view[1].GetInt();
- int w = list_view[2].GetInt();
- int h = list_view[3].GetInt();
+ int x = list[0].GetInt();
+ int y = list[1].GetInt();
+ int w = list[2].GetInt();
+ int h = list[3].GetInt();
*out_rect = gfx::Rect(x, y, w, h);
return true;
diff --git a/chromium/cc/base/math_util.h b/chromium/cc/base/math_util.h
index 6e4fb25f941..a0ec2432d21 100644
--- a/chromium/cc/base/math_util.h
+++ b/chromium/cc/base/math_util.h
@@ -118,7 +118,7 @@ class CC_BASE_EXPORT MathUtil {
public:
// Returns true if rounded up value does not overflow, false otherwise.
template <typename T>
- static bool VerifyRoundup(T n, T mul) {
+ static constexpr bool VerifyRoundup(T n, T mul) {
return mul && (n <= (std::numeric_limits<T>::max() -
(std::numeric_limits<T>::max() % mul)));
}
@@ -128,7 +128,7 @@ class CC_BASE_EXPORT MathUtil {
// - RoundUp(123, 50) returns 150.
// - RoundUp(-123, 50) returns -100.
template <typename T>
- static T UncheckedRoundUp(T n, T mul) {
+ static constexpr T UncheckedRoundUp(T n, T mul) {
static_assert(std::numeric_limits<T>::is_integer,
"T must be an integer type");
return RoundUpInternal(n, mul);
@@ -137,7 +137,7 @@ class CC_BASE_EXPORT MathUtil {
// Similar to UncheckedRoundUp(), but dies with a CRASH() if rounding up a
// given |n| overflows T.
template <typename T>
- static T CheckedRoundUp(T n, T mul) {
+ static constexpr T CheckedRoundUp(T n, T mul) {
static_assert(std::numeric_limits<T>::is_integer,
"T must be an integer type");
CHECK(VerifyRoundup(n, mul));
@@ -146,7 +146,7 @@ class CC_BASE_EXPORT MathUtil {
// Returns true if rounded down value does not underflow, false otherwise.
template <typename T>
- static bool VerifyRoundDown(T n, T mul) {
+ static constexpr bool VerifyRoundDown(T n, T mul) {
return mul && (n >= (std::numeric_limits<T>::min() -
(std::numeric_limits<T>::min() % mul)));
}
@@ -156,7 +156,7 @@ class CC_BASE_EXPORT MathUtil {
// - RoundDown(123, 50) returns 100.
// - RoundDown(-123, 50) returns -150.
template <typename T>
- static T UncheckedRoundDown(T n, T mul) {
+ static constexpr T UncheckedRoundDown(T n, T mul) {
static_assert(std::numeric_limits<T>::is_integer,
"T must be an integer type");
return RoundDownInternal(n, mul);
@@ -165,7 +165,7 @@ class CC_BASE_EXPORT MathUtil {
// Similar to UncheckedRoundDown(), but dies with a CRASH() if rounding down a
// given |n| underflows T.
template <typename T>
- static T CheckedRoundDown(T n, T mul) {
+ static constexpr T CheckedRoundDown(T n, T mul) {
static_assert(std::numeric_limits<T>::is_integer,
"T must be an integer type");
CHECK(VerifyRoundDown(n, mul));
@@ -173,7 +173,7 @@ class CC_BASE_EXPORT MathUtil {
}
template <typename T>
- static bool IsWithinEpsilon(T a, T b) {
+ static constexpr bool IsWithinEpsilon(T a, T b) {
return std::abs(a - b) < std::numeric_limits<T>::epsilon();
}
@@ -338,12 +338,12 @@ class CC_BASE_EXPORT MathUtil {
private:
template <typename T>
- static T RoundUpInternal(T n, T mul) {
+ static constexpr T RoundUpInternal(T n, T mul) {
return (n > 0) ? ((n + mul - 1) / mul) * mul : (n / mul) * mul;
}
template <typename T>
- static T RoundDownInternal(T n, T mul) {
+ static constexpr T RoundDownInternal(T n, T mul) {
return (n > 0) ? (n / mul) * mul : (n == 0) ? 0
: ((n - mul + 1) / mul) * mul;
}
diff --git a/chromium/cc/base/math_util_unittest.cc b/chromium/cc/base/math_util_unittest.cc
index 8006369bdd0..1a532eadc7b 100644
--- a/chromium/cc/base/math_util_unittest.cc
+++ b/chromium/cc/base/math_util_unittest.cc
@@ -47,11 +47,11 @@ TEST(MathUtilTest, ProjectionOfAlmostPerpendicularPlane) {
// +16331238407143424.0000 +0.0000 -0.0000 +51346917453137000267776.0000
// +0.0000 +0.0000 +0.0000 +1.0000 ]
transform.MakeIdentity();
- transform.set_rc(0, 2, static_cast<SkScalar>(-1));
- transform.set_rc(0, 3, static_cast<SkScalar>(3144132.0));
- transform.set_rc(2, 0, static_cast<SkScalar>(16331238407143424.0));
- transform.set_rc(2, 2, static_cast<SkScalar>(-1e-33));
- transform.set_rc(2, 3, static_cast<SkScalar>(51346917453137000267776.0));
+ transform.set_rc(0, 2, -1);
+ transform.set_rc(0, 3, 3144132.0);
+ transform.set_rc(2, 0, 16331238407143424.0);
+ transform.set_rc(2, 2, -1e-33);
+ transform.set_rc(2, 3, 51346917453137000267776.0);
gfx::RectF rect = gfx::RectF(0, 0, 1, 1);
gfx::RectF projected_rect = MathUtil::ProjectClippedRect(transform, rect);
@@ -329,14 +329,12 @@ TEST(MathUtilTest, MapEnclosingRectWithLargeTransforms) {
gfx::Rect input(1, 2, 100, 200);
gfx::Rect output;
- gfx::Transform large_x_scale;
- large_x_scale.Scale(SkDoubleToScalar(1e37), 1.0);
+ gfx::Transform large_x_scale = gfx::Transform::MakeScale(1e37, 1.0);
gfx::Transform infinite_x_scale;
infinite_x_scale = large_x_scale * large_x_scale;
- gfx::Transform large_y_scale;
- large_y_scale.Scale(1.0, SkDoubleToScalar(1e37));
+ gfx::Transform large_y_scale = gfx::Transform::MakeScale(1.0, 1e37);
gfx::Transform infinite_y_scale;
infinite_y_scale = large_y_scale * large_y_scale;
@@ -378,8 +376,7 @@ TEST(MathUtilTest, MapEnclosingRectIgnoringError) {
gfx::Rect input(0, 0, 1000, 500);
gfx::Rect output;
- gfx::Transform transform;
- transform.Scale(SkDoubleToScalar(scale), SkDoubleToScalar(scale));
+ gfx::Transform transform = gfx::Transform::MakeScale(scale);
output =
MathUtil::MapEnclosingClippedRectIgnoringError(transform, input, 0.f);
EXPECT_EQ(gfx::Rect(0, 0, 2001, 1001), output);
@@ -397,14 +394,12 @@ TEST(MathUtilTest, ProjectEnclosingRectWithLargeTransforms) {
gfx::Rect input(1, 2, 100, 200);
gfx::Rect output;
- gfx::Transform large_x_scale;
- large_x_scale.Scale(SkDoubleToScalar(1e37), 1.0);
+ gfx::Transform large_x_scale = gfx::Transform::MakeScale(1e37, 1.0);
gfx::Transform infinite_x_scale;
infinite_x_scale = large_x_scale * large_x_scale;
- gfx::Transform large_y_scale;
- large_y_scale.Scale(1.0, SkDoubleToScalar(1e37));
+ gfx::Transform large_y_scale = gfx::Transform::MakeScale(1.0, 1e37);
gfx::Transform infinite_y_scale;
infinite_y_scale = large_y_scale * large_y_scale;
@@ -444,6 +439,7 @@ TEST(MathUtilTest, ProjectEnclosingRectWithLargeTransforms) {
}
TEST(MathUtilTest, RoundUp) {
+ static_assert(MathUtil::UncheckedRoundUp(45, 10) == 50);
for (int multiplier = 1; multiplier <= 10; ++multiplier) {
// Try attempts in descending order, so that we can
// determine the correct value before it's needed.
@@ -478,6 +474,7 @@ TEST(MathUtilTest, RoundUpOverflow) {
}
TEST(MathUtilTest, RoundDown) {
+ static_assert(MathUtil::UncheckedRoundDown(45, 10) == 40);
for (int multiplier = 1; multiplier <= 10; ++multiplier) {
// Try attempts in ascending order, so that we can
// determine the correct value before it's needed.
@@ -930,14 +927,14 @@ TEST(MathUtilTest, MapClippedQuadClampWholePlane) {
EXPECT_EQ(clipped_quad[0].x(), 0.0f);
EXPECT_EQ(clipped_quad[0].y(), 0.0f);
- EXPECT_EQ(clipped_quad[0].z(), 750000.0f);
+ EXPECT_LE_LE(750000.0f, clipped_quad[0].z(), 750001.0f);
EXPECT_EQ(clipped_quad[1].x(), 0.0f);
- EXPECT_EQ(clipped_quad[1].y(), 1000000.0f);
+ EXPECT_LE_LE(999999.0f, clipped_quad[1].y(), 1000000.0f);
EXPECT_LE_LE(-250001.0f, clipped_quad[1].z(), -249999.0f);
EXPECT_LE_LE(14100.0f, clipped_quad[2].x(), 14200.0f);
- EXPECT_EQ(clipped_quad[2].y(), 1000000.0f);
+ EXPECT_LE_LE(999999.0f, clipped_quad[2].y(), 1000000.0f);
EXPECT_LE_LE(-250001.0f, clipped_quad[2].z(), -249999.0f);
EXPECT_LE_LE(3500.0f, clipped_quad[3].x(), 3600.0f);
diff --git a/chromium/cc/base/region.cc b/chromium/cc/base/region.cc
index 10251d5f5da..387d588c73a 100644
--- a/chromium/cc/base/region.cc
+++ b/chromium/cc/base/region.cc
@@ -9,7 +9,6 @@
#include "base/no_destructor.h"
#include "base/trace_event/traced_value.h"
-#include "base/values.h"
#include "cc/base/simple_enclosed_region.h"
#include "ui/gfx/geometry/vector2d.h"
@@ -136,17 +135,6 @@ std::string Region::ToString() const {
return result;
}
-std::unique_ptr<base::Value> Region::AsValue() const {
- std::unique_ptr<base::ListValue> result(new base::ListValue());
- for (gfx::Rect rect : *this) {
- result->Append(rect.x());
- result->Append(rect.y());
- result->Append(rect.width());
- result->Append(rect.height());
- }
- return std::move(result);
-}
-
void Region::AsValueInto(base::trace_event::TracedValue* result) const {
for (gfx::Rect rect : *this) {
result->AppendInteger(rect.x());
diff --git a/chromium/cc/base/region.h b/chromium/cc/base/region.h
index 453baf81e61..459cea646b6 100644
--- a/chromium/cc/base/region.h
+++ b/chromium/cc/base/region.h
@@ -16,11 +16,10 @@
class SkPath;
namespace base {
-class Value;
namespace trace_event {
class TracedValue;
}
-}
+} // namespace base
namespace gfx {
class Vector2d;
@@ -76,7 +75,6 @@ class CC_BASE_EXPORT Region {
}
std::string ToString() const;
- std::unique_ptr<base::Value> AsValue() const;
void AsValueInto(base::trace_event::TracedValue* array) const;
// Iterator for iterating through the gfx::Rects contained in this Region.
diff --git a/chromium/cc/base/unique_notifier_unittest.cc b/chromium/cc/base/unique_notifier_unittest.cc
index ee9bcf3597a..72036dbb170 100644
--- a/chromium/cc/base/unique_notifier_unittest.cc
+++ b/chromium/cc/base/unique_notifier_unittest.cc
@@ -7,7 +7,6 @@
#include "base/callback_helpers.h"
#include "base/run_loop.h"
#include "base/task/single_thread_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cc {
@@ -49,9 +48,10 @@ class UniqueNotifierTest : public testing::Test {
// 50000 can be any number bigger than 1. The bigger the easier to more runs.
TEST_F(UniqueNotifierTest, Schedule) {
{
- UniqueNotifier notifier(base::ThreadTaskRunnerHandle::Get().get(),
- base::BindRepeating(&UniqueNotifierTest::Notify,
- base::Unretained(this)));
+ UniqueNotifier notifier(
+ base::SingleThreadTaskRunner::GetCurrentDefault().get(),
+ base::BindRepeating(&UniqueNotifierTest::Notify,
+ base::Unretained(this)));
EXPECT_EQ(0, NotificationCount());
diff --git a/chromium/cc/benchmarks/benchmark_instrumentation.cc b/chromium/cc/benchmarks/benchmark_instrumentation.cc
index 8b98d4ee77e..87b217ea0cd 100644
--- a/chromium/cc/benchmarks/benchmark_instrumentation.cc
+++ b/chromium/cc/benchmarks/benchmark_instrumentation.cc
@@ -18,14 +18,5 @@ void IssueImplThreadRenderingStatsEvent(const RenderingStats& stats) {
TRACE_EVENT_SCOPE_THREAD, "data", stats.AsTraceableData());
}
-void IssueDisplayRenderingStatsEvent() {
- std::unique_ptr<base::trace_event::TracedValue> record_data(
- new base::trace_event::TracedValue());
- record_data->SetInteger("frame_count", 1);
- TRACE_EVENT_INSTANT1(
- "benchmark", "BenchmarkInstrumentation::DisplayRenderingStats",
- TRACE_EVENT_SCOPE_THREAD, "data", std::move(record_data));
-}
-
} // namespace benchmark_instrumentation
} // namespace cc
diff --git a/chromium/cc/benchmarks/benchmark_instrumentation.h b/chromium/cc/benchmarks/benchmark_instrumentation.h
index e90a0ae594e..d9c508efba9 100644
--- a/chromium/cc/benchmarks/benchmark_instrumentation.h
+++ b/chromium/cc/benchmarks/benchmark_instrumentation.h
@@ -25,8 +25,8 @@ constexpr const char* Category() {
const char kBeginFrameId[] = "begin_frame_id";
} // namespace internal
-const char kSendBeginFrame[] = "ThreadProxy::ScheduledActionSendBeginMainFrame";
-const char kDoBeginFrame[] = "ThreadProxy::BeginMainFrame";
+const char kSendBeginFrame[] = "ProxyImpl::ScheduledActionSendBeginMainFrame";
+const char kDoBeginFrame[] = "ProxyMain::BeginMainFrame";
class ScopedBeginFrameTask {
public:
@@ -47,7 +47,6 @@ class ScopedBeginFrameTask {
};
void IssueImplThreadRenderingStatsEvent(const RenderingStats& stats);
-void CC_EXPORT IssueDisplayRenderingStatsEvent();
} // namespace benchmark_instrumentation
} // namespace cc
diff --git a/chromium/cc/benchmarks/invalidation_benchmark.cc b/chromium/cc/benchmarks/invalidation_benchmark.cc
index 02d9470310b..a2ef2c6817d 100644
--- a/chromium/cc/benchmarks/invalidation_benchmark.cc
+++ b/chromium/cc/benchmarks/invalidation_benchmark.cc
@@ -70,10 +70,8 @@ void InvalidationBenchmark::DidUpdateLayers(LayerTreeHost* layer_tree_host) {
void InvalidationBenchmark::RunOnLayer(PictureLayer* layer) {
gfx::Rect visible_layer_rect = gfx::Rect(layer->bounds());
- gfx::Transform from_screen;
- bool invertible = layer->ScreenSpaceTransform().GetInverse(&from_screen);
- if (!invertible)
- from_screen = gfx::Transform();
+ gfx::Transform from_screen =
+ layer->ScreenSpaceTransform().InverseOrIdentity();
gfx::Rect viewport_rect = MathUtil::ProjectEnclosingClippedRect(
from_screen, layer->layer_tree_host()->device_viewport_rect());
visible_layer_rect.Intersect(viewport_rect);
diff --git a/chromium/cc/benchmarks/micro_benchmark_controller.cc b/chromium/cc/benchmarks/micro_benchmark_controller.cc
index ed372b852ce..22b63e2eb3e 100644
--- a/chromium/cc/benchmarks/micro_benchmark_controller.cc
+++ b/chromium/cc/benchmarks/micro_benchmark_controller.cc
@@ -10,7 +10,7 @@
#include "base/callback.h"
#include "base/containers/cxx20_erase.h"
#include "base/ranges/algorithm.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/task/single_thread_task_runner.h"
#include "base/values.h"
#include "cc/benchmarks/invalidation_benchmark.h"
#include "cc/benchmarks/rasterize_and_record_benchmark.h"
@@ -45,9 +45,10 @@ std::unique_ptr<MicroBenchmark> CreateBenchmark(
MicroBenchmarkController::MicroBenchmarkController(LayerTreeHost* host)
: host_(host),
- main_controller_task_runner_(base::ThreadTaskRunnerHandle::IsSet()
- ? base::ThreadTaskRunnerHandle::Get()
- : nullptr) {
+ main_controller_task_runner_(
+ base::SingleThreadTaskRunner::HasCurrentDefault()
+ ? base::SingleThreadTaskRunner::GetCurrentDefault()
+ : nullptr) {
DCHECK(host_);
}
diff --git a/chromium/cc/benchmarks/micro_benchmark_controller_unittest.cc b/chromium/cc/benchmarks/micro_benchmark_controller_unittest.cc
index 7d218b0e4a6..da55e85e310 100644
--- a/chromium/cc/benchmarks/micro_benchmark_controller_unittest.cc
+++ b/chromium/cc/benchmarks/micro_benchmark_controller_unittest.cc
@@ -37,8 +37,8 @@ class MicroBenchmarkControllerTest : public testing::Test {
&layer_tree_host_client_, &task_graph_runner_, animation_host_.get());
layer_tree_host_->SetRootLayer(Layer::Create());
layer_tree_host_->InitializeForTesting(
- TaskRunnerProvider::Create(base::ThreadTaskRunnerHandle::Get(),
- nullptr),
+ TaskRunnerProvider::Create(
+ base::SingleThreadTaskRunner::GetCurrentDefault(), nullptr),
std::unique_ptr<Proxy>(new FakeProxy));
}
diff --git a/chromium/cc/document_transition/document_transition_shared_element_id.cc b/chromium/cc/document_transition/document_transition_shared_element_id.cc
deleted file mode 100644
index 5baacf7e270..00000000000
--- a/chromium/cc/document_transition/document_transition_shared_element_id.cc
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// 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_shared_element_id.h"
-
-#include <sstream>
-#include <string>
-
-#include "base/check_op.h"
-#include "base/containers/flat_set.h"
-
-namespace cc {
-
-DocumentTransitionSharedElementId::DocumentTransitionSharedElementId() =
- default;
-
-DocumentTransitionSharedElementId::DocumentTransitionSharedElementId(
- uint32_t document_tag)
- : document_tag_(document_tag) {}
-
-DocumentTransitionSharedElementId::DocumentTransitionSharedElementId(
- DocumentTransitionSharedElementId&&) = default;
-
-DocumentTransitionSharedElementId::DocumentTransitionSharedElementId(
- const DocumentTransitionSharedElementId&) = default;
-
-DocumentTransitionSharedElementId::~DocumentTransitionSharedElementId() =
- default;
-
-void DocumentTransitionSharedElementId::AddIndex(uint32_t index) {
- DCHECK_NE(document_tag_, 0u);
- element_indices_.insert(index);
-}
-
-bool DocumentTransitionSharedElementId::Matches(uint32_t document_tag,
- uint32_t index) const {
- return document_tag_ == document_tag && element_indices_.count(index) != 0;
-}
-
-std::string DocumentTransitionSharedElementId::ToString() const {
- std::ostringstream str;
- str << "DocumentTransitionSharedElementId{ document_tag: " << document_tag_
- << " element_indices: [";
- std::string separator = "";
- for (auto index : element_indices_) {
- str << separator << index;
- separator = ", ";
- }
- str << "]}";
- return str.str();
-}
-
-} // namespace cc
diff --git a/chromium/cc/input/browser_controls_offset_manager.cc b/chromium/cc/input/browser_controls_offset_manager.cc
index 0e49328a96a..e9c36e7e849 100644
--- a/chromium/cc/input/browser_controls_offset_manager.cc
+++ b/chromium/cc/input/browser_controls_offset_manager.cc
@@ -195,6 +195,13 @@ void BrowserControlsOffsetManager::UpdateBrowserControlsState(
ResetAnimations();
+ // If we're about to animate the controls in, then restart the animation after
+ // the scroll completes. We don't know if a scroll is in progress, but that's
+ // okay; the flag will be reset when a scroll starts next in that case.
+ if (animate && direction == AnimationDirection::SHOWING_CONTROLS) {
+ show_controls_when_scroll_completes_ = true;
+ }
+
if (animate)
SetupAnimation(direction);
else
@@ -387,6 +394,11 @@ void BrowserControlsOffsetManager::ScrollBegin() {
if (pinch_gesture_active_)
return;
+ // If an animation to show the controls is in progress, re-order the animation
+ // to start after the scroll completes. This ensures that the user doesn't
+ // accidentally hide the controls with a gesture that would not normally be
+ // enough to hide them.
+ show_controls_when_scroll_completes_ = IsAnimatingToShowControls();
ResetAnimations();
ResetBaseline();
}
@@ -459,8 +471,13 @@ gfx::Vector2dF BrowserControlsOffsetManager::ScrollBy(
// If the controls are fully visible, treat the current position as the
// new baseline even if the gesture didn't end.
- if (TopControlsShownRatio() == 1.f && BottomControlsShownRatio() == 1.f)
+ if (TopControlsShownRatio() == 1.f && BottomControlsShownRatio() == 1.f) {
ResetBaseline();
+ // Once the controls are fully visible, then any cancelled animation to show
+ // them isn't relevant; the user definitely sees the controls and can decide
+ // if they'd like to keep them.
+ show_controls_when_scroll_completes_ = false;
+ }
ResetAnimations();
@@ -476,6 +493,13 @@ void BrowserControlsOffsetManager::ScrollEnd() {
if (pinch_gesture_active_)
return;
+ // See if we should animate the top bar in, in case there was a race between
+ // chrome showing the controls and the user performing a scroll.
+ if (show_controls_when_scroll_completes_) {
+ SetupAnimation(AnimationDirection::SHOWING_CONTROLS);
+ return;
+ }
+
StartAnimationIfNecessary();
}
diff --git a/chromium/cc/input/browser_controls_offset_manager.h b/chromium/cc/input/browser_controls_offset_manager.h
index 81273d32bcc..6bee980c00d 100644
--- a/chromium/cc/input/browser_controls_offset_manager.h
+++ b/chromium/cc/input/browser_controls_offset_manager.h
@@ -81,6 +81,11 @@ class CC_EXPORT BrowserControlsOffsetManager {
std::pair<float, float> BottomControlsShownRatioRange();
bool HasAnimation();
+ bool IsAnimatingToShowControls() const {
+ return top_controls_animation_.IsInitialized() &&
+ top_controls_animation_.Direction() ==
+ AnimationDirection::SHOWING_CONTROLS;
+ }
void UpdateBrowserControlsState(BrowserControlsState constraints,
BrowserControlsState current,
@@ -177,6 +182,15 @@ class CC_EXPORT BrowserControlsOffsetManager {
absl::optional<std::pair<float, float>>
bottom_min_height_offset_animation_range_;
+ // Should ScrollEnd() animate the controls into view? This is used if there's
+ // a race between chrome starting an animation to show the controls while the
+ // user is doing a scroll gesture, which would cancel animations. We want to
+ // err on the side of showing the controls, so that the user realizes that
+ // they're an option. If we have started, but not yet completed an animation
+ // to show the controls when the scroll starts, or if one starts during the
+ // gesture, then we reorder the animation until after the scroll.
+ bool show_controls_when_scroll_completes_ = false;
+
// Class that holds and manages the state of the controls animations.
class Animation {
public:
@@ -184,8 +198,8 @@ class CC_EXPORT BrowserControlsOffsetManager {
// Whether the animation is initialized with a direction and start and stop
// values.
- bool IsInitialized() { return initialized_; }
- AnimationDirection Direction() { return direction_; }
+ bool IsInitialized() const { return initialized_; }
+ AnimationDirection Direction() const { return direction_; }
void Initialize(AnimationDirection direction,
float start_value,
float stop_value,
diff --git a/chromium/cc/input/browser_controls_offset_manager_unittest.cc b/chromium/cc/input/browser_controls_offset_manager_unittest.cc
index 80b66b6c365..4f5f9b2bdb3 100644
--- a/chromium/cc/input/browser_controls_offset_manager_unittest.cc
+++ b/chromium/cc/input/browser_controls_offset_manager_unittest.cc
@@ -1299,5 +1299,65 @@ TEST(BrowserControlsOffsetManagerTest,
EXPECT_FLOAT_EQ(20.f, manager->TopControlsMinHeightOffset());
}
+// Tests that a "show" animation that's interrupted by a scroll is restarted
+// when the gesture completes.
+TEST(BrowserControlsOffsetManagerTest,
+ InterruptedShowAnimationsAreRestartedAfterScroll) {
+ MockBrowserControlsOffsetManagerClient client(100.f, 0.5f, 0.5f);
+ BrowserControlsOffsetManager* manager = client.manager();
+ // Start off with the controls mostly hidden, so that they will, by default,
+ // try to fully hide at the end of a scroll.
+ client.SetCurrentBrowserControlsShownRatio(/*top_ratio=*/0.2,
+ /*bottom_ratio=*/0.2);
+
+ EXPECT_FALSE(manager->HasAnimation());
+
+ // Start an animation to show the controls
+ manager->UpdateBrowserControlsState(BrowserControlsState::kBoth,
+ BrowserControlsState::kShown, true);
+ EXPECT_TRUE(manager->IsAnimatingToShowControls());
+
+ // Start a scroll, which should cancel the animation.
+ manager->ScrollBegin();
+ EXPECT_FALSE(manager->HasAnimation());
+
+ // Finish the scroll, which should restart the show animation. Since the
+ // animation didn't run yet, the controls would auto-hide otherwise since they
+ // started almost hidden.
+ manager->ScrollEnd();
+ EXPECT_TRUE(manager->IsAnimatingToShowControls());
+}
+
+// If chrome tries to animate in browser controls during a scroll gesture, it
+// should animate them in after the scroll completes.
+TEST(BrowserControlsOffsetManagerTest,
+ ShowingControlsDuringScrollStartsAnimationAfterScroll) {
+ MockBrowserControlsOffsetManagerClient client(100.f, 0.5f, 0.5f);
+ BrowserControlsOffsetManager* manager = client.manager();
+ // Start off with the controls mostly hidden, so that they will, by default,
+ // try to fully hide at the end of a scroll.
+ client.SetCurrentBrowserControlsShownRatio(/*top_ratio=*/0.2,
+ /*bottom_ratio=*/0.2);
+
+ EXPECT_FALSE(manager->HasAnimation());
+
+ // Start a scroll. Make sure that there's no animation running, else we're
+ // testing the wrong case.
+ ASSERT_FALSE(manager->HasAnimation());
+ manager->ScrollBegin();
+ EXPECT_FALSE(manager->HasAnimation());
+
+ // Start an animation to show the controls.
+ manager->UpdateBrowserControlsState(BrowserControlsState::kBoth,
+ BrowserControlsState::kShown, true);
+ EXPECT_TRUE(manager->IsAnimatingToShowControls());
+
+ // Finish the scroll, and the animation should still be in progress and/or
+ // restarted. We don't really care which, as long as it wasn't cancelled and
+ // is trying to show the controls.
+ manager->ScrollEnd();
+ EXPECT_TRUE(manager->IsAnimatingToShowControls());
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/input/input_handler.cc b/chromium/cc/input/input_handler.cc
index 929c3963fcc..a7e81274758 100644
--- a/chromium/cc/input/input_handler.cc
+++ b/chromium/cc/input/input_handler.cc
@@ -62,7 +62,7 @@ base::WeakPtr<InputHandler> InputHandler::Create(
InputHandler::InputHandler(CompositorDelegateForInput& compositor_delegate)
: compositor_delegate_(compositor_delegate),
scrollbar_controller_(std::make_unique<ScrollbarController>(
- &compositor_delegate_.GetImplDeprecated())) {}
+ &compositor_delegate_->GetImplDeprecated())) {}
InputHandler::~InputHandler() = default;
@@ -98,7 +98,7 @@ InputHandler::ScrollStatus InputHandler::ScrollBegin(ScrollState* scroll_state,
// ScrollBy is a better place to do it).
if (scroll_state->delta_granularity() ==
ui::ScrollGranularity::kScrollByPrecisePixel) {
- compositor_delegate_.GetImplDeprecated()
+ compositor_delegate_->GetImplDeprecated()
.mutator_host()
->ScrollAnimationAbort();
scroll_animating_snap_target_ids_ = TargetSnapAreaElementIds();
@@ -176,7 +176,7 @@ InputHandler::ScrollStatus InputHandler::ScrollBegin(ScrollState* scroll_state,
scroll_state->position_y());
gfx::PointF device_viewport_point =
gfx::ScalePoint(gfx::PointF(viewport_point),
- compositor_delegate_.DeviceScaleFactor());
+ compositor_delegate_->DeviceScaleFactor());
if (unification_enabled) {
if (scroll_state->data()->is_main_thread_hit_tested) {
@@ -286,7 +286,7 @@ InputHandler::ScrollStatus InputHandler::ScrollBegin(ScrollState* scroll_state,
// InputHander::ScrollThread::SCROLL_ON_MAIN_THREAD
scroll_status.main_thread_scrolling_reasons =
MainThreadScrollingReason::kNoScrollingLayer;
- if (compositor_delegate_.GetSettings().is_for_embedded_frame) {
+ if (compositor_delegate_->GetSettings().is_for_embedded_frame) {
// OOPIFs or fenced frames 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_IGNORED.
@@ -401,12 +401,12 @@ InputHandlerScrollResult InputHandler::ScrollUpdate(
ui::ScrollGranularity::kScrollByPixel;
}
- compositor_delegate_.AccumulateScrollDeltaForTracing(
+ compositor_delegate_->AccumulateScrollDeltaForTracing(
gfx::Vector2dF(scroll_state->delta_x(), scroll_state->delta_y()));
- compositor_delegate_.WillScrollContent(scroll_node.element_id);
+ compositor_delegate_->WillScrollContent(scroll_node.element_id);
- float initial_top_controls_offset = compositor_delegate_.GetImplDeprecated()
+ float initial_top_controls_offset = compositor_delegate_->GetImplDeprecated()
.browser_controls_manager()
->ControlsTopOffset();
@@ -421,8 +421,8 @@ InputHandlerScrollResult InputHandler::ScrollUpdate(
bool did_scroll_content = did_scroll_x || did_scroll_y;
if (did_scroll_content) {
bool is_animated_scroll = ShouldAnimateScroll(*scroll_state);
- compositor_delegate_.DidScrollContent(scroll_node.element_id,
- is_animated_scroll);
+ compositor_delegate_->DidScrollContent(scroll_node.element_id,
+ is_animated_scroll);
} else {
overscroll_delta_for_main_thread_ +=
gfx::Vector2dF(scroll_state->delta_x(), scroll_state->delta_y());
@@ -451,7 +451,7 @@ InputHandlerScrollResult InputHandler::ScrollUpdate(
accumulated_root_overscroll_ += unused_root_delta;
bool did_scroll_top_controls =
- initial_top_controls_offset != compositor_delegate_.GetImplDeprecated()
+ initial_top_controls_offset != compositor_delegate_->GetImplDeprecated()
.browser_controls_manager()
->ControlsTopOffset();
@@ -481,11 +481,12 @@ InputHandlerScrollResult InputHandler::ScrollUpdate(
}
// Run animations which need to respond to updated scroll offset.
- compositor_delegate_.GetImplDeprecated().mutator_host()->TickScrollAnimations(
- compositor_delegate_.GetImplDeprecated()
- .CurrentBeginFrameArgs()
- .frame_time,
- GetScrollTree());
+ compositor_delegate_->GetImplDeprecated()
+ .mutator_host()
+ ->TickScrollAnimations(compositor_delegate_->GetImplDeprecated()
+ .CurrentBeginFrameArgs()
+ .frame_time,
+ GetScrollTree());
return scroll_result;
}
@@ -527,7 +528,7 @@ void InputHandler::ScrollEnd(bool should_snap) {
// Note that if we deferred the scroll end then we should not snap. We will
// snap once we deliver the deferred scroll end.
- if (compositor_delegate_.GetImplDeprecated()
+ if (compositor_delegate_->GetImplDeprecated()
.mutator_host()
->ImplOnlyScrollAnimatingElement()) {
DCHECK(!deferred_scroll_end_);
@@ -542,7 +543,7 @@ void InputHandler::ScrollEnd(bool should_snap) {
DCHECK(latched_scroll_type_.has_value());
- compositor_delegate_.GetImplDeprecated()
+ compositor_delegate_->GetImplDeprecated()
.browser_controls_manager()
->ScrollEnd();
@@ -575,19 +576,20 @@ void InputHandler::RecordScrollBegin(
scrolling_thread = FrameInfo::SmoothEffectDrivingThread::kMain;
break;
}
- compositor_delegate_.GetImplDeprecated().frame_trackers().StartScrollSequence(
- tracker_type, scrolling_thread);
+ compositor_delegate_->GetImplDeprecated()
+ .frame_trackers()
+ .StartScrollSequence(tracker_type, scrolling_thread);
}
void InputHandler::RecordScrollEnd(ui::ScrollInputType input_type) {
- compositor_delegate_.GetImplDeprecated().frame_trackers().StopSequence(
+ compositor_delegate_->GetImplDeprecated().frame_trackers().StopSequence(
GetTrackerTypeForScroll(input_type));
}
InputHandlerPointerResult InputHandler::MouseMoveAt(
const gfx::Point& viewport_point) {
InputHandlerPointerResult result;
- if (compositor_delegate_.GetSettings()
+ if (compositor_delegate_->GetSettings()
.compositor_threaded_scrollbar_scrolling) {
result =
scrollbar_controller_->HandlePointerMove(gfx::PointF(viewport_point));
@@ -595,11 +597,11 @@ InputHandlerPointerResult InputHandler::MouseMoveAt(
// Early out if there are no animation controllers and avoid the hit test.
// This happens on platforms without animated scrollbars.
- if (!compositor_delegate_.HasAnimatedScrollbars())
+ if (!compositor_delegate_->HasAnimatedScrollbars())
return result;
gfx::PointF device_viewport_point = gfx::ScalePoint(
- gfx::PointF(viewport_point), compositor_delegate_.DeviceScaleFactor());
+ gfx::PointF(viewport_point), compositor_delegate_->DeviceScaleFactor());
ScrollHitTestResult hit_test = HitTestScrollNode(device_viewport_point);
@@ -616,11 +618,11 @@ InputHandlerPointerResult InputHandler::MouseMoveAt(
ElementId scroll_element_id = scroll_node->element_id;
ScrollbarAnimationController* new_animation_controller =
- compositor_delegate_.GetImplDeprecated()
+ compositor_delegate_->GetImplDeprecated()
.ScrollbarAnimationControllerForElementId(scroll_element_id);
if (scroll_element_id != scroll_element_id_mouse_currently_over_) {
ScrollbarAnimationController* old_animation_controller =
- compositor_delegate_.GetImplDeprecated()
+ compositor_delegate_->GetImplDeprecated()
.ScrollbarAnimationControllerForElementId(
scroll_element_id_mouse_currently_over_);
if (old_animation_controller)
@@ -638,7 +640,7 @@ InputHandlerPointerResult InputHandler::MouseMoveAt(
}
PointerResultType InputHandler::HitTest(const gfx::PointF& viewport_point) {
- return compositor_delegate_.GetSettings()
+ return compositor_delegate_->GetSettings()
.compositor_threaded_scrollbar_scrolling
? scrollbar_controller_->HitTest(viewport_point)
: PointerResultType::kUnhandled;
@@ -648,7 +650,7 @@ InputHandlerPointerResult InputHandler::MouseDown(
const gfx::PointF& viewport_point,
bool shift_modifier) {
ScrollbarAnimationController* animation_controller =
- compositor_delegate_.GetImplDeprecated()
+ compositor_delegate_->GetImplDeprecated()
.ScrollbarAnimationControllerForElementId(
scroll_element_id_mouse_currently_over_);
if (animation_controller) {
@@ -658,7 +660,7 @@ InputHandlerPointerResult InputHandler::MouseDown(
}
InputHandlerPointerResult result;
- if (compositor_delegate_.GetSettings()
+ if (compositor_delegate_->GetSettings()
.compositor_threaded_scrollbar_scrolling) {
result = scrollbar_controller_->HandlePointerDown(viewport_point,
shift_modifier);
@@ -671,7 +673,7 @@ InputHandlerPointerResult InputHandler::MouseUp(
const gfx::PointF& viewport_point) {
if (scroll_element_id_mouse_currently_captured_) {
ScrollbarAnimationController* animation_controller =
- compositor_delegate_.GetImplDeprecated()
+ compositor_delegate_->GetImplDeprecated()
.ScrollbarAnimationControllerForElementId(
scroll_element_id_mouse_currently_captured_);
@@ -682,7 +684,7 @@ InputHandlerPointerResult InputHandler::MouseUp(
}
InputHandlerPointerResult result;
- if (compositor_delegate_.GetSettings()
+ if (compositor_delegate_->GetSettings()
.compositor_threaded_scrollbar_scrolling)
result = scrollbar_controller_->HandlePointerUp(viewport_point);
@@ -690,14 +692,14 @@ InputHandlerPointerResult InputHandler::MouseUp(
}
void InputHandler::MouseLeave() {
- compositor_delegate_.DidMouseLeave();
+ compositor_delegate_->DidMouseLeave();
scroll_element_id_mouse_currently_over_ = ElementId();
}
ElementId InputHandler::FindFrameElementIdAtPoint(
const gfx::PointF& viewport_point) {
gfx::PointF device_viewport_point = gfx::ScalePoint(
- gfx::PointF(viewport_point), compositor_delegate_.DeviceScaleFactor());
+ gfx::PointF(viewport_point), compositor_delegate_->DeviceScaleFactor());
return ActiveTree().FindFrameElementIdAtPoint(device_viewport_point);
}
@@ -725,15 +727,15 @@ void InputHandler::SetSynchronousInputHandlerRootScrollOffset(
if (!changed)
return;
- compositor_delegate_.DidScrollContent(OuterViewportScrollNode()->element_id,
- /*is_animated_scroll=*/false);
+ compositor_delegate_->DidScrollContent(OuterViewportScrollNode()->element_id,
+ /*is_animated_scroll=*/false);
SetNeedsCommit();
// After applying the synchronous input handler's scroll offset, tell it what
// we ended up with.
UpdateRootLayerStateForSynchronousInputHandler();
- compositor_delegate_.SetNeedsFullViewportRedraw();
+ compositor_delegate_->SetNeedsFullViewportRedraw();
}
void InputHandler::PinchGestureBegin(const gfx::Point& anchor,
@@ -767,10 +769,10 @@ void InputHandler::PinchGestureBegin(const gfx::Point& anchor,
DidLatchToScroller(state, source);
}
- compositor_delegate_.GetImplDeprecated()
+ compositor_delegate_->GetImplDeprecated()
.browser_controls_manager()
->PinchBegin();
- compositor_delegate_.DidStartPinchZoom();
+ compositor_delegate_->DidStartPinchZoom();
}
void InputHandler::PinchGestureUpdate(float magnify_delta,
@@ -781,7 +783,7 @@ void InputHandler::PinchGestureUpdate(float magnify_delta,
has_pinch_zoomed_ = true;
GetViewport().PinchUpdate(magnify_delta, anchor);
SetNeedsCommit();
- compositor_delegate_.DidUpdatePinchZoom();
+ compositor_delegate_->DidUpdatePinchZoom();
// Pinching can change the root scroll offset, so inform the synchronous input
// handler.
UpdateRootLayerStateForSynchronousInputHandler();
@@ -799,15 +801,15 @@ void InputHandler::PinchGestureEnd(const gfx::Point& anchor) {
ClearCurrentlyScrollingNode();
}
GetViewport().PinchEnd(anchor, snap_to_min);
- compositor_delegate_.GetImplDeprecated()
+ compositor_delegate_->GetImplDeprecated()
.browser_controls_manager()
->PinchEnd();
SetNeedsCommit();
- compositor_delegate_.DidEndPinchZoom();
+ compositor_delegate_->DidEndPinchZoom();
}
void InputHandler::SetNeedsAnimateInput() {
- compositor_delegate_.GetImplDeprecated().SetNeedsAnimateInput();
+ compositor_delegate_->GetImplDeprecated().SetNeedsAnimateInput();
}
bool InputHandler::IsCurrentlyScrollingViewport() const {
@@ -825,7 +827,7 @@ EventListenerProperties InputHandler::GetEventListenerProperties(
bool InputHandler::HasBlockingWheelEventHandlerAt(
const gfx::Point& viewport_point) const {
gfx::PointF device_viewport_point = gfx::ScalePoint(
- gfx::PointF(viewport_point), compositor_delegate_.DeviceScaleFactor());
+ gfx::PointF(viewport_point), compositor_delegate_->DeviceScaleFactor());
LayerImpl* layer_impl_with_wheel_event_handler =
ActiveTree().FindLayerThatIsHitByPointInWheelEventHandlerRegion(
@@ -839,7 +841,7 @@ InputHandler::EventListenerTypeForTouchStartOrMoveAt(
const gfx::Point& viewport_point,
TouchAction* out_touch_action) {
gfx::PointF device_viewport_point = gfx::ScalePoint(
- gfx::PointF(viewport_point), compositor_delegate_.DeviceScaleFactor());
+ gfx::PointF(viewport_point), compositor_delegate_->DeviceScaleFactor());
LayerImpl* layer_impl_with_touch_handler =
ActiveTree().FindLayerThatIsHitByPointInTouchHandlerRegion(
@@ -854,14 +856,11 @@ InputHandler::EventListenerTypeForTouchStartOrMoveAt(
if (out_touch_action) {
gfx::Transform layer_screen_space_transform =
layer_impl_with_touch_handler->ScreenSpaceTransform();
- gfx::Transform inverse_layer_screen_space(
- gfx::Transform::kSkipInitialization);
- bool can_be_inversed =
- layer_screen_space_transform.GetInverse(&inverse_layer_screen_space);
// Getting here indicates that |layer_impl_with_touch_handler| is non-null,
// which means that the |hit| in FindClosestMatchingLayer() is true, which
// indicates that the inverse is available.
- DCHECK(can_be_inversed);
+ gfx::Transform inverse_layer_screen_space =
+ layer_screen_space_transform.GetCheckedInverse();
bool clipped = false;
gfx::Point3F planar_point = MathUtil::ProjectPoint3D(
inverse_layer_screen_space, device_viewport_point, &clipped);
@@ -890,23 +889,23 @@ InputHandler::EventListenerTypeForTouchStartOrMoveAt(
std::unique_ptr<LatencyInfoSwapPromiseMonitor>
InputHandler::CreateLatencyInfoSwapPromiseMonitor(ui::LatencyInfo* latency) {
- return compositor_delegate_.GetImplDeprecated()
+ return compositor_delegate_->GetImplDeprecated()
.CreateLatencyInfoSwapPromiseMonitor(latency);
}
std::unique_ptr<EventsMetricsManager::ScopedMonitor>
InputHandler::GetScopedEventMetricsMonitor(
EventsMetricsManager::ScopedMonitor::DoneCallback done_callback) {
- return compositor_delegate_.GetImplDeprecated().GetScopedEventMetricsMonitor(
+ return compositor_delegate_->GetImplDeprecated().GetScopedEventMetricsMonitor(
std::move(done_callback));
}
ScrollElasticityHelper* InputHandler::CreateScrollElasticityHelper() {
DCHECK(!scroll_elasticity_helper_);
- if (compositor_delegate_.GetSettings().enable_elastic_overscroll) {
+ if (compositor_delegate_->GetSettings().enable_elastic_overscroll) {
scroll_elasticity_helper_.reset(
ScrollElasticityHelper::CreateForLayerTreeHostImpl(
- &compositor_delegate_.GetImplDeprecated()));
+ &compositor_delegate_->GetImplDeprecated()));
}
return scroll_elasticity_helper_.get();
}
@@ -1007,7 +1006,7 @@ void InputHandler::ScrollEndForSnapFling(bool did_finish) {
}
void InputHandler::NotifyInputEvent() {
- compositor_delegate_.GetImplDeprecated().NotifyInputEvent();
+ compositor_delegate_->GetImplDeprecated().NotifyInputEvent();
}
//
@@ -1037,7 +1036,7 @@ void InputHandler::ProcessCommitDeltas(
// an input responsibility.
GetScrollTree().CollectScrollDeltas(
commit_data, inner_viewport_scroll_element_id,
- compositor_delegate_.GetSettings().commit_fractional_scroll_deltas,
+ compositor_delegate_->GetSettings().commit_fractional_scroll_deltas,
snapped_elements, main_thread_mutator_host);
// Record and reset scroll source flags.
@@ -1108,7 +1107,7 @@ void InputHandler::WillBeginImplFrame(const viz::BeginFrameArgs& args) {
void InputHandler::DidCommit() {
// In high latency mode commit cannot finish within the same frame. We need to
// flush input here to make sure they got picked up by |PrepareTiles()|.
- if (input_handler_client_ && compositor_delegate_.IsInHighLatencyMode())
+ if (input_handler_client_ && compositor_delegate_->IsInHighLatencyMode())
input_handler_client_->DeliverInputForHighLatencyMode();
}
@@ -1214,11 +1213,11 @@ const ScrollNode* InputHandler::CurrentlyScrollingNode() const {
}
ScrollTree& InputHandler::GetScrollTree() {
- return compositor_delegate_.GetScrollTree();
+ return compositor_delegate_->GetScrollTree();
}
ScrollTree& InputHandler::GetScrollTree() const {
- return compositor_delegate_.GetScrollTree();
+ return compositor_delegate_->GetScrollTree();
}
ScrollNode* InputHandler::InnerViewportScrollNode() const {
@@ -1230,21 +1229,21 @@ ScrollNode* InputHandler::OuterViewportScrollNode() const {
}
Viewport& InputHandler::GetViewport() const {
- return compositor_delegate_.GetImplDeprecated().viewport();
+ return compositor_delegate_->GetImplDeprecated().viewport();
}
void InputHandler::SetNeedsCommit() {
- compositor_delegate_.SetNeedsCommit();
+ compositor_delegate_->SetNeedsCommit();
}
LayerTreeImpl& InputHandler::ActiveTree() {
- DCHECK(compositor_delegate_.GetImplDeprecated().active_tree());
- return *compositor_delegate_.GetImplDeprecated().active_tree();
+ DCHECK(compositor_delegate_->GetImplDeprecated().active_tree());
+ return *compositor_delegate_->GetImplDeprecated().active_tree();
}
LayerTreeImpl& InputHandler::ActiveTree() const {
- DCHECK(compositor_delegate_.GetImplDeprecated().active_tree());
- return *compositor_delegate_.GetImplDeprecated().active_tree();
+ DCHECK(compositor_delegate_->GetImplDeprecated().active_tree());
+ return *compositor_delegate_->GetImplDeprecated().active_tree();
}
FrameSequenceTrackerType InputHandler::GetTrackerTypeForScroll(
@@ -1299,15 +1298,15 @@ gfx::Vector2dF InputHandler::ResolveScrollGranularityToPixels(
if (granularity == ui::ScrollGranularity::kScrollByPercentage) {
gfx::SizeF scroller_size = gfx::SizeF(scroll_node.container_bounds);
- gfx::SizeF viewport_size(compositor_delegate_.VisualDeviceViewportSize());
+ gfx::SizeF viewport_size(compositor_delegate_->VisualDeviceViewportSize());
// Convert from rootframe coordinates to screen coordinates (physical
// pixels if --use-zoom-for-dsf enabled, DIPs otherwise).
- scroller_size.Scale(compositor_delegate_.PageScaleFactor());
+ scroller_size.Scale(compositor_delegate_->PageScaleFactor());
// Convert from physical pixels to screen coordinates (if --use-zoom-for-dsf
// enabled, `DeviceScaleFactor()` returns 1).
- viewport_size.InvScale(compositor_delegate_.DeviceScaleFactor());
+ viewport_size.InvScale(compositor_delegate_->DeviceScaleFactor());
pixel_delta = ScrollUtils::ResolveScrollPercentageToPixels(
pixel_delta, scroller_size, viewport_size);
@@ -1643,7 +1642,7 @@ bool InputHandler::IsInitialScrollHitTestReliable(
gfx::Vector2dF InputHandler::ComputeScrollDelta(const ScrollNode& scroll_node,
const gfx::Vector2dF& delta) {
ScrollTree& scroll_tree = GetScrollTree();
- float scale_factor = compositor_delegate_.PageScaleFactor();
+ float scale_factor = compositor_delegate_->PageScaleFactor();
gfx::Vector2dF adjusted_scroll(delta);
adjusted_scroll.InvScale(scale_factor);
@@ -1667,17 +1666,13 @@ bool InputHandler::CalculateLocalScrollDeltaAndStartPoint(
// the scroll hit test in the first place.
const gfx::Transform screen_space_transform =
GetScrollTree().ScreenSpaceTransform(scroll_node.id);
- DCHECK(screen_space_transform.IsInvertible());
- gfx::Transform inverse_screen_space_transform(
- gfx::Transform::kSkipInitialization);
- bool did_invert =
- screen_space_transform.GetInverse(&inverse_screen_space_transform);
// TODO(shawnsingh): With the advent of impl-side scrolling for non-root
// layers, we may need to explicitly handle uninvertible transforms here.
- DCHECK(did_invert);
+ gfx::Transform inverse_screen_space_transform =
+ screen_space_transform.GetCheckedInverse();
float scale_from_viewport_to_screen_space =
- compositor_delegate_.DeviceScaleFactor();
+ compositor_delegate_->DeviceScaleFactor();
gfx::PointF screen_space_point =
gfx::ScalePoint(viewport_point, scale_from_viewport_to_screen_space);
@@ -1747,7 +1742,7 @@ gfx::Vector2dF InputHandler::ScrollNodeWithViewportSpaceDelta(
return gfx::Vector2dF();
float scale_from_viewport_to_screen_space =
- compositor_delegate_.DeviceScaleFactor();
+ compositor_delegate_->DeviceScaleFactor();
gfx::PointF actual_viewport_end_point = gfx::ScalePoint(
actual_screen_space_end_point, 1.f / scale_from_viewport_to_screen_space);
return actual_viewport_end_point - viewport_point;
@@ -1759,7 +1754,7 @@ gfx::Vector2dF InputHandler::ScrollNodeWithLocalDelta(
bool scrolls_outer_viewport = scroll_node.scrolls_outer_viewport;
TRACE_EVENT2("cc", "ScrollNodeWithLocalDelta", "delta_y", local_delta.y(),
"is_outer", scrolls_outer_viewport);
- float page_scale_factor = compositor_delegate_.PageScaleFactor();
+ float page_scale_factor = compositor_delegate_->PageScaleFactor();
ScrollTree& scroll_tree = GetScrollTree();
gfx::PointF previous_offset =
@@ -1823,7 +1818,7 @@ void InputHandler::ScrollLatchedScroller(ScrollState* scroll_state,
if (ShouldAnimateScroll(*scroll_state)) {
DCHECK(!scroll_state->is_in_inertial_phase());
- if (ElementId id = compositor_delegate_.GetImplDeprecated()
+ if (ElementId id = compositor_delegate_->GetImplDeprecated()
.mutator_host()
->ImplOnlyScrollAnimatingElement()) {
TRACE_EVENT_INSTANT0("cc", "UpdateExistingAnimation",
@@ -1864,7 +1859,7 @@ void InputHandler::ScrollLatchedScroller(ScrollState* scroll_state,
applied_delta = GetViewport().ScrollAnimated(delta, delayed_by);
} else {
applied_delta = ComputeScrollDelta(scroll_node, delta);
- compositor_delegate_.GetImplDeprecated().ScrollAnimationCreate(
+ compositor_delegate_->GetImplDeprecated().ScrollAnimationCreate(
scroll_node, applied_delta, delayed_by);
}
}
@@ -2008,10 +2003,10 @@ void InputHandler::DidLatchToScroller(const ScrollState& scroll_state,
ui::ScrollInputType type) {
DCHECK(CurrentlyScrollingNode());
deferred_scroll_end_ = false;
- compositor_delegate_.GetImplDeprecated()
+ compositor_delegate_->GetImplDeprecated()
.browser_controls_manager()
->ScrollBegin();
- compositor_delegate_.GetImplDeprecated()
+ compositor_delegate_->GetImplDeprecated()
.mutator_host()
->ScrollAnimationAbort();
@@ -2021,7 +2016,7 @@ void InputHandler::DidLatchToScroller(const ScrollState& scroll_state,
latched_scroll_type_ = type;
last_scroll_begin_state_ = scroll_state;
- compositor_delegate_.DidStartScroll();
+ compositor_delegate_->DidStartScroll();
RecordCompositorSlowScrollMetric(type, CC_THREAD);
UpdateScrollSourceInfo(scroll_state, type);
@@ -2062,7 +2057,7 @@ bool InputHandler::CanConsumeDelta(const ScrollState& scroll_state,
}
bool InputHandler::ShouldAnimateScroll(const ScrollState& scroll_state) const {
- if (!compositor_delegate_.GetSettings().enable_smooth_scroll)
+ if (!compositor_delegate_->GetSettings().enable_smooth_scroll)
return false;
bool has_precise_scroll_deltas = scroll_state.delta_granularity() ==
@@ -2118,20 +2113,20 @@ bool InputHandler::SnapAtScrollEnd(SnapReason reason) {
// TODO(bokan): Why only on the viewport?
if (GetViewport().ShouldScroll(*scroll_node)) {
- compositor_delegate_.WillScrollContent(scroll_node->element_id);
+ compositor_delegate_->WillScrollContent(scroll_node->element_id);
}
gfx::Vector2dF delta = snap_position - current_position;
bool did_animate = false;
if (scroll_node->scrolls_outer_viewport) {
gfx::Vector2dF scaled_delta(delta);
- scaled_delta.Scale(compositor_delegate_.PageScaleFactor());
+ scaled_delta.Scale(compositor_delegate_->PageScaleFactor());
gfx::Vector2dF consumed_delta =
GetViewport().ScrollAnimated(scaled_delta, base::TimeDelta());
did_animate = !consumed_delta.IsZero();
} else {
did_animate =
- compositor_delegate_.GetImplDeprecated().ScrollAnimationCreate(
+ compositor_delegate_->GetImplDeprecated().ScrollAnimationCreate(
*scroll_node, delta, base::TimeDelta());
}
DCHECK(!IsAnimatingForSnap());
@@ -2167,7 +2162,7 @@ void InputHandler::ClearCurrentlyScrollingNode() {
latched_scroll_type_.reset();
last_scroll_update_state_.reset();
last_scroll_begin_state_.reset();
- compositor_delegate_.DidEndScroll();
+ compositor_delegate_->DidEndScroll();
}
bool InputHandler::ScrollAnimationUpdateTarget(
@@ -2176,26 +2171,26 @@ bool InputHandler::ScrollAnimationUpdateTarget(
base::TimeDelta delayed_by) {
// TODO(bokan): Remove |scroll_node| as a parameter and just use the value
// coming from |mutator_host|.
- DCHECK_EQ(scroll_node.element_id, compositor_delegate_.GetImplDeprecated()
+ DCHECK_EQ(scroll_node.element_id, compositor_delegate_->GetImplDeprecated()
.mutator_host()
->ImplOnlyScrollAnimatingElement());
- float scale_factor = compositor_delegate_.PageScaleFactor();
+ float scale_factor = compositor_delegate_->PageScaleFactor();
gfx::Vector2dF adjusted_delta =
gfx::ScaleVector2d(scroll_delta, 1.f / scale_factor);
adjusted_delta = UserScrollableDelta(scroll_node, adjusted_delta);
bool animation_updated =
- compositor_delegate_.GetImplDeprecated()
+ compositor_delegate_->GetImplDeprecated()
.mutator_host()
->ImplOnlyScrollAnimationUpdateTarget(
adjusted_delta, GetScrollTree().MaxScrollOffset(scroll_node.id),
- compositor_delegate_.GetImplDeprecated()
+ compositor_delegate_->GetImplDeprecated()
.CurrentBeginFrameArgs()
.frame_time,
delayed_by);
if (animation_updated) {
- compositor_delegate_.DidUpdateScrollAnimationCurve();
+ compositor_delegate_->DidUpdateScrollAnimationCurve();
// The animation is no longer targeting a snap position. By clearing the
// target, this will ensure that we attempt to resnap at the end of this
@@ -2254,14 +2249,14 @@ bool InputHandler::ScrollbarScrollIsActive() {
}
void InputHandler::SetDeferBeginMainFrame(bool defer_begin_main_frame) const {
- compositor_delegate_.SetDeferBeginMainFrame(defer_begin_main_frame);
+ compositor_delegate_->SetDeferBeginMainFrame(defer_begin_main_frame);
}
void InputHandler::UpdateBrowserControlsState(BrowserControlsState constraints,
BrowserControlsState current,
bool animate) {
- compositor_delegate_.UpdateBrowserControlsState(constraints, current,
- animate);
+ compositor_delegate_->UpdateBrowserControlsState(constraints, current,
+ animate);
}
} // namespace cc
diff --git a/chromium/cc/input/input_handler.h b/chromium/cc/input/input_handler.h
index 6625d4bfea8..4b47f750ad5 100644
--- a/chromium/cc/input/input_handler.h
+++ b/chromium/cc/input/input_handler.h
@@ -7,6 +7,8 @@
#include <memory>
+#include "base/memory/raw_ptr.h"
+#include "base/memory/raw_ref.h"
#include "base/time/time.h"
#include "cc/cc_export.h"
#include "cc/input/browser_controls_state.h"
@@ -636,7 +638,7 @@ class CC_EXPORT InputHandler : public InputDelegateForCompositor {
// |scroll_node|. This can be nullptr if no layer was hit and there are no
// viewport nodes (e.g. OOPIF, UI compositor).
struct ScrollHitTestResult {
- ScrollNode* scroll_node;
+ raw_ptr<ScrollNode> scroll_node;
bool hit_test_successful;
};
ScrollHitTestResult HitTestScrollNode(
@@ -681,7 +683,7 @@ class CC_EXPORT InputHandler : public InputDelegateForCompositor {
// The input handler is owned by the delegate so their lifetimes are tied
// together.
- CompositorDelegateForInput& compositor_delegate_;
+ const raw_ref<CompositorDelegateForInput> compositor_delegate_;
raw_ptr<InputHandlerClient> input_handler_client_ = nullptr;
diff --git a/chromium/cc/input/page_scale_animation.cc b/chromium/cc/input/page_scale_animation.cc
index 8c05ddfaa5c..5125cb75aa4 100644
--- a/chromium/cc/input/page_scale_animation.cc
+++ b/chromium/cc/input/page_scale_animation.cc
@@ -18,6 +18,7 @@ namespace {
// between 0 and 1, representing the percentage position within the viewport.
gfx::Vector2dF NormalizeFromViewport(const gfx::Vector2dF& denormalized,
const gfx::SizeF& viewport_size) {
+ DCHECK(!viewport_size.IsEmpty());
return gfx::ScaleVector2d(denormalized,
1.f / viewport_size.width(),
1.f / viewport_size.height());
diff --git a/chromium/cc/input/scrollbar_controller.cc b/chromium/cc/input/scrollbar_controller.cc
index e47ff01bb19..5a00962bf42 100644
--- a/chromium/cc/input/scrollbar_controller.cc
+++ b/chromium/cc/input/scrollbar_controller.cc
@@ -786,8 +786,7 @@ gfx::PointF ScrollbarController::GetScrollbarRelativePosition(
return gfx::PointF(0, 0);
}
- gfx::Transform inverse_screen_space_transform(
- gfx::Transform::kSkipInitialization);
+ gfx::Transform inverse_screen_space_transform;
gfx::Transform scaled_screen_space_transform(
scrollbar->ScreenSpaceTransform());
diff --git a/chromium/cc/input/scroller_size_metrics.h b/chromium/cc/input/scroller_size_metrics.h
deleted file mode 100644
index acfd7950f34..00000000000
--- a/chromium/cc/input/scroller_size_metrics.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2017 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_INPUT_SCROLLER_SIZE_METRICS_H_
-#define CC_INPUT_SCROLLER_SIZE_METRICS_H_
-
-namespace cc {
-
-// Use the two constants to record GPU memory for tilings. Any layer that
-// costs more than ~1GB will get capped.
-static constexpr int kGPUMemoryForTilingsLargestBucketKb = 1000000;
-static constexpr int kGPUMemoryForTilingsBucketCount = 50;
-} // namespace cc
-
-#endif // CC_INPUT_SCROLLER_SIZE_METRICS_H_
diff --git a/chromium/cc/layers/append_quads_data.h b/chromium/cc/layers/append_quads_data.h
index c6ade616bb0..939a92df584 100644
--- a/chromium/cc/layers/append_quads_data.h
+++ b/chromium/cc/layers/append_quads_data.h
@@ -45,8 +45,8 @@ class CC_EXPORT AppendQuadsData {
// activate.
std::vector<viz::SurfaceId> activation_dependencies;
- // Indicates if any layer has SharedElementResourceIds which need to be
- // swapped with actual viz::ResourceIds in the Viz process.
+ // Indicates if any layer has ViewTransitionElementResourceIds which need to
+ // be swapped with actual viz::ResourceIds in the Viz process.
bool has_shared_element_resources = false;
};
diff --git a/chromium/cc/layers/document_transition_content_layer.cc b/chromium/cc/layers/document_transition_content_layer.cc
deleted file mode 100644
index 7e982e0d7fc..00000000000
--- a/chromium/cc/layers/document_transition_content_layer.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/layers/document_transition_content_layer.h"
-
-#include <memory>
-
-#include "base/logging.h"
-#include "cc/layers/document_transition_content_layer_impl.h"
-#include "cc/trees/layer_tree_host.h"
-
-namespace cc {
-
-scoped_refptr<DocumentTransitionContentLayer>
-DocumentTransitionContentLayer::Create(
- const viz::SharedElementResourceId& resource_id,
- bool is_live_content_layer) {
- return base::WrapRefCounted(
- new DocumentTransitionContentLayer(resource_id, is_live_content_layer));
-}
-
-DocumentTransitionContentLayer::DocumentTransitionContentLayer(
- const viz::SharedElementResourceId& resource_id,
- bool is_live_content_layer)
- : resource_id_(resource_id),
- is_live_content_layer_(is_live_content_layer) {}
-
-DocumentTransitionContentLayer::~DocumentTransitionContentLayer() = default;
-
-viz::SharedElementResourceId
-DocumentTransitionContentLayer::DocumentTransitionResourceId() const {
- return resource_id_;
-}
-
-std::unique_ptr<LayerImpl> DocumentTransitionContentLayer::CreateLayerImpl(
- LayerTreeImpl* tree_impl) const {
- return DocumentTransitionContentLayerImpl::Create(
- tree_impl, id(), resource_id_, is_live_content_layer_);
-}
-
-} // namespace cc
diff --git a/chromium/cc/layers/document_transition_content_layer.h b/chromium/cc/layers/document_transition_content_layer.h
deleted file mode 100644
index 8c7a09a29b0..00000000000
--- a/chromium/cc/layers/document_transition_content_layer.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_LAYERS_DOCUMENT_TRANSITION_CONTENT_LAYER_H_
-#define CC_LAYERS_DOCUMENT_TRANSITION_CONTENT_LAYER_H_
-
-#include <memory>
-
-#include "base/logging.h"
-#include "cc/cc_export.h"
-#include "cc/layers/layer.h"
-#include "components/viz/common/shared_element_resource_id.h"
-
-namespace cc {
-
-// A layer that renders a texture cached in the Viz process.
-class CC_EXPORT DocumentTransitionContentLayer : public Layer {
- public:
- static scoped_refptr<DocumentTransitionContentLayer> Create(
- const viz::SharedElementResourceId& resource_id,
- bool is_live_content_layer);
-
- DocumentTransitionContentLayer(const DocumentTransitionContentLayer&) =
- delete;
- DocumentTransitionContentLayer& operator=(
- const DocumentTransitionContentLayer&) = delete;
-
- viz::SharedElementResourceId DocumentTransitionResourceId() const override;
-
- // Layer overrides.
- std::unique_ptr<LayerImpl> CreateLayerImpl(
- LayerTreeImpl* tree_impl) const override;
-
- protected:
- explicit DocumentTransitionContentLayer(
- const viz::SharedElementResourceId& resource_id,
- bool is_live_content_layer);
-
- private:
- ~DocumentTransitionContentLayer() override;
-
- const viz::SharedElementResourceId resource_id_;
- const bool is_live_content_layer_;
-};
-
-} // namespace cc
-
-#endif // CC_LAYERS_DOCUMENT_TRANSITION_CONTENT_LAYER_H_
diff --git a/chromium/cc/layers/document_transition_content_layer_impl.h b/chromium/cc/layers/document_transition_content_layer_impl.h
deleted file mode 100644
index 2c7938dc735..00000000000
--- a/chromium/cc/layers/document_transition_content_layer_impl.h
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2021 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_LAYERS_DOCUMENT_TRANSITION_CONTENT_LAYER_IMPL_H_
-#define CC_LAYERS_DOCUMENT_TRANSITION_CONTENT_LAYER_IMPL_H_
-
-#include <memory>
-
-#include "cc/cc_export.h"
-#include "cc/layers/layer_impl.h"
-#include "components/viz/common/shared_element_resource_id.h"
-
-namespace cc {
-
-class CC_EXPORT DocumentTransitionContentLayerImpl : public LayerImpl {
- public:
- static std::unique_ptr<DocumentTransitionContentLayerImpl> Create(
- LayerTreeImpl* tree_impl,
- int id,
- const viz::SharedElementResourceId& resource_id,
- bool is_live_content_layer);
-
- DocumentTransitionContentLayerImpl(
- const DocumentTransitionContentLayerImpl&) = delete;
- ~DocumentTransitionContentLayerImpl() override;
-
- DocumentTransitionContentLayerImpl& operator=(
- const DocumentTransitionContentLayerImpl&) = delete;
-
- // LayerImpl overrides.
- std::unique_ptr<LayerImpl> CreateLayerImpl(
- LayerTreeImpl* tree_impl) const override;
- void AppendQuads(viz::CompositorRenderPass* render_pass,
- AppendQuadsData* append_quads_data) override;
-
- void NotifyKnownResourceIdsBeforeAppendQuads(
- const base::flat_set<viz::SharedElementResourceId>& known_resource_ids)
- override;
-
- protected:
- DocumentTransitionContentLayerImpl(
- LayerTreeImpl* tree_impl,
- int id,
- const viz::SharedElementResourceId& resource_id,
- bool is_live_content_layer);
-
- private:
- const char* LayerTypeAsString() const override;
-
- const viz::SharedElementResourceId resource_id_;
- const bool is_live_content_layer_;
- bool skip_unseen_resource_quads_ = false;
-};
-
-} // namespace cc
-
-#endif // CC_LAYERS_DOCUMENT_TRANSITION_CONTENT_LAYER_IMPL_H_
diff --git a/chromium/cc/layers/effect_tree_layer_list_iterator.h b/chromium/cc/layers/effect_tree_layer_list_iterator.h
index fb7b879e8bc..2540c5564ad 100644
--- a/chromium/cc/layers/effect_tree_layer_list_iterator.h
+++ b/chromium/cc/layers/effect_tree_layer_list_iterator.h
@@ -75,9 +75,9 @@ class CC_EXPORT EffectTreeLayerListIterator {
struct Position {
State state = State::END;
- LayerImpl* current_layer = nullptr;
- RenderSurfaceImpl* current_render_surface = nullptr;
- RenderSurfaceImpl* target_render_surface = nullptr;
+ raw_ptr<LayerImpl> current_layer = nullptr;
+ raw_ptr<RenderSurfaceImpl> current_render_surface = nullptr;
+ raw_ptr<RenderSurfaceImpl> target_render_surface = nullptr;
};
operator const Position() const {
diff --git a/chromium/cc/layers/heads_up_display_layer_impl.cc b/chromium/cc/layers/heads_up_display_layer_impl.cc
index b24cfcfe67f..bc9d3659532 100644
--- a/chromium/cc/layers/heads_up_display_layer_impl.cc
+++ b/chromium/cc/layers/heads_up_display_layer_impl.cc
@@ -360,12 +360,11 @@ void HeadsUpDisplayLayerImpl::UpdateHudTexture(
auto* backing = static_cast<HudGpuBacking*>(pool_resource.gpu_backing());
const auto& size = pool_resource.size();
- auto display_item_list = base::MakeRefCounted<DisplayItemList>(
- DisplayItemList::kTopLevelDisplayItemList);
- RecordPaintCanvas canvas(display_item_list.get(),
- SkRect::MakeIWH(size.width(), size.height()));
- display_item_list->StartPaint();
+ RecordPaintCanvas canvas;
DrawHudContents(&canvas);
+ auto display_item_list = base::MakeRefCounted<DisplayItemList>();
+ display_item_list->StartPaint();
+ display_item_list->push<DrawRecordOp>(canvas.ReleaseAsRecord());
display_item_list->EndPaintOfUnpaired(gfx::Rect(size));
display_item_list->Finalize();
diff --git a/chromium/cc/layers/layer.cc b/chromium/cc/layers/layer.cc
index 44ed9d841ef..9c42235ec95 100644
--- a/chromium/cc/layers/layer.cc
+++ b/chromium/cc/layers/layer.cc
@@ -36,7 +36,7 @@
#include "cc/trees/transform_node.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/shared_element_resource_id.h"
+#include "components/viz/common/view_transition_element_resource_id.h"
#include "third_party/skia/include/core/SkImageFilter.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/vector2d_conversions.h"
@@ -215,8 +215,8 @@ void Layer::SetDebugName(const std::string& name) {
EnsureDebugInfo().name = name;
}
-viz::SharedElementResourceId Layer::DocumentTransitionResourceId() const {
- return viz::SharedElementResourceId();
+viz::ViewTransitionElementResourceId Layer::ViewTransitionResourceId() const {
+ return viz::ViewTransitionElementResourceId();
}
void Layer::SetNeedsFullTreeSync() {
@@ -933,7 +933,7 @@ bool Are2dAxisAligned(const gfx::Transform& a, const gfx::Transform& b) {
return true;
}
- gfx::Transform inverse(gfx::Transform::kSkipInitialization);
+ gfx::Transform inverse;
if (b.GetInverse(&inverse)) {
inverse *= a;
return inverse.Preserves2dAxisAlignment();
diff --git a/chromium/cc/layers/layer.h b/chromium/cc/layers/layer.h
index 08b05f55485..503ee5e6790 100644
--- a/chromium/cc/layers/layer.h
+++ b/chromium/cc/layers/layer.h
@@ -26,13 +26,14 @@
#include "cc/layers/touch_action_region.h"
#include "cc/paint/element_id.h"
#include "cc/paint/filter_operations.h"
+#include "cc/paint/node_id.h"
#include "cc/paint/paint_record.h"
#include "cc/trees/effect_node.h"
#include "cc/trees/property_tree.h"
#include "cc/trees/target_property.h"
-#include "components/viz/common/shared_element_resource_id.h"
#include "components/viz/common/surfaces/region_capture_bounds.h"
#include "components/viz/common/surfaces/subtree_capture_id.h"
+#include "components/viz/common/view_transition_element_resource_id.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/geometry/linear_gradient.h"
#include "ui/gfx/geometry/point3_f.h"
@@ -842,7 +843,7 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
// If the content of this layer is provided by a cached or live render
// surface, returns the ID of that resource.
- virtual viz::SharedElementResourceId DocumentTransitionResourceId() const;
+ virtual viz::ViewTransitionElementResourceId ViewTransitionResourceId() const;
protected:
friend class LayerImpl;
diff --git a/chromium/cc/layers/layer_impl.h b/chromium/cc/layers/layer_impl.h
index 98a98494406..c7914aeb7a3 100644
--- a/chromium/cc/layers/layer_impl.h
+++ b/chromium/cc/layers/layer_impl.h
@@ -378,9 +378,10 @@ class CC_EXPORT LayerImpl {
// Mark a layer on pending tree that needs to push its properties to the
// active tree. These properties should not be changed during pending tree
// lifetime, and only changed by being pushed from the main thread. There are
- // two cases where this function needs to be called: when main thread layer
- // has properties that need to be pushed, or when a new LayerImpl is created
- // on pending tree when syncing layers from main thread.
+ // three cases where this function needs to be called: when main thread layer
+ // has properties that need to be pushed, when a new LayerImpl is created
+ // on pending tree when syncing layers from main thread, or when we recompute
+ // visible layer properties on the pending tree.
void SetNeedsPushProperties();
virtual void RunMicroBenchmark(MicroBenchmarkImpl* benchmark);
@@ -459,7 +460,8 @@ class CC_EXPORT LayerImpl {
virtual gfx::ContentColorUsage GetContentColorUsage() const;
virtual void NotifyKnownResourceIdsBeforeAppendQuads(
- const base::flat_set<viz::SharedElementResourceId>& known_resource_ids) {}
+ const base::flat_set<viz::ViewTransitionElementResourceId>&
+ known_resource_ids) {}
protected:
// When |will_always_push_properties| is true, the layer will not itself set
diff --git a/chromium/cc/layers/layer_perftest.cc b/chromium/cc/layers/layer_perftest.cc
index 06e8653ee29..5b399a74af8 100644
--- a/chromium/cc/layers/layer_perftest.cc
+++ b/chromium/cc/layers/layer_perftest.cc
@@ -4,7 +4,7 @@
#include "cc/layers/layer.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/task/single_thread_task_runner.h"
#include "base/timer/lap_timer.h"
#include "cc/animation/animation_host.h"
#include "cc/test/fake_impl_task_runner_provider.h"
@@ -37,7 +37,8 @@ class LayerPerfTest : public testing::Test {
layer_tree_host_ = FakeLayerTreeHost::Create(
&fake_client_, &task_graph_runner_, animation_host_.get());
layer_tree_host_->InitializeSingleThreaded(
- &single_thread_client_, base::ThreadTaskRunnerHandle::Get());
+ &single_thread_client_,
+ base::SingleThreadTaskRunner::GetCurrentDefault());
}
void TearDown() override {
diff --git a/chromium/cc/layers/layer_unittest.cc b/chromium/cc/layers/layer_unittest.cc
index ba956329220..2943dafc1b5 100644
--- a/chromium/cc/layers/layer_unittest.cc
+++ b/chromium/cc/layers/layer_unittest.cc
@@ -11,7 +11,7 @@
#include "base/bind.h"
#include "base/containers/contains.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/task/single_thread_task_runner.h"
#include "cc/animation/animation_host.h"
#include "cc/animation/animation_id_provider.h"
#include "cc/base/math_util.h"
@@ -44,17 +44,29 @@
#include "ui/gfx/geometry/transform.h"
#include "ui/gfx/geometry/vector2d_f.h"
+using ::testing::_;
using ::testing::AnyNumber;
using ::testing::AtLeast;
using ::testing::Mock;
using ::testing::StrictMock;
-using ::testing::_;
-#define EXPECT_SET_NEEDS_FULL_TREE_SYNC(expect, code_to_test) \
- do { \
- EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times((expect)); \
- code_to_test; \
- Mock::VerifyAndClearExpectations(layer_tree_host_.get()); \
+#define EXPECT_CALL_MOCK_DELEGATE(obj, call) \
+ EXPECT_CALL((obj).mock_delegate(), call)
+
+#define EXPECT_SET_NEEDS_UPDATE(expect, code_to_test) \
+ do { \
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsUpdateLayers()) \
+ .Times((expect)); \
+ code_to_test; \
+ layer_tree_host_->VerifyAndClearExpectations(); \
+ } while (false)
+
+#define EXPECT_SET_NEEDS_FULL_TREE_SYNC(expect, code_to_test) \
+ do { \
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsFullTreeSync()) \
+ .Times((expect)); \
+ code_to_test; \
+ layer_tree_host_->VerifyAndClearExpectations(); \
} while (false)
#define EXECUTE_AND_VERIFY_SUBTREE_CHANGED(code_to_test) \
@@ -87,19 +99,19 @@ using ::testing::_;
EXPECT_FALSE(child->subtree_property_changed()); \
EXPECT_FALSE(grand_child->subtree_property_changed());
-// TODO(https://crbug.com/1330728): tests should be cleaned up to eliminate
-// mixing of EXPECT_CALL with calls to the mock functions. This method
-// should be deduped with EXPECT_SET_NEEDS_COMMIT as part of this cleanup.
-#define EXPECT_SET_NEEDS_COMMIT_WAS_CALLED(code_to_test) \
- do { \
- code_to_test; \
- EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset()); \
+#define EXPECT_SET_NEEDS_COMMIT_WAS_CALLED(code_to_test) \
+ do { \
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsCommit()) \
+ .Times(AtLeast(1)); \
+ code_to_test; \
+ layer_tree_host_->VerifyAndClearExpectations(); \
} while (false)
-#define EXPECT_SET_NEEDS_COMMIT_WAS_NOT_CALLED(code_to_test) \
- do { \
- code_to_test; \
- EXPECT_FALSE(layer_tree_host_->GetNeedsCommitAndReset()); \
+#define EXPECT_SET_NEEDS_COMMIT_WAS_NOT_CALLED(code_to_test) \
+ do { \
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsCommit()).Times(0); \
+ code_to_test; \
+ layer_tree_host_->VerifyAndClearExpectations(); \
} while (false)
namespace cc {
@@ -111,13 +123,29 @@ static auto kArbitrarySourceId1 =
static auto kArbitrarySourceId2 =
base::UnguessableToken::Deserialize(0xdead, 0xbee0);
-class MockLayerTreeHost : public LayerTreeHost {
+// http://google.github.io/googletest/gmock_for_dummies.html#using-mocks-in-tests
+// says that it is undefined behavior if we alternate between calls to
+// EXPECT_CALL_MOCK_DELEGATE() and calls to the mock functions. It is also
+// undefined behavior if we set new expectations after a call to
+// VerifyAndClearExpectations. So we need a way to make mocking expectations
+// resettable. This delegate object could help achieve that. When we want to
+// reset the expectations, we can delete and recreate the delegate object.
+class MockLayerTreeHostDelegate {
public:
- MockLayerTreeHost(LayerTreeHostSingleThreadClient* single_thread_client,
+ MOCK_METHOD(void, SetNeedsUpdateLayers, (), ());
+ MOCK_METHOD(void, SetNeedsFullTreeSync, (), ());
+ MOCK_METHOD(void, SetNeedsCommit, (), ());
+};
+
+class FakeLayerTreeHost : public LayerTreeHost {
+ public:
+ FakeLayerTreeHost(LayerTreeHostSingleThreadClient* single_thread_client,
LayerTreeHost::InitParams params)
- : LayerTreeHost(std::move(params), CompositorMode::SINGLE_THREADED) {
+ : LayerTreeHost(std::move(params), CompositorMode::SINGLE_THREADED),
+ mock_delegate_(
+ std::make_unique<StrictMock<MockLayerTreeHostDelegate>>()) {
InitializeSingleThreaded(single_thread_client,
- base::ThreadTaskRunnerHandle::Get());
+ base::SingleThreadTaskRunner::GetCurrentDefault());
}
CommitState* GetPendingCommitState() { return pending_commit_state(); }
@@ -125,18 +153,26 @@ class MockLayerTreeHost : public LayerTreeHost {
return thread_unsafe_commit_state();
}
- MOCK_METHOD(void, SetNeedsUpdateLayers, (), (override));
- MOCK_METHOD(void, SetNeedsFullTreeSync, (), (override));
+ void SetNeedsUpdateLayers() override {
+ mock_delegate_->SetNeedsUpdateLayers();
+ }
+ void SetNeedsFullTreeSync() override {
+ mock_delegate_->SetNeedsFullTreeSync();
+ }
+
+ void SetNeedsCommit() override { mock_delegate_->SetNeedsCommit(); }
+
+ StrictMock<MockLayerTreeHostDelegate>& mock_delegate() {
+ return *mock_delegate_;
+ }
- void SetNeedsCommit() override { needs_commit_ = true; }
- bool GetNeedsCommitAndReset() {
- const bool out = needs_commit_;
- needs_commit_ = false;
- return out;
+ void VerifyAndClearExpectations() {
+ mock_delegate_.reset();
+ mock_delegate_ = std::make_unique<StrictMock<MockLayerTreeHostDelegate>>();
}
private:
- bool needs_commit_ = false;
+ std::unique_ptr<StrictMock<MockLayerTreeHostDelegate>> mock_delegate_;
};
bool LayerNeedsDisplay(Layer* layer) {
@@ -168,13 +204,14 @@ class LayerTest : public testing::Test {
params.task_graph_runner = &task_graph_runner_;
params.mutator_host = animation_host_.get();
- layer_tree_host_ = std::make_unique<StrictMock<MockLayerTreeHost>>(
+ layer_tree_host_ = std::make_unique<FakeLayerTreeHost>(
&single_thread_client_, std::move(params));
}
void TearDown() override {
- Mock::VerifyAndClearExpectations(layer_tree_host_.get());
- EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(AnyNumber());
+ layer_tree_host_->VerifyAndClearExpectations();
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsFullTreeSync())
+ .Times(AnyNumber());
parent_ = nullptr;
child1_ = nullptr;
child2_ = nullptr;
@@ -236,7 +273,8 @@ class LayerTest : public testing::Test {
grand_child2_ = Layer::Create();
grand_child3_ = Layer::Create();
- EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(AnyNumber());
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsFullTreeSync())
+ .Times(AnyNumber());
layer_tree_host_->SetRootLayer(parent_);
parent_->AddChild(child1_);
@@ -246,7 +284,7 @@ class LayerTest : public testing::Test {
child1_->AddChild(grand_child2_);
child2_->AddChild(grand_child3_);
- Mock::VerifyAndClearExpectations(layer_tree_host_.get());
+ layer_tree_host_->VerifyAndClearExpectations();
VerifyTestTreeInitialState();
}
@@ -257,7 +295,7 @@ class LayerTest : public testing::Test {
StubLayerTreeHostSingleThreadClient single_thread_client_;
FakeLayerTreeHostClient fake_client_;
- std::unique_ptr<StrictMock<MockLayerTreeHost>> layer_tree_host_;
+ std::unique_ptr<FakeLayerTreeHost> layer_tree_host_;
std::unique_ptr<AnimationHost> animation_host_;
scoped_refptr<Layer> parent_;
scoped_refptr<Layer> child1_;
@@ -288,7 +326,8 @@ TEST_F(LayerTest, BasicCreateAndDestroy) {
}
TEST_F(LayerTest, LayerPropertyChangedForSubtree) {
- EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(AtLeast(1));
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsFullTreeSync())
+ .Times(AtLeast(1));
scoped_refptr<Layer> root = Layer::Create();
scoped_refptr<Layer> top = Layer::Create();
scoped_refptr<Layer> child = Layer::Create();
@@ -305,11 +344,13 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) {
child->AddChild(grand_child);
// To force a transform node for |top|.
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsCommit())
+ .Times(AtLeast(1));
gfx::Transform top_transform;
top_transform.Scale3d(1, 2, 3);
top->SetTransform(top_transform);
child->SetForceRenderSurfaceForTesting(true);
- EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset());
+ layer_tree_host_->VerifyAndClearExpectations();
// Resizing without a mask layer or masks_to_bounds, should only require a
// regular commit. Note that a layer and its mask should match sizes, but
@@ -318,11 +359,14 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) {
EXPECT_SET_NEEDS_COMMIT_WAS_CALLED(top->SetBounds(arbitrary_size));
EXPECT_SET_NEEDS_COMMIT_WAS_NOT_CALLED(
mask_layer1->SetBounds(arbitrary_size));
- EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync());
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsFullTreeSync());
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsCommit())
+ .Times(AtLeast(1));
layer_tree_host_->WillCommit(/*completion=*/nullptr,
/*has_updates=*/true);
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(top->SetMaskLayer(mask_layer1));
layer_tree_host_->CommitComplete({base::TimeTicks(), base::TimeTicks::Now()});
+ layer_tree_host_->VerifyAndClearExpectations();
// Set up the impl layers after the full tree is constructed, including the
// mask layer.
@@ -356,15 +400,18 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) {
// Once there is a mask layer, resizes require subtree properties to update.
arbitrary_size = gfx::Size(11, 22);
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsCommit()).Times(2);
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(top->SetBounds(arbitrary_size));
- EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset());
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(mask_layer1->SetBounds(arbitrary_size));
- EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset());
+ layer_tree_host_->VerifyAndClearExpectations();
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsCommit()).Times(1);
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(top->SetMasksToBounds(true));
+ layer_tree_host_->VerifyAndClearExpectations();
commit_state = layer_tree_host_->WillCommit(/*completion=*/nullptr,
/*has_updates=*/true);
+
EXECUTE_AND_VERIFY_SUBTREE_CHANGES_RESET(
top->PushPropertiesTo(top_impl.get(), *commit_state, unsafe_state);
child->PushPropertiesTo(child_impl.get(), *commit_state, unsafe_state);
@@ -372,10 +419,10 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) {
grand_child->PushPropertiesTo(grand_child_impl.get(), *commit_state,
unsafe_state));
layer_tree_host_->CommitComplete({base::TimeTicks(), base::TimeTicks::Now()});
- EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset());
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsCommit()).Times(1);
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(top->SetContentsOpaque(true));
- EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset());
+ layer_tree_host_->VerifyAndClearExpectations();
commit_state = layer_tree_host_->WillCommit(/*completion=*/nullptr,
/*has_updates=*/true);
@@ -387,8 +434,9 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) {
unsafe_state));
layer_tree_host_->CommitComplete({base::TimeTicks(), base::TimeTicks::Now()});
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsCommit()).Times(1);
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(top->SetTrilinearFiltering(true));
- EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset());
+ layer_tree_host_->VerifyAndClearExpectations();
commit_state = layer_tree_host_->WillCommit(/*completion=*/nullptr,
/*has_updates=*/true);
@@ -400,8 +448,9 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) {
unsafe_state));
layer_tree_host_->CommitComplete({base::TimeTicks(), base::TimeTicks::Now()});
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsCommit()).Times(1);
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(top->SetTrilinearFiltering(false));
- EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset());
+ layer_tree_host_->VerifyAndClearExpectations();
commit_state = layer_tree_host_->WillCommit(/*completion=*/nullptr,
/*has_updates=*/true);
@@ -413,10 +462,10 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) {
unsafe_state));
layer_tree_host_->CommitComplete({base::TimeTicks(), base::TimeTicks::Now()});
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsCommit()).Times(2);
top->SetRoundedCorner({1, 2, 3, 4});
- EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset());
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(top->SetIsFastRoundedCorner(true));
- EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset());
+ layer_tree_host_->VerifyAndClearExpectations();
commit_state = layer_tree_host_->WillCommit(/*completion=*/nullptr,
/*has_updates=*/true);
@@ -428,8 +477,9 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) {
unsafe_state));
layer_tree_host_->CommitComplete({base::TimeTicks(), base::TimeTicks::Now()});
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsCommit()).Times(1);
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(top->SetHideLayerAndSubtree(true));
- EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset());
+ layer_tree_host_->VerifyAndClearExpectations();
commit_state = layer_tree_host_->WillCommit(/*completion=*/nullptr,
/*has_updates=*/true);
@@ -441,8 +491,9 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) {
unsafe_state));
layer_tree_host_->CommitComplete({base::TimeTicks(), base::TimeTicks::Now()});
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsCommit()).Times(1);
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(top->SetBlendMode(arbitrary_blend_mode));
- EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset());
+ layer_tree_host_->VerifyAndClearExpectations();
commit_state = layer_tree_host_->WillCommit(/*completion=*/nullptr,
/*has_updates=*/true);
@@ -457,10 +508,10 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) {
// Should be a different size than previous call, to ensure it marks tree
// changed.
arbitrary_size = gfx::Size(111, 222);
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsCommit()).Times(2);
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(top->SetBounds(arbitrary_size));
- EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset());
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(mask_layer1->SetBounds(arbitrary_size));
- EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset());
+ layer_tree_host_->VerifyAndClearExpectations();
commit_state = layer_tree_host_->WillCommit(/*completion=*/nullptr,
/*has_updates=*/true);
@@ -474,8 +525,9 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) {
FilterOperations arbitrary_filters;
arbitrary_filters.Append(FilterOperation::CreateOpacityFilter(0.5f));
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsCommit()).Times(1);
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(top->SetFilters(arbitrary_filters));
- EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset());
+ layer_tree_host_->VerifyAndClearExpectations();
commit_state = layer_tree_host_->WillCommit(/*completion=*/nullptr,
/*has_updates=*/true);
@@ -487,6 +539,7 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) {
unsafe_state));
layer_tree_host_->CommitComplete({base::TimeTicks(), base::TimeTicks::Now()});
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsCommit()).Times(2);
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(
top->SetBackdropFilters(arbitrary_filters));
@@ -499,9 +552,10 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) {
grand_child->PushPropertiesTo(grand_child_impl.get(), *commit_state,
unsafe_state));
layer_tree_host_->CommitComplete({base::TimeTicks(), base::TimeTicks::Now()});
- EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset());
+ layer_tree_host_->VerifyAndClearExpectations();
gfx::PointF arbitrary_point_f = gfx::PointF(0.125f, 0.25f);
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsCommit()).Times(1);
top->SetPosition(arbitrary_point_f);
TransformNode* node =
layer_tree_host_->property_trees()->transform_tree_mutable().Node(
@@ -519,13 +573,14 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) {
layer_tree_host_->property_trees()->ResetAllChangeTracking());
layer_tree_host_->CommitComplete({base::TimeTicks(), base::TimeTicks::Now()});
EXPECT_FALSE(node->transform_changed);
- EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset());
+ layer_tree_host_->VerifyAndClearExpectations();
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsCommit()).Times(1);
child->SetPosition(arbitrary_point_f);
node = layer_tree_host_->property_trees()->transform_tree_mutable().Node(
child->transform_tree_index());
EXPECT_TRUE(node->transform_changed);
- EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset());
+ layer_tree_host_->VerifyAndClearExpectations();
commit_state = layer_tree_host_->WillCommit(/*completion=*/nullptr,
/*has_updates=*/true);
@@ -540,11 +595,12 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) {
EXPECT_FALSE(node->transform_changed);
gfx::Point3F arbitrary_point_3f = gfx::Point3F(0.125f, 0.25f, 0.f);
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsCommit()).Times(1);
top->SetTransformOrigin(arbitrary_point_3f);
node = layer_tree_host_->property_trees()->transform_tree_mutable().Node(
top->transform_tree_index());
EXPECT_TRUE(node->transform_changed);
- EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset());
+ layer_tree_host_->VerifyAndClearExpectations();
commit_state = layer_tree_host_->WillCommit(/*completion=*/nullptr,
/*has_updates=*/true);
@@ -559,11 +615,12 @@ TEST_F(LayerTest, LayerPropertyChangedForSubtree) {
gfx::Transform arbitrary_transform;
arbitrary_transform.Scale3d(0.1f, 0.2f, 0.3f);
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsCommit()).Times(1);
top->SetTransform(arbitrary_transform);
node = layer_tree_host_->property_trees()->transform_tree_mutable().Node(
top->transform_tree_index());
EXPECT_TRUE(node->transform_changed);
- EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset());
+ layer_tree_host_->VerifyAndClearExpectations();
}
TEST_F(LayerTest, AddAndRemoveChild) {
@@ -655,7 +712,8 @@ TEST_F(LayerTest, AddChildAfterSetMaskLayer) {
}
TEST_F(LayerTest, AddSameChildTwice) {
- EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(AtLeast(1));
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsFullTreeSync())
+ .Times(AtLeast(1));
scoped_refptr<Layer> parent = Layer::Create();
scoped_refptr<Layer> child = Layer::Create();
@@ -674,7 +732,8 @@ TEST_F(LayerTest, AddSameChildTwice) {
}
TEST_F(LayerTest, ReorderChildren) {
- EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(AtLeast(1));
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsFullTreeSync())
+ .Times(AtLeast(1));
scoped_refptr<Layer> parent = Layer::Create();
scoped_refptr<Layer> child1 = Layer::Create();
@@ -900,7 +959,8 @@ TEST_F(LayerTest, GetRootLayerAfterTreeManipulations) {
CreateSimpleTestTree();
// For this test we don't care about SetNeedsFullTreeSync calls.
- EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(AnyNumber());
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsFullTreeSync())
+ .Times(AnyNumber());
scoped_refptr<Layer> child4 = Layer::Create();
@@ -1062,14 +1122,16 @@ TEST_F(LayerTest, CheckPropertyChangeCausesCorrectBehavior) {
base::flat_map<viz::RegionCaptureCropId, gfx::Rect>{
{viz::RegionCaptureCropId(123u, 456u),
gfx::Rect(0, 0, 640, 480)}})));
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsCommit()).Times(1);
EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, test_layer->SetMaskLayer(mask_layer1));
- EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset());
+ layer_tree_host_->VerifyAndClearExpectations();
// The above tests should not have caused a change to the needs_display
// flag.
EXPECT_FALSE(LayerNeedsDisplay(test_layer.get()));
// As layers are removed from the tree, they will cause a tree sync.
- EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times((AnyNumber()));
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsFullTreeSync())
+ .Times((AnyNumber()));
}
TEST_F(LayerTest, PushPropertiesAccumulatesUpdateRect) {
@@ -1191,7 +1253,7 @@ class LayerTreeHostFactory {
params.client = &client_;
params.task_graph_runner = &task_graph_runner_;
params.settings = &settings;
- params.main_task_runner = base::ThreadTaskRunnerHandle::Get();
+ params.main_task_runner = base::SingleThreadTaskRunner::GetCurrentDefault();
params.mutator_host = mutator_host;
return LayerTreeHost::CreateSingleThreaded(&single_thread_client_,
@@ -1466,6 +1528,7 @@ TEST_F(LayerTest, PushUpdatesShouldHitTest) {
LayerImpl::Create(host_impl_.active_tree(), 1);
EXPECT_SET_NEEDS_FULL_TREE_SYNC(1,
layer_tree_host_->SetRootLayer(root_layer));
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsCommit()).Times(5);
// A layer that draws content should be hit testable.
root_layer->SetIsDrawable(true);
@@ -1473,7 +1536,6 @@ TEST_F(LayerTest, PushUpdatesShouldHitTest) {
CommitAndPushProperties(root_layer.get(), impl_layer.get());
EXPECT_TRUE(impl_layer->draws_content());
EXPECT_TRUE(impl_layer->HitTestable());
- EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset());
// A layer that does not draw content and does not hit test without drawing
// content should not be hit testable.
@@ -1482,7 +1544,6 @@ TEST_F(LayerTest, PushUpdatesShouldHitTest) {
CommitAndPushProperties(root_layer.get(), impl_layer.get());
EXPECT_FALSE(impl_layer->draws_content());
EXPECT_FALSE(impl_layer->HitTestable());
- EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset());
// |SetHitTestableWithoutDrawsContent| should cause a layer to become hit
// testable even though it does not draw content.
@@ -1490,7 +1551,6 @@ TEST_F(LayerTest, PushUpdatesShouldHitTest) {
CommitAndPushProperties(root_layer.get(), impl_layer.get());
EXPECT_FALSE(impl_layer->draws_content());
EXPECT_TRUE(impl_layer->HitTestable());
- EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset());
}
void ReceiveCopyOutputResult(int* result_count,
@@ -1616,24 +1676,24 @@ TEST_F(LayerTest, AnimationSchedulesLayerUpdate) {
EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, layer_tree_host_->SetRootLayer(layer));
auto element_id = layer->element_id();
- EXPECT_CALL(*layer_tree_host_, SetNeedsUpdateLayers());
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsUpdateLayers());
layer_tree_host_->SetElementOpacityMutated(element_id,
ElementListType::ACTIVE, 0.5f);
- Mock::VerifyAndClearExpectations(layer_tree_host_.get());
+ layer_tree_host_->VerifyAndClearExpectations();
- EXPECT_CALL(*layer_tree_host_, SetNeedsUpdateLayers());
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsUpdateLayers());
gfx::Transform transform;
transform.Rotate(45.0);
layer_tree_host_->SetElementTransformMutated(
element_id, ElementListType::ACTIVE, transform);
- Mock::VerifyAndClearExpectations(layer_tree_host_.get());
+ layer_tree_host_->VerifyAndClearExpectations();
// Scroll offset animation should not schedule a layer update since it is
// handled similarly to normal compositor scroll updates.
- EXPECT_CALL(*layer_tree_host_, SetNeedsUpdateLayers()).Times(0);
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsUpdateLayers()).Times(0);
layer_tree_host_->SetElementScrollOffsetMutated(
element_id, ElementListType::ACTIVE, gfx::PointF(10, 10));
- Mock::VerifyAndClearExpectations(layer_tree_host_.get());
+ layer_tree_host_->VerifyAndClearExpectations();
}
TEST_F(LayerTest, ElementIdIsPushed) {
@@ -1644,12 +1704,13 @@ TEST_F(LayerTest, ElementIdIsPushed) {
EXPECT_SET_NEEDS_FULL_TREE_SYNC(1,
layer_tree_host_->SetRootLayer(test_layer));
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsCommit()).Times(1);
+
test_layer->SetElementId(ElementId(2));
EXPECT_FALSE(impl_layer->element_id());
CommitAndPushProperties(test_layer.get(), impl_layer.get());
EXPECT_EQ(ElementId(2), impl_layer->element_id());
- EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset());
}
TEST_F(LayerTest, SetLayerTreeHostNotUsingLayerListsManagesElementId) {
@@ -1659,6 +1720,7 @@ TEST_F(LayerTest, SetLayerTreeHostNotUsingLayerListsManagesElementId) {
// Expect additional calls due to has-animation check and initialization
// of keyframes.
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsCommit()).Times(3);
scoped_refptr<AnimationTimeline> timeline =
AnimationTimeline::Create(AnimationIdProvider::NextTimelineId());
animation_host_->AddAnimationTimeline(timeline);
@@ -1666,13 +1728,11 @@ TEST_F(LayerTest, SetLayerTreeHostNotUsingLayerListsManagesElementId) {
AddOpacityTransitionToElementWithAnimation(element_id, timeline, 10.0, 1.f,
0.f, false);
EXPECT_TRUE(animation_host_->IsElementAnimating(element_id));
- EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset());
EXPECT_EQ(nullptr, layer_tree_host_->LayerByElementId(element_id));
test_layer->SetLayerTreeHost(layer_tree_host_.get());
// Layer should now be registered by element id.
EXPECT_EQ(test_layer, layer_tree_host_->LayerByElementId(element_id));
- EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset());
// We're expected to remove the animations before calling
// SetLayerTreeHost(nullptr).
@@ -1687,6 +1747,7 @@ TEST_F(LayerTest, SetLayerTreeHostNotUsingLayerListsManagesElementId) {
// compositor is expensive and updated counts can wait until the next
// commit to be pushed. See https://crbug.com/1083244.
TEST_F(LayerTest, PushAnimationCountsLazily) {
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsCommit()).Times(0);
animation_host_->SetAnimationCounts(0);
animation_host_->SetCurrentFrameHadRaf(true);
animation_host_->SetNextFrameHasPendingRaf(true);
@@ -1698,20 +1759,19 @@ TEST_F(LayerTest, PushAnimationCountsLazily) {
*layer_tree_host_->property_trees());
EXPECT_TRUE(host_impl_.animation_host()->CurrentFrameHadRAF());
EXPECT_TRUE(host_impl_.animation_host()->HasSmilAnimation());
- EXPECT_FALSE(layer_tree_host_->GetNeedsCommitAndReset());
}
TEST_F(LayerTest, SetElementIdNotUsingLayerLists) {
scoped_refptr<Layer> test_layer = Layer::Create();
test_layer->SetLayerTreeHost(layer_tree_host_.get());
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsCommit()).Times(2);
ElementId element_id = ElementId(2);
EXPECT_EQ(nullptr, layer_tree_host_->LayerByElementId(element_id));
test_layer->SetElementId(element_id);
// Layer should now be registered by element id.
EXPECT_EQ(test_layer, layer_tree_host_->LayerByElementId(element_id));
- EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset());
ElementId other_element_id = ElementId(3);
test_layer->SetElementId(other_element_id);
@@ -1721,7 +1781,6 @@ TEST_F(LayerTest, SetElementIdNotUsingLayerLists) {
EXPECT_EQ(test_layer, layer_tree_host_->LayerByElementId(other_element_id));
test_layer->SetLayerTreeHost(nullptr);
- EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset());
}
// Verifies that when mirror count of the layer is incremented or decremented,
@@ -1795,8 +1854,11 @@ TEST_F(LayerTest, UpdatingCaptureBounds) {
base::flat_map<viz::RegionCaptureCropId, gfx::Rect>{
{viz::RegionCaptureCropId(123u, 456u), gfx::Rect(0, 0, 1280, 720)}});
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsCommit()).Times(3);
+
// We don't track full tree syncs in this test.
- EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(AtLeast(1));
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsFullTreeSync())
+ .Times(AtLeast(1));
scoped_refptr<Layer> layer = Layer::Create();
layer_tree_host_->SetRootLayer(layer);
@@ -1809,13 +1871,11 @@ TEST_F(LayerTest, UpdatingCaptureBounds) {
layer->SetCaptureBounds(kEmptyBounds);
EXPECT_FALSE(layer_tree_host_->property_trees()->needs_rebuild());
EXPECT_FALSE(layer->subtree_property_changed());
- EXPECT_FALSE(layer_tree_host_->GetNeedsCommitAndReset());
// Setting to a new bounds should cause an update.
layer->SetCaptureBounds(kPopulatedBounds);
EXPECT_TRUE(layer_tree_host_->property_trees()->needs_rebuild());
EXPECT_TRUE(layer->subtree_property_changed());
- EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset());
// Reset properties.
layer->ClearSubtreePropertyChangedForTesting();
@@ -1825,13 +1885,11 @@ TEST_F(LayerTest, UpdatingCaptureBounds) {
layer->SetCaptureBounds(kPopulatedBounds);
EXPECT_FALSE(layer_tree_host_->property_trees()->needs_rebuild());
EXPECT_FALSE(layer->subtree_property_changed());
- EXPECT_FALSE(layer_tree_host_->GetNeedsCommitAndReset());
// Switching to a differently valued bounds should cause an update.
layer->SetCaptureBounds(kUpdatedBounds);
EXPECT_TRUE(layer_tree_host_->property_trees()->needs_rebuild());
EXPECT_TRUE(layer->subtree_property_changed());
- EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset());
// Reset properties.
layer->ClearSubtreePropertyChangedForTesting();
@@ -1841,7 +1899,6 @@ TEST_F(LayerTest, UpdatingCaptureBounds) {
layer->SetCaptureBounds(kEmptyBounds);
EXPECT_TRUE(layer_tree_host_->property_trees()->needs_rebuild());
EXPECT_TRUE(layer->subtree_property_changed());
- EXPECT_TRUE(layer_tree_host_->GetNeedsCommitAndReset());
}
TEST_F(LayerTest, UpdatingClipRect) {
@@ -1861,7 +1918,10 @@ TEST_F(LayerTest, UpdatingClipRect) {
scoped_refptr<Layer> clipped_3 = Layer::Create();
scoped_refptr<Layer> clipped_4 = Layer::Create();
- EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(AtLeast(1));
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsFullTreeSync())
+ .Times(AtLeast(1));
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsCommit())
+ .Times(AtLeast(1));
layer_tree_host_->SetRootLayer(root);
root->AddChild(parent);
parent->AddChild(clipped_1);
@@ -1966,7 +2026,11 @@ TEST_F(LayerTest, UpdatingRoundedCorners) {
scoped_refptr<Layer> layer_4 = Layer::Create();
scoped_refptr<Layer> layer_5 = Layer::Create();
- EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(AtLeast(1));
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsFullTreeSync())
+ .Times(AtLeast(1));
+ EXPECT_CALL_MOCK_DELEGATE(*layer_tree_host_, SetNeedsCommit())
+ .Times(AtLeast(1));
+
layer_tree_host_->SetRootLayer(root);
root->AddChild(layer_1);
root->AddChild(layer_2);
diff --git a/chromium/cc/layers/picture_layer_impl.cc b/chromium/cc/layers/picture_layer_impl.cc
index c11493bb5ab..ebc1200658c 100644
--- a/chromium/cc/layers/picture_layer_impl.cc
+++ b/chromium/cc/layers/picture_layer_impl.cc
@@ -684,7 +684,7 @@ void PictureLayerImpl::UpdateViewportRectForTilePriorityInContentSpace() {
if (visible_rect_in_content_space.IsEmpty() ||
layer_tree_impl()->GetDeviceViewport() !=
viewport_rect_for_tile_priority) {
- gfx::Transform view_to_layer(gfx::Transform::kSkipInitialization);
+ gfx::Transform view_to_layer;
if (ScreenSpaceTransform().GetInverse(&view_to_layer)) {
// Transform from view space to content space.
visible_rect_in_content_space = MathUtil::ProjectEnclosingClippedRect(
@@ -1229,6 +1229,25 @@ void PictureLayerImpl::RemoveAllTilings() {
bool PictureLayerImpl::CanRecreateHighResTilingForLCDTextAndRasterTransform(
const PictureLayerTiling& high_res) const {
+ // Prefer re-rasterization for a change in LCD status from the following
+ // reasons since visual artifacts of LCD text on non-opaque background are
+ // very noticeable. This state also only changes during a commit and is likely
+ // to be discrete as opposed to every frame of the animation.
+ if (high_res.can_use_lcd_text() &&
+ (lcd_text_disallowed_reason_ ==
+ LCDTextDisallowedReason::kBackgroundColorNotOpaque ||
+ lcd_text_disallowed_reason_ ==
+ LCDTextDisallowedReason::kContentsNotOpaque)) {
+ // LCD text state changes require a commit and the existing tiling is
+ // invalidated before scheduling rasterization work for the new pending
+ // tree. So it shouldn't be possible for the new pending tree to be ready to
+ // activate before we have invalidated the existing high rest tiling. This
+ // is important to avoid activating a tree with missing tiles which can
+ // cause flickering.
+ DCHECK(!layer_tree_impl()->IsSyncTree() ||
+ !layer_tree_impl()->IsReadyToActivate());
+ return true;
+ }
// We can recreate the tiling if we would invalidate all of its tiles.
if (high_res.may_contain_low_resolution_tiles())
return true;
diff --git a/chromium/cc/layers/picture_layer_impl_perftest.cc b/chromium/cc/layers/picture_layer_impl_perftest.cc
index 525e64351f9..0cfa4f3eb43 100644
--- a/chromium/cc/layers/picture_layer_impl_perftest.cc
+++ b/chromium/cc/layers/picture_layer_impl_perftest.cc
@@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/memory/raw_ptr.h"
#include "cc/layers/picture_layer_impl.h"
+#include "base/memory/raw_ptr.h"
+#include "base/ranges/algorithm.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/timer/lap_timer.h"
#include "cc/test/fake_picture_layer_impl.h"
@@ -31,8 +32,7 @@ void AddTiling(float scale,
tiling->set_resolution(HIGH_RESOLUTION);
tiling->CreateAllTilesForTesting();
std::vector<Tile*> tiling_tiles = tiling->AllTilesForTesting();
- std::copy(
- tiling_tiles.begin(), tiling_tiles.end(), std::back_inserter(*all_tiles));
+ base::ranges::copy(tiling_tiles, std::back_inserter(*all_tiles));
}
class PictureLayerImplPerfTest : public LayerTreeImplTestBase,
diff --git a/chromium/cc/layers/picture_layer_unittest.cc b/chromium/cc/layers/picture_layer_unittest.cc
index d3925bf6f17..821825c9dc9 100644
--- a/chromium/cc/layers/picture_layer_unittest.cc
+++ b/chromium/cc/layers/picture_layer_unittest.cc
@@ -8,7 +8,7 @@
#include <utility>
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/task/single_thread_task_runner.h"
#include "cc/animation/animation_host.h"
#include "cc/base/completion_event.h"
#include "cc/layers/append_quads_data.h"
@@ -266,7 +266,7 @@ TEST(PictureLayerTest, NonMonotonicSourceFrameNumber) {
params.client = &host_client1;
params.settings = &settings;
params.task_graph_runner = &task_graph_runner;
- params.main_task_runner = base::ThreadTaskRunnerHandle::Get();
+ params.main_task_runner = base::SingleThreadTaskRunner::GetCurrentDefault();
params.mutator_host = animation_host.get();
std::unique_ptr<LayerTreeHost> host1 = LayerTreeHost::CreateSingleThreaded(
&single_thread_client, std::move(params));
@@ -279,7 +279,7 @@ TEST(PictureLayerTest, NonMonotonicSourceFrameNumber) {
params2.client = &host_client1;
params2.settings = &settings;
params2.task_graph_runner = &task_graph_runner;
- params2.main_task_runner = base::ThreadTaskRunnerHandle::Get();
+ params2.main_task_runner = base::SingleThreadTaskRunner::GetCurrentDefault();
params2.client = &host_client2;
params2.mutator_host = animation_host2.get();
std::unique_ptr<LayerTreeHost> host2 = LayerTreeHost::CreateSingleThreaded(
@@ -338,7 +338,7 @@ TEST(PictureLayerTest, ChangingHostsWithCollidingFrames) {
params.client = &host_client1;
params.settings = &settings;
params.task_graph_runner = &task_graph_runner;
- params.main_task_runner = base::ThreadTaskRunnerHandle::Get();
+ params.main_task_runner = base::SingleThreadTaskRunner::GetCurrentDefault();
params.mutator_host = animation_host.get();
std::unique_ptr<LayerTreeHost> host1 = LayerTreeHost::CreateSingleThreaded(
&single_thread_client, std::move(params));
@@ -351,7 +351,7 @@ TEST(PictureLayerTest, ChangingHostsWithCollidingFrames) {
params2.client = &host_client1;
params2.settings = &settings;
params2.task_graph_runner = &task_graph_runner;
- params2.main_task_runner = base::ThreadTaskRunnerHandle::Get();
+ params2.main_task_runner = base::SingleThreadTaskRunner::GetCurrentDefault();
params2.client = &host_client2;
params2.mutator_host = animation_host2.get();
std::unique_ptr<LayerTreeHost> host2 = LayerTreeHost::CreateSingleThreaded(
diff --git a/chromium/cc/layers/render_surface_impl.cc b/chromium/cc/layers/render_surface_impl.cc
index e7cbb0025b0..615819685ae 100644
--- a/chromium/cc/layers/render_surface_impl.cc
+++ b/chromium/cc/layers/render_surface_impl.cc
@@ -19,7 +19,6 @@
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/occlusion.h"
#include "cc/trees/transform_node.h"
-#include "components/viz/common/display/de_jelly.h"
#include "components/viz/common/quads/compositor_render_pass.h"
#include "components/viz/common/quads/compositor_render_pass_draw_quad.h"
#include "components/viz/common/quads/content_draw_quad_base.h"
@@ -174,7 +173,7 @@ bool RenderSurfaceImpl::ShouldCacheRenderSurface() const {
bool RenderSurfaceImpl::CopyOfOutputRequired() const {
return HasCopyRequest() || ShouldCacheRenderSurface() ||
SubtreeCaptureId().is_valid() ||
- OwningEffectNode()->shared_element_resource_id.IsValid();
+ OwningEffectNode()->view_transition_element_resource_id.IsValid();
}
int RenderSurfaceImpl::TransformTreeIndex() const {
@@ -194,9 +193,9 @@ const EffectNode* RenderSurfaceImpl::OwningEffectNode() const {
EffectTreeIndex());
}
-const DocumentTransitionSharedElementId&
-RenderSurfaceImpl::GetDocumentTransitionSharedElementId() const {
- return OwningEffectNode()->document_transition_shared_element_id;
+const ViewTransitionElementId& RenderSurfaceImpl::GetViewTransitionElementId()
+ const {
+ return OwningEffectNode()->view_transition_shared_element_id;
}
void RenderSurfaceImpl::SetClipRect(const gfx::Rect& clip_rect) {
@@ -240,7 +239,7 @@ gfx::Rect RenderSurfaceImpl::CalculateClippedAccumulatedContentRect() {
// Calculate projection from the target surface rect to local
// space. Non-invertible draw transforms means no able to bring clipped rect
// in target space back to local space, early out without clip.
- gfx::Transform target_to_surface(gfx::Transform::kSkipInitialization);
+ gfx::Transform target_to_surface;
if (!draw_transform().GetInverse(&target_to_surface))
return accumulated_content_rect();
@@ -261,10 +260,6 @@ gfx::Rect RenderSurfaceImpl::CalculateClippedAccumulatedContentRect() {
} else {
clipped_accumulated_rect_in_target_space = clip_rect();
}
- if (layer_tree_impl_->settings().allow_de_jelly_effect) {
- clipped_accumulated_rect_in_target_space.Inset(
- gfx::Insets::VH(-viz::MaxDeJellyHeight(), 0));
- }
clipped_accumulated_rect_in_target_space.Intersect(
accumulated_rect_in_target_space);
@@ -337,7 +332,7 @@ void RenderSurfaceImpl::AccumulateContentRectFromContributingRenderSurface(
// If this surface is a shared element id then it is being used to generate an
// independent snapshot and won't contribute to its target surface.
if (contributing_surface->OwningEffectNode()
- ->shared_element_resource_id.IsValid())
+ ->view_transition_element_resource_id.IsValid())
return;
// The content rect of contributing surface is in its own space. Instead, we
@@ -425,8 +420,8 @@ RenderSurfaceImpl::CreateRenderPass() {
pass->cache_render_pass = ShouldCacheRenderSurface();
pass->has_damage_from_contributing_content =
HasDamageFromeContributingContent();
- pass->shared_element_resource_id =
- OwningEffectNode()->shared_element_resource_id;
+ pass->view_transition_element_resource_id =
+ OwningEffectNode()->view_transition_element_resource_id;
return pass;
}
@@ -438,10 +433,10 @@ void RenderSurfaceImpl::AppendQuads(DrawMode draw_mode,
if (unoccluded_content_rect.IsEmpty())
return;
- // If this render surface has a valid |shared_element_resource_id| then its
- // being used to produce live content. Its content will be drawn to its
- // actual position in the Viz process.
- if (OwningEffectNode()->shared_element_resource_id.IsValid())
+ // If this render surface has a valid |view_transition_element_resource_id|
+ // then its being used to produce live content. Its content will be drawn to
+ // its actual position in the Viz process.
+ if (OwningEffectNode()->view_transition_element_resource_id.IsValid())
return;
const PropertyTrees* property_trees = layer_tree_impl_->property_trees();
diff --git a/chromium/cc/layers/render_surface_impl.h b/chromium/cc/layers/render_surface_impl.h
index 2534505f593..2e21ab54ea1 100644
--- a/chromium/cc/layers/render_surface_impl.h
+++ b/chromium/cc/layers/render_surface_impl.h
@@ -14,11 +14,11 @@
#include "base/memory/raw_ptr.h"
#include "cc/cc_export.h"
-#include "cc/document_transition/document_transition_shared_element_id.h"
#include "cc/layers/draw_mode.h"
#include "cc/layers/layer_collections.h"
#include "cc/trees/occlusion.h"
#include "cc/trees/property_tree.h"
+#include "cc/view_transition/view_transition_shared_element_id.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"
@@ -240,8 +240,7 @@ class CC_EXPORT RenderSurfaceImpl {
const EffectNode* OwningEffectNode() const;
- const DocumentTransitionSharedElementId&
- GetDocumentTransitionSharedElementId() const;
+ const ViewTransitionElementId& GetViewTransitionElementId() const;
private:
void SetContentRect(const gfx::Rect& content_rect);
@@ -303,7 +302,8 @@ class CC_EXPORT RenderSurfaceImpl {
// The nearest ancestor target surface that will contain the contents of this
// surface, and that ignores outside occlusion. This can point to itself.
- raw_ptr<const RenderSurfaceImpl> nearest_occlusion_immune_ancestor_;
+ raw_ptr<const RenderSurfaceImpl, DanglingUntriaged>
+ nearest_occlusion_immune_ancestor_;
std::unique_ptr<DamageTracker> damage_tracker_;
};
diff --git a/chromium/cc/layers/scrollbar_layer_unittest.cc b/chromium/cc/layers/scrollbar_layer_unittest.cc
index 6ef0a463468..c78687df04f 100644
--- a/chromium/cc/layers/scrollbar_layer_unittest.cc
+++ b/chromium/cc/layers/scrollbar_layer_unittest.cc
@@ -8,7 +8,7 @@
#include <unordered_map>
#include "base/memory/raw_ptr.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/task/single_thread_task_runner.h"
#include "cc/animation/animation_host.h"
#include "cc/input/scrollbar_animation_controller.h"
#include "cc/layers/append_quads_data.h"
@@ -127,7 +127,8 @@ class BaseScrollbarLayerTest : public testing::Test {
layer_tree_host_->SetUIResourceManagerForTesting(
std::move(fake_ui_resource_manager));
layer_tree_host_->InitializeSingleThreaded(
- &single_thread_client_, base::ThreadTaskRunnerHandle::Get());
+ &single_thread_client_,
+ base::SingleThreadTaskRunner::GetCurrentDefault());
layer_tree_host_->SetVisible(true);
fake_client_.SetLayerTreeHost(layer_tree_host_.get());
}
@@ -1423,7 +1424,7 @@ TEST_F(ScaledScrollbarLayerTestResourceCreation, ScaledResourceUpload) {
// Keep the max texture size reasonable so we don't OOM on low end devices
// (crbug.com/642333).
context->UnboundTestContextGL()->set_max_texture_size(512);
- context->BindToCurrentThread();
+ context->BindToCurrentSequence();
int max_texture_size = 0;
context->ContextGL()->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
EXPECT_EQ(512, max_texture_size);
diff --git a/chromium/cc/layers/texture_layer.cc b/chromium/cc/layers/texture_layer.cc
index 4c2704b9392..f7c6b66315c 100644
--- a/chromium/cc/layers/texture_layer.cc
+++ b/chromium/cc/layers/texture_layer.cc
@@ -78,10 +78,14 @@ void TextureLayer::SetUV(const gfx::PointF& top_left,
SetNeedsCommit();
}
-void TextureLayer::SetHDRMetadata(
+void TextureLayer::SetHDRConfiguration(
+ gfx::HDRMode hdr_mode,
absl::optional<gfx::HDRMetadata> hdr_metadata) {
- if (hdr_metadata_.Read(*this) == hdr_metadata)
+ if (hdr_mode_.Read(*this) == hdr_mode &&
+ hdr_metadata_.Read(*this) == hdr_metadata) {
return;
+ }
+ hdr_mode_.Write(*this) = hdr_mode;
hdr_metadata_.Write(*this) = hdr_metadata;
SetNeedsCommit();
}
@@ -215,7 +219,8 @@ void TextureLayer::PushPropertiesTo(
texture_layer->SetPremultipliedAlpha(premultiplied_alpha_.Read(*this));
texture_layer->SetBlendBackgroundColor(blend_background_color_.Read(*this));
texture_layer->SetForceTextureToOpaque(force_texture_to_opaque_.Read(*this));
- texture_layer->SetHDRMetadata(hdr_metadata_.Read(*this));
+ texture_layer->SetHDRConfiguration(hdr_mode_.Read(*this),
+ hdr_metadata_.Read(*this));
if (needs_set_resource_.Read(*this)) {
viz::TransferableResource resource;
viz::ReleaseCallback release_callback;
diff --git a/chromium/cc/layers/texture_layer.h b/chromium/cc/layers/texture_layer.h
index 58878c7e869..1e4f6d1536f 100644
--- a/chromium/cc/layers/texture_layer.h
+++ b/chromium/cc/layers/texture_layer.h
@@ -126,7 +126,8 @@ class CC_EXPORT TextureLayer : public Layer, SharedBitmapIdRegistrar {
viz::ReleaseCallback release_callback);
// Set or unset HDR metadata.
- void SetHDRMetadata(absl::optional<gfx::HDRMetadata> hdr_metadata);
+ void SetHDRConfiguration(gfx::HDRMode mode,
+ absl::optional<gfx::HDRMetadata> hdr_metadata);
void SetLayerTreeHost(LayerTreeHost* layer_tree_host) override;
bool Update() override;
@@ -179,6 +180,7 @@ class CC_EXPORT TextureLayer : public Layer, SharedBitmapIdRegistrar {
ProtectedSequenceReadable<bool> premultiplied_alpha_;
ProtectedSequenceReadable<bool> blend_background_color_;
ProtectedSequenceReadable<bool> force_texture_to_opaque_;
+ ProtectedSequenceReadable<gfx::HDRMode> hdr_mode_;
ProtectedSequenceWritable<absl::optional<gfx::HDRMetadata>> hdr_metadata_;
ProtectedSequenceWritable<scoped_refptr<TransferableResourceHolder>>
diff --git a/chromium/cc/layers/texture_layer_impl.cc b/chromium/cc/layers/texture_layer_impl.cc
index 10e490fc646..c87bc2a6e89 100644
--- a/chromium/cc/layers/texture_layer_impl.cc
+++ b/chromium/cc/layers/texture_layer_impl.cc
@@ -59,7 +59,7 @@ void TextureLayerImpl::PushPropertiesTo(LayerImpl* layer) {
texture_layer->SetBlendBackgroundColor(blend_background_color_);
texture_layer->SetForceTextureToOpaque(force_texture_to_opaque_);
texture_layer->SetNearestNeighbor(nearest_neighbor_);
- texture_layer->SetHDRMetadata(hdr_metadata_);
+ texture_layer->SetHDRConfiguration(hdr_mode_, hdr_metadata_);
if (own_resource_) {
texture_layer->SetTransferableResource(transferable_resource_,
std::move(release_callback_));
@@ -155,6 +155,7 @@ void TextureLayerImpl::AppendQuads(viz::CompositorRenderPass* render_pass,
nearest_neighbor_, /*secure_output=*/false,
gfx::ProtectedVideoType::kClear);
quad->set_resource_size_in_pixels(transferable_resource_.size);
+ quad->hdr_mode = hdr_mode_;
quad->hdr_metadata = hdr_metadata_;
ValidateQuadResources(quad);
}
@@ -200,6 +201,8 @@ void TextureLayerImpl::ReleaseResources() {
}
gfx::ContentColorUsage TextureLayerImpl::GetContentColorUsage() const {
+ if (hdr_mode_ == gfx::HDRMode::kExtended)
+ return gfx::ContentColorUsage::kHDR;
return transferable_resource_.color_space.GetContentColorUsage();
}
@@ -231,8 +234,10 @@ void TextureLayerImpl::SetUVBottomRight(const gfx::PointF& bottom_right) {
uv_bottom_right_ = bottom_right;
}
-void TextureLayerImpl::SetHDRMetadata(
+void TextureLayerImpl::SetHDRConfiguration(
+ gfx::HDRMode hdr_mode,
absl::optional<gfx::HDRMetadata> hdr_metadata) {
+ hdr_mode_ = hdr_mode;
hdr_metadata_ = hdr_metadata;
}
diff --git a/chromium/cc/layers/texture_layer_impl.h b/chromium/cc/layers/texture_layer_impl.h
index d4853afc1d3..8ca34ade423 100644
--- a/chromium/cc/layers/texture_layer_impl.h
+++ b/chromium/cc/layers/texture_layer_impl.h
@@ -58,7 +58,8 @@ class CC_EXPORT TextureLayerImpl : public LayerImpl {
void SetNearestNeighbor(bool nearest_neighbor);
void SetUVTopLeft(const gfx::PointF& top_left);
void SetUVBottomRight(const gfx::PointF& bottom_right);
- void SetHDRMetadata(absl::optional<gfx::HDRMetadata> hdr_metadata);
+ void SetHDRConfiguration(gfx::HDRMode mode,
+ absl::optional<gfx::HDRMetadata> hdr_metadata);
void SetTransferableResource(const viz::TransferableResource& resource,
viz::ReleaseCallback release_callback);
@@ -90,6 +91,7 @@ class CC_EXPORT TextureLayerImpl : public LayerImpl {
bool nearest_neighbor_ = false;
gfx::PointF uv_top_left_ = gfx::PointF();
gfx::PointF uv_bottom_right_ = gfx::PointF(1.f, 1.f);
+ gfx::HDRMode hdr_mode_ = gfx::HDRMode::kDefault;
absl::optional<gfx::HDRMetadata> hdr_metadata_;
// True while the |transferable_resource_| is owned by this layer, and
diff --git a/chromium/cc/layers/texture_layer_unittest.cc b/chromium/cc/layers/texture_layer_unittest.cc
index 8bbd9995f60..7b5aed9521e 100644
--- a/chromium/cc/layers/texture_layer_unittest.cc
+++ b/chromium/cc/layers/texture_layer_unittest.cc
@@ -23,7 +23,6 @@
#include "base/task/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "base/threading/thread.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"
@@ -56,11 +55,21 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-using ::testing::Mock;
using ::testing::_;
-using ::testing::AtLeast;
using ::testing::AnyNumber;
+using ::testing::AtLeast;
using ::testing::InvokeWithoutArgs;
+using ::testing::Mock;
+
+// TODO(https://crbug.com/1400943): settings new expecations after
+// VerifyAndClearExpectations is undefined behavior. See
+// http://google.github.io/googletest/gmock_cook_book.html#forcing-a-verification
+#define EXPECT_SET_NEEDS_COMMIT(expect, code_to_test) \
+ do { \
+ EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times((expect)); \
+ code_to_test; \
+ Mock::VerifyAndClearExpectations(layer_tree_host_.get()); \
+ } while (false)
namespace cc {
namespace {
@@ -99,7 +108,7 @@ class MockLayerTreeHost : public LayerTreeHost {
explicit MockLayerTreeHost(LayerTreeHost::InitParams params)
: LayerTreeHost(std::move(params), CompositorMode::SINGLE_THREADED) {
InitializeSingleThreaded(&single_thread_client_,
- base::ThreadTaskRunnerHandle::Get());
+ base::SingleThreadTaskRunner::GetCurrentDefault());
}
StubLayerTreeHostSingleThreadClient single_thread_client_;
@@ -216,12 +225,14 @@ TEST_F(TextureLayerTest, CheckPropertyChangeCausesCorrectBehavior) {
// be set to new values in order for SetNeedsCommit to be called.
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetFlipped(false));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetNearestNeighbor(true));
- EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetUV(
- gfx::PointF(0.25f, 0.25f), gfx::PointF(0.75f, 0.75f)));
+ EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetUV(gfx::PointF(0.25f, 0.25f),
+ gfx::PointF(0.75f, 0.75f)));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetPremultipliedAlpha(false));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetBlendBackgroundColor(true));
- EXPECT_SET_NEEDS_COMMIT(0, test_layer->SetHDRMetadata(absl::nullopt));
- EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetHDRMetadata(gfx::HDRMetadata()));
+ EXPECT_SET_NEEDS_COMMIT(0, test_layer->SetHDRConfiguration(
+ gfx::HDRMode::kDefault, absl::nullopt));
+ EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetHDRConfiguration(
+ gfx::HDRMode::kDefault, gfx::HDRMetadata()));
}
class RunOnCommitLayerTreeHostClient : public FakeLayerTreeHostClient {
@@ -254,7 +265,7 @@ TEST_F(TextureLayerTest, ShutdownWithResource) {
params.mutator_host = animation_host_.get();
LayerTreeSettings settings;
params.settings = &settings;
- params.main_task_runner = base::ThreadTaskRunnerHandle::Get();
+ params.main_task_runner = base::SingleThreadTaskRunner::GetCurrentDefault();
auto host = LayerTreeHost::CreateSingleThreaded(&single_thread_client,
std::move(params));
@@ -386,8 +397,7 @@ TEST_F(TextureLayerWithResourceTest, ReplaceMailboxOnMainThreadBeforeCommit) {
class TextureLayerMailboxHolderTest : public TextureLayerTest {
public:
- TextureLayerMailboxHolderTest()
- : main_thread_("MAIN") {
+ TextureLayerMailboxHolderTest() : main_thread_("MAIN") {
main_thread_.Start();
}
@@ -767,8 +777,8 @@ class TextureLayerImplWithResourceTest : public TextureLayerTest {
}
bool WillDraw(TextureLayerImpl* layer, DrawMode mode) {
- bool will_draw = layer->WillDraw(
- mode, host_impl_.active_tree()->resource_provider());
+ bool will_draw =
+ layer->WillDraw(mode, host_impl_.active_tree()->resource_provider());
if (will_draw)
layer->DidDraw(host_impl_.active_tree()->resource_provider());
return will_draw;
@@ -914,9 +924,8 @@ TEST_F(TextureLayerImplWithResourceTest,
// Checks that TextureLayer::Update does not cause an extra commit when setting
// the texture mailbox.
-class TextureLayerNoExtraCommitForMailboxTest
- : public LayerTreeTest,
- public TextureLayerClient {
+class TextureLayerNoExtraCommitForMailboxTest : public LayerTreeTest,
+ public TextureLayerClient {
public:
// TextureLayerClient implementation.
bool PrepareTransferableResource(
@@ -986,16 +995,10 @@ SINGLE_AND_MULTI_THREAD_TEST_F(TextureLayerNoExtraCommitForMailboxTest);
// Checks that changing a mailbox in the client for a TextureLayer that's
// invisible correctly works and uses the new mailbox as soon as the layer
// becomes visible (and returns the old one).
-class TextureLayerChangeInvisibleMailboxTest
- : public LayerTreeTest,
- public TextureLayerClient {
+class TextureLayerChangeInvisibleMailboxTest : public LayerTreeTest,
+ public TextureLayerClient {
public:
- TextureLayerChangeInvisibleMailboxTest()
- : resource_changed_(true),
- resource_(MakeResource('1')),
- resource_returned_(0),
- prepare_called_(0),
- commit_count_(0) {}
+ TextureLayerChangeInvisibleMailboxTest() : resource_(MakeResource('1')) {}
// TextureLayerClient implementation.
bool PrepareTransferableResource(
@@ -1024,6 +1027,17 @@ class TextureLayerChangeInvisibleMailboxTest
void ResourceReleased(const gpu::SyncToken& sync_token, bool lost_resource) {
EXPECT_TRUE(sync_token.HasData());
++resource_returned_;
+
+ // The actual releasing of resources by
+ // TextureLayer::TransferableResourceHolder::dtor can be done as a PostTask.
+ // The test signal being used, DidReceiveCompositorFrameAck itself is also
+ // posted back from the Compositor-thread to the Main-thread. Due to this
+ // there's a teardown race which tsan builds can encounter. So if
+ // `close_on_resource_returned_` is set we actually end the test here.
+ if (close_on_resource_returned_) {
+ EXPECT_EQ(2, resource_returned_);
+ EndTest();
+ }
}
void SetupTree() override {
@@ -1054,8 +1068,28 @@ class TextureLayerChangeInvisibleMailboxTest
void BeginTest() override { PostSetNeedsCommitToMainThread(); }
void DidReceiveCompositorFrameAck() override {
- ++commit_count_;
- switch (commit_count_) {
+ ++ack_count_;
+ // The fifth frame to be Acked will be returning resources. Due to PostTasks
+ // the ResourcesReleased callback may not yet have been called. So we can
+ // only end the test here if we have received the updated
+ // `resource_returned_`. Otherwise set `close_on_resources_returned_` to
+ // have the callback do the teardown.
+ if (ack_count_ == 5) {
+ if (resource_returned_ < 2) {
+ close_on_resource_returned_ = true;
+ } else {
+ EXPECT_EQ(2, resource_returned_);
+ EndTest();
+ }
+ }
+ }
+
+ void DidCommitAndDrawFrame() override {
+ ++commit_and_draw_count_;
+ // The timing of DidReceiveCompositorFrameAck is not guaranteed. Each of
+ // these checks are actually valid immediately after frame submission, as
+ // the are a part of Commit.
+ switch (commit_and_draw_count_) {
case 1:
// We should have updated the layer, committing the texture.
EXPECT_EQ(1, prepare_called_);
@@ -1086,16 +1120,13 @@ class TextureLayerChangeInvisibleMailboxTest
// for BeginMainFrame and hence PrepareTransferableResource to run twice
// before DidReceiveCompositorFrameAck due to pipelining.
EXPECT_GE(prepare_called_, 2);
- // So the old resource should have been returned already.
+ // So the old resource should have been returned already. This resource
+ // is returned during paint, and so does not need the same PostTask
+ // syncing as for frame 5.
EXPECT_EQ(1, resource_returned_);
texture_layer_->ClearClient();
break;
- case 5:
- EXPECT_EQ(2, resource_returned_);
- EndTest();
- break;
default:
- NOTREACHED();
break;
}
}
@@ -1106,11 +1137,13 @@ class TextureLayerChangeInvisibleMailboxTest
scoped_refptr<TextureLayer> texture_layer_;
// Used on the main thread.
- bool resource_changed_;
+ bool resource_changed_ = true;
viz::TransferableResource resource_;
- int resource_returned_;
- int prepare_called_;
- int commit_count_;
+ int resource_returned_ = 0;
+ int prepare_called_ = 0;
+ int ack_count_ = 0;
+ int commit_and_draw_count_ = 0;
+ bool close_on_resource_returned_ = false;
};
// TODO(crbug.com/1197350): Test fails on chromeos-amd64-generic-rel.
@@ -1124,9 +1157,8 @@ MAYBE_SINGLE_AND_MULTI_THREAD_TEST_F(TextureLayerChangeInvisibleMailboxTest);
// Test that TextureLayerImpl::ReleaseResources can be called which releases
// the resource back to TextureLayerClient.
-class TextureLayerReleaseResourcesBase
- : public LayerTreeTest,
- public TextureLayerClient {
+class TextureLayerReleaseResourcesBase : public LayerTreeTest,
+ public TextureLayerClient {
public:
// TextureLayerClient implementation.
bool PrepareTransferableResource(
diff --git a/chromium/cc/layers/video_layer_impl.cc b/chromium/cc/layers/video_layer_impl.cc
index a6ced88c6b1..a5593d39305 100644
--- a/chromium/cc/layers/video_layer_impl.cc
+++ b/chromium/cc/layers/video_layer_impl.cc
@@ -141,16 +141,16 @@ void VideoLayerImpl::AppendQuads(viz::CompositorRenderPass* render_pass,
switch (media_transform.rotation) {
case media::VIDEO_ROTATION_90:
rotated_size = gfx::Size(rotated_size.height(), rotated_size.width());
- transform.RotateAboutZAxis(90.0);
+ transform *= gfx::Transform::Make90degRotation();
transform.Translate(0.0, -rotated_size.height());
break;
case media::VIDEO_ROTATION_180:
- transform.RotateAboutZAxis(180.0);
+ transform *= gfx::Transform::Make180degRotation();
transform.Translate(-rotated_size.width(), -rotated_size.height());
break;
case media::VIDEO_ROTATION_270:
rotated_size = gfx::Size(rotated_size.height(), rotated_size.width());
- transform.RotateAboutZAxis(270.0);
+ transform *= gfx::Transform::Make270degRotation();
transform.Translate(-rotated_size.width(), 0);
break;
case media::VIDEO_ROTATION_0:
diff --git a/chromium/cc/layers/view_transition_content_layer.cc b/chromium/cc/layers/view_transition_content_layer.cc
new file mode 100644
index 00000000000..4d872b87b93
--- /dev/null
+++ b/chromium/cc/layers/view_transition_content_layer.cc
@@ -0,0 +1,41 @@
+// Copyright 2021 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/layers/view_transition_content_layer.h"
+
+#include <memory>
+
+#include "base/logging.h"
+#include "cc/layers/view_transition_content_layer_impl.h"
+#include "cc/trees/layer_tree_host.h"
+
+namespace cc {
+
+scoped_refptr<ViewTransitionContentLayer> ViewTransitionContentLayer::Create(
+ const viz::ViewTransitionElementResourceId& resource_id,
+ bool is_live_content_layer) {
+ return base::WrapRefCounted(
+ new ViewTransitionContentLayer(resource_id, is_live_content_layer));
+}
+
+ViewTransitionContentLayer::ViewTransitionContentLayer(
+ const viz::ViewTransitionElementResourceId& resource_id,
+ bool is_live_content_layer)
+ : resource_id_(resource_id),
+ is_live_content_layer_(is_live_content_layer) {}
+
+ViewTransitionContentLayer::~ViewTransitionContentLayer() = default;
+
+viz::ViewTransitionElementResourceId
+ViewTransitionContentLayer::ViewTransitionResourceId() const {
+ return resource_id_;
+}
+
+std::unique_ptr<LayerImpl> ViewTransitionContentLayer::CreateLayerImpl(
+ LayerTreeImpl* tree_impl) const {
+ return ViewTransitionContentLayerImpl::Create(tree_impl, id(), resource_id_,
+ is_live_content_layer_);
+}
+
+} // namespace cc
diff --git a/chromium/cc/layers/view_transition_content_layer.h b/chromium/cc/layers/view_transition_content_layer.h
new file mode 100644
index 00000000000..e04724333c7
--- /dev/null
+++ b/chromium/cc/layers/view_transition_content_layer.h
@@ -0,0 +1,49 @@
+// Copyright 2021 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_LAYERS_VIEW_TRANSITION_CONTENT_LAYER_H_
+#define CC_LAYERS_VIEW_TRANSITION_CONTENT_LAYER_H_
+
+#include <memory>
+
+#include "base/logging.h"
+#include "cc/cc_export.h"
+#include "cc/layers/layer.h"
+#include "components/viz/common/view_transition_element_resource_id.h"
+
+namespace cc {
+
+// A layer that renders a texture cached in the Viz process.
+class CC_EXPORT ViewTransitionContentLayer : public Layer {
+ public:
+ static scoped_refptr<ViewTransitionContentLayer> Create(
+ const viz::ViewTransitionElementResourceId& resource_id,
+ bool is_live_content_layer);
+
+ ViewTransitionContentLayer(const ViewTransitionContentLayer&) = delete;
+ ViewTransitionContentLayer& operator=(const ViewTransitionContentLayer&) =
+ delete;
+
+ viz::ViewTransitionElementResourceId ViewTransitionResourceId()
+ const override;
+
+ // Layer overrides.
+ std::unique_ptr<LayerImpl> CreateLayerImpl(
+ LayerTreeImpl* tree_impl) const override;
+
+ protected:
+ explicit ViewTransitionContentLayer(
+ const viz::ViewTransitionElementResourceId& resource_id,
+ bool is_live_content_layer);
+
+ private:
+ ~ViewTransitionContentLayer() override;
+
+ const viz::ViewTransitionElementResourceId resource_id_;
+ const bool is_live_content_layer_;
+};
+
+} // namespace cc
+
+#endif // CC_LAYERS_VIEW_TRANSITION_CONTENT_LAYER_H_
diff --git a/chromium/cc/layers/document_transition_content_layer_impl.cc b/chromium/cc/layers/view_transition_content_layer_impl.cc
index 562413b64d8..b4f03d37e2d 100644
--- a/chromium/cc/layers/document_transition_content_layer_impl.cc
+++ b/chromium/cc/layers/view_transition_content_layer_impl.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "cc/layers/document_transition_content_layer_impl.h"
+#include "cc/layers/view_transition_content_layer_impl.h"
#include "base/memory/ptr_util.h"
#include "cc/layers/append_quads_data.h"
@@ -10,47 +10,45 @@
#include "cc/trees/layer_tree_impl.h"
#include "components/viz/common/quads/shared_element_draw_quad.h"
#include "components/viz/common/quads/solid_color_draw_quad.h"
-#include "components/viz/common/shared_element_resource_id.h"
+#include "components/viz/common/view_transition_element_resource_id.h"
namespace cc {
// static
-std::unique_ptr<DocumentTransitionContentLayerImpl>
-DocumentTransitionContentLayerImpl::Create(
+std::unique_ptr<ViewTransitionContentLayerImpl>
+ViewTransitionContentLayerImpl::Create(
LayerTreeImpl* tree_impl,
int id,
- const viz::SharedElementResourceId& resource_id,
+ const viz::ViewTransitionElementResourceId& resource_id,
bool is_live_content_layer) {
- return base::WrapUnique(new DocumentTransitionContentLayerImpl(
+ return base::WrapUnique(new ViewTransitionContentLayerImpl(
tree_impl, id, resource_id, is_live_content_layer));
}
-DocumentTransitionContentLayerImpl::DocumentTransitionContentLayerImpl(
+ViewTransitionContentLayerImpl::ViewTransitionContentLayerImpl(
LayerTreeImpl* tree_impl,
int id,
- const viz::SharedElementResourceId& resource_id,
+ const viz::ViewTransitionElementResourceId& resource_id,
bool is_live_content_layer)
: LayerImpl(tree_impl, id),
resource_id_(resource_id),
is_live_content_layer_(is_live_content_layer) {}
-DocumentTransitionContentLayerImpl::~DocumentTransitionContentLayerImpl() =
- default;
+ViewTransitionContentLayerImpl::~ViewTransitionContentLayerImpl() = default;
-std::unique_ptr<LayerImpl> DocumentTransitionContentLayerImpl::CreateLayerImpl(
+std::unique_ptr<LayerImpl> ViewTransitionContentLayerImpl::CreateLayerImpl(
LayerTreeImpl* tree_impl) const {
- return DocumentTransitionContentLayerImpl::Create(
- tree_impl, id(), resource_id_, is_live_content_layer_);
+ return ViewTransitionContentLayerImpl::Create(tree_impl, id(), resource_id_,
+ is_live_content_layer_);
}
-void DocumentTransitionContentLayerImpl::
- NotifyKnownResourceIdsBeforeAppendQuads(
- const base::flat_set<viz::SharedElementResourceId>&
- known_resource_ids) {
+void ViewTransitionContentLayerImpl::NotifyKnownResourceIdsBeforeAppendQuads(
+ const base::flat_set<viz::ViewTransitionElementResourceId>&
+ known_resource_ids) {
skip_unseen_resource_quads_ = known_resource_ids.count(resource_id_) == 0;
}
-void DocumentTransitionContentLayerImpl::AppendQuads(
+void ViewTransitionContentLayerImpl::AppendQuads(
viz::CompositorRenderPass* render_pass,
AppendQuadsData* append_quads_data) {
// Skip live content elements that don't have a corresponding resource render
@@ -84,8 +82,8 @@ void DocumentTransitionContentLayerImpl::AppendQuads(
append_quads_data->has_shared_element_resources = true;
}
-const char* DocumentTransitionContentLayerImpl::LayerTypeAsString() const {
- return "cc::DocumentTransitionContentLayerImpl";
+const char* ViewTransitionContentLayerImpl::LayerTypeAsString() const {
+ return "cc::ViewTransitionContentLayerImpl";
}
} // namespace cc
diff --git a/chromium/cc/layers/view_transition_content_layer_impl.h b/chromium/cc/layers/view_transition_content_layer_impl.h
new file mode 100644
index 00000000000..de7cd3c371a
--- /dev/null
+++ b/chromium/cc/layers/view_transition_content_layer_impl.h
@@ -0,0 +1,58 @@
+// Copyright 2021 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_LAYERS_VIEW_TRANSITION_CONTENT_LAYER_IMPL_H_
+#define CC_LAYERS_VIEW_TRANSITION_CONTENT_LAYER_IMPL_H_
+
+#include <memory>
+
+#include "cc/cc_export.h"
+#include "cc/layers/layer_impl.h"
+#include "components/viz/common/view_transition_element_resource_id.h"
+
+namespace cc {
+
+class CC_EXPORT ViewTransitionContentLayerImpl : public LayerImpl {
+ public:
+ static std::unique_ptr<ViewTransitionContentLayerImpl> Create(
+ LayerTreeImpl* tree_impl,
+ int id,
+ const viz::ViewTransitionElementResourceId& resource_id,
+ bool is_live_content_layer);
+
+ ViewTransitionContentLayerImpl(const ViewTransitionContentLayerImpl&) =
+ delete;
+ ~ViewTransitionContentLayerImpl() override;
+
+ ViewTransitionContentLayerImpl& operator=(
+ const ViewTransitionContentLayerImpl&) = delete;
+
+ // LayerImpl overrides.
+ std::unique_ptr<LayerImpl> CreateLayerImpl(
+ LayerTreeImpl* tree_impl) const override;
+ void AppendQuads(viz::CompositorRenderPass* render_pass,
+ AppendQuadsData* append_quads_data) override;
+
+ void NotifyKnownResourceIdsBeforeAppendQuads(
+ const base::flat_set<viz::ViewTransitionElementResourceId>&
+ known_resource_ids) override;
+
+ protected:
+ ViewTransitionContentLayerImpl(
+ LayerTreeImpl* tree_impl,
+ int id,
+ const viz::ViewTransitionElementResourceId& resource_id,
+ bool is_live_content_layer);
+
+ private:
+ const char* LayerTypeAsString() const override;
+
+ const viz::ViewTransitionElementResourceId resource_id_;
+ const bool is_live_content_layer_;
+ bool skip_unseen_resource_quads_ = false;
+};
+
+} // namespace cc
+
+#endif // CC_LAYERS_VIEW_TRANSITION_CONTENT_LAYER_IMPL_H_
diff --git a/chromium/cc/metrics/compositor_frame_reporter.cc b/chromium/cc/metrics/compositor_frame_reporter.cc
index a835131fcb7..ff22dab9a26 100644
--- a/chromium/cc/metrics/compositor_frame_reporter.cc
+++ b/chromium/cc/metrics/compositor_frame_reporter.cc
@@ -803,11 +803,6 @@ void CompositorFrameReporter::TerminateReporter() {
global_trackers_.dropped_frame_counter->AddGoodFrame();
}
global_trackers_.dropped_frame_counter->OnEndFrame(args_, frame_info);
-
- 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) {
@@ -1474,9 +1469,9 @@ void CompositorFrameReporter::CalculateEventLatencyPrediction(
event_metrics->GetDispatchStageTimestamp(
EventMetrics::DispatchStage::kGenerated);
- // Determine the last valid stage in case kRendererMainFinished or
- // kRendererCompositorFinished stages do not exist, otherwise there is not
- // enough information for the prediction.
+ // Determine the last valid stage. First check kRendererMainFinished and if it
+ // doesn't exist, check kRendererCompositorFinished. If neither of them
+ // exists, there is not enough information for the prediction.
EventMetrics::DispatchStage last_valid_stage =
EventMetrics::DispatchStage::kGenerated;
if (event_metrics->GetDispatchStageTimestamp(
@@ -1487,6 +1482,8 @@ void CompositorFrameReporter::CalculateEventLatencyPrediction(
EventMetrics::DispatchStage::kRendererCompositorFinished) >
dispatch_start_time) {
last_valid_stage = EventMetrics::DispatchStage::kRendererCompositorFinished;
+ } else {
+ return;
}
base::TimeTicks dispatch_end_time =
@@ -1616,7 +1613,6 @@ void CompositorFrameReporter::DiscardOldPartialUpdateReporters() {
auto& dependent = owned_partial_update_dependents_.front();
dependent->set_has_partial_update(false);
owned_partial_update_dependents_.pop();
- discarded_partial_update_dependents_count_++;
}
// Remove dependent reporters from the front of `partial_update_dependents_`
diff --git a/chromium/cc/metrics/compositor_frame_reporter.h b/chromium/cc/metrics/compositor_frame_reporter.h
index 9034cff4e0f..335ce5db04a 100644
--- a/chromium/cc/metrics/compositor_frame_reporter.h
+++ b/chromium/cc/metrics/compositor_frame_reporter.h
@@ -40,7 +40,8 @@ struct GlobalMetricsTrackers {
raw_ptr<DroppedFrameCounter> dropped_frame_counter = nullptr;
raw_ptr<LatencyUkmReporter> latency_ukm_reporter = nullptr;
raw_ptr<FrameSequenceTrackerCollection> frame_sequence_trackers = nullptr;
- raw_ptr<EventLatencyTracker> event_latency_tracker = nullptr;
+ raw_ptr<EventLatencyTracker, DanglingUntriaged> event_latency_tracker =
+ nullptr;
};
// This is used for tracing and reporting the duration of pipeline stages within
@@ -548,7 +549,6 @@ class CC_EXPORT CompositorFrameReporter {
// |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
diff --git a/chromium/cc/metrics/custom_metrics_recorder.h b/chromium/cc/metrics/custom_metrics_recorder.h
index 49eb8d1923e..ced959e4820 100644
--- a/chromium/cc/metrics/custom_metrics_recorder.h
+++ b/chromium/cc/metrics/custom_metrics_recorder.h
@@ -5,7 +5,10 @@
#ifndef CC_METRICS_CUSTOM_METRICS_RECORDER_H_
#define CC_METRICS_CUSTOM_METRICS_RECORDER_H_
+#include <vector>
+
#include "cc/cc_export.h"
+#include "cc/metrics/event_latency_tracker.h"
namespace cc {
@@ -15,7 +18,11 @@ class CC_EXPORT CustomMetricRecorder {
static CustomMetricRecorder* Get();
// Invoked to report "PercentDroppedFrames_1sWindow".
- virtual void ReportPercentDroppedFramesInOneSecoundWindow(double percent) = 0;
+ virtual void ReportPercentDroppedFramesInOneSecondWindow(double percent) = 0;
+
+ // Invoked to report event latencies.
+ virtual void ReportEventLatency(
+ std::vector<EventLatencyTracker::LatencyData> latencies) = 0;
protected:
CustomMetricRecorder();
diff --git a/chromium/cc/metrics/dropped_frame_counter.cc b/chromium/cc/metrics/dropped_frame_counter.cc
index a7685e97221..5bc85335a28 100644
--- a/chromium/cc/metrics/dropped_frame_counter.cc
+++ b/chromium/cc/metrics/dropped_frame_counter.cc
@@ -12,6 +12,7 @@
#include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram.h"
#include "base/metrics/histogram_macros.h"
+#include "base/ranges/algorithm.h"
#include "base/trace_event/trace_event.h"
#include "build/chromeos_buildflags.h"
#include "cc/base/features.h"
@@ -351,8 +352,7 @@ void DroppedFrameCounter::ReportFrames() {
.GetPercentDroppedFrameBuckets();
DCHECK_EQ(sliding_window_buckets.size(),
std::size(smoothness_data.buckets));
- std::copy(sliding_window_buckets.begin(), sliding_window_buckets.end(),
- smoothness_data.buckets);
+ base::ranges::copy(sliding_window_buckets, smoothness_data.buckets);
smoothness_data.main_focused_median = SlidingWindowMedianPercentDropped(
SmoothnessStrategy::kMainFocusedStrategy);
@@ -402,7 +402,7 @@ void DroppedFrameCounter::ReportFramesForUI() {
if (!recorder)
return;
- recorder->ReportPercentDroppedFramesInOneSecoundWindow(
+ recorder->ReportPercentDroppedFramesInOneSecondWindow(
sliding_window_current_percent_dropped_);
}
diff --git a/chromium/cc/metrics/dropped_frame_counter_unittest.cc b/chromium/cc/metrics/dropped_frame_counter_unittest.cc
index bcc6572ddd3..6c21d28643e 100644
--- a/chromium/cc/metrics/dropped_frame_counter_unittest.cc
+++ b/chromium/cc/metrics/dropped_frame_counter_unittest.cc
@@ -35,11 +35,12 @@ class TestCustomMetricsRecorder : public CustomMetricRecorder {
~TestCustomMetricsRecorder() override = default;
// CustomMetricRecorder:
- void ReportPercentDroppedFramesInOneSecoundWindow(
- double percentage) override {
+ void ReportPercentDroppedFramesInOneSecondWindow(double percentage) override {
++percent_dropped_frames_count_;
last_percent_dropped_frames_ = percentage;
}
+ void ReportEventLatency(
+ std::vector<EventLatencyTracker::LatencyData> latencies) override {}
int percent_dropped_frames_count() const {
return percent_dropped_frames_count_;
diff --git a/chromium/cc/metrics/event_metrics.cc b/chromium/cc/metrics/event_metrics.cc
index 69647429caa..e9a5b7db994 100644
--- a/chromium/cc/metrics/event_metrics.cc
+++ b/chromium/cc/metrics/event_metrics.cc
@@ -280,7 +280,12 @@ EventMetrics::~EventMetrics() {
}
const char* EventMetrics::GetTypeName() const {
- return kInterestingEvents[static_cast<int>(type_)].name;
+ return GetTypeName(type_);
+}
+
+// static
+const char* EventMetrics::GetTypeName(EventMetrics::EventType type) {
+ return kInterestingEvents[static_cast<int>(type)].name;
}
void EventMetrics::SetHighLatencyStage(const std::string& stage) {
diff --git a/chromium/cc/metrics/event_metrics.h b/chromium/cc/metrics/event_metrics.h
index 4eafd0ef986..8f773f317af 100644
--- a/chromium/cc/metrics/event_metrics.h
+++ b/chromium/cc/metrics/event_metrics.h
@@ -107,6 +107,7 @@ class CC_EXPORT EventMetrics {
// Returns a string representing event type.
const char* GetTypeName() const;
+ static const char* GetTypeName(EventType type);
void SetHighLatencyStage(const std::string& stage);
const std::vector<std::string>& GetHighLatencyStages() const {
diff --git a/chromium/cc/metrics/frame_sequence_metrics.h b/chromium/cc/metrics/frame_sequence_metrics.h
index d16a4cf1130..ee945cd01d2 100644
--- a/chromium/cc/metrics/frame_sequence_metrics.h
+++ b/chromium/cc/metrics/frame_sequence_metrics.h
@@ -234,7 +234,8 @@ class CC_EXPORT FrameSequenceMetrics {
} trace_data_{this};
// Pointer to the reporter owned by the FrameSequenceTrackerCollection.
- const raw_ptr<ThroughputUkmReporter> throughput_ukm_reporter_;
+ const raw_ptr<ThroughputUkmReporter, DanglingUntriaged>
+ throughput_ukm_reporter_;
// Track state for measuring the PercentDroppedFrames v2 metrics.
struct {
diff --git a/chromium/cc/paint/BUILD.gn b/chromium/cc/paint/BUILD.gn
index 71b6dd6087b..ca0821437fa 100644
--- a/chromium/cc/paint/BUILD.gn
+++ b/chromium/cc/paint/BUILD.gn
@@ -49,8 +49,12 @@ cc_component("paint") {
"paint_image_builder.h",
"paint_image_generator.cc",
"paint_image_generator.h",
+ "paint_op.cc",
+ "paint_op.h",
"paint_op_buffer.cc",
"paint_op_buffer.h",
+ "paint_op_buffer_iterator.cc",
+ "paint_op_buffer_iterator.h",
"paint_op_buffer_serializer.cc",
"paint_op_buffer_serializer.h",
"paint_op_reader.cc",
@@ -132,7 +136,6 @@ cc_component("paint") {
"//components/crash/core/common:crash_key",
"//gpu/command_buffer/common:mailbox",
"//ui/gfx/animation",
- "//ui/gfx/ipc/color",
]
if (skia_support_skottie) {
diff --git a/chromium/cc/paint/discardable_image_map.cc b/chromium/cc/paint/discardable_image_map.cc
index bf5cf44e5a3..3543e180740 100644
--- a/chromium/cc/paint/discardable_image_map.cc
+++ b/chromium/cc/paint/discardable_image_map.cc
@@ -18,6 +18,7 @@
#include "cc/paint/image_provider.h"
#include "cc/paint/paint_filter.h"
#include "cc/paint/paint_op_buffer.h"
+#include "cc/paint/paint_op_buffer_iterator.h"
#include "cc/paint/skottie_wrapper.h"
#include "third_party/skia/include/utils/SkNoDrawCanvas.h"
#include "ui/gfx/display_color_spaces.h"
@@ -32,7 +33,7 @@ class DiscardableImageGenerator {
public:
DiscardableImageGenerator(int width,
int height,
- const PaintOpBuffer* buffer) {
+ const PaintOpBuffer& buffer) {
SkNoDrawCanvas canvas(width, height);
GatherDiscardableImages(buffer, nullptr, &canvas);
}
@@ -90,10 +91,10 @@ class DiscardableImageGenerator {
// |top_level_op_rect| is set to the rect for that op. If provided, the
// |top_level_op_rect| will be used as the rect for tracking the position of
// this image in the top-level buffer.
- void GatherDiscardableImages(const PaintOpBuffer* buffer,
+ void GatherDiscardableImages(const PaintOpBuffer& buffer,
const gfx::Rect* top_level_op_rect,
SkNoDrawCanvas* canvas) {
- if (!buffer->HasDiscardableImages())
+ if (!buffer.HasDiscardableImages())
return;
// Prevent PaintOpBuffers from having side effects back into the canvas.
@@ -102,7 +103,7 @@ class DiscardableImageGenerator {
PlaybackParams params(nullptr, canvas->getLocalToDevice());
// TODO(khushalsagar): Optimize out save/restore blocks if there are no
// images in the draw ops between them.
- for (const PaintOp& op : PaintOpBuffer::Iterator(buffer)) {
+ for (const PaintOp& op : buffer) {
// We need to play non-draw ops on the SkCanvas since they can affect the
// transform/clip state.
if (!op.IsDrawOp())
@@ -186,9 +187,8 @@ class DiscardableImageGenerator {
frame_data.quality);
}
} else if (op_type == PaintOpType::DrawRecord) {
- GatherDiscardableImages(
- static_cast<const DrawRecordOp&>(op).record.get(),
- top_level_op_rect, canvas);
+ GatherDiscardableImages(*static_cast<const DrawRecordOp&>(op).record,
+ top_level_op_rect, canvas);
}
}
}
@@ -237,7 +237,7 @@ class DiscardableImageGenerator {
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);
+ GatherDiscardableImages(*shader->paint_record(), &op_rect, &canvas);
// We only track animated images for PaintShaders. If we added any entry
// to the |image_set_|, this shader any has animated images.
@@ -367,7 +367,7 @@ void DiscardableImageMap::Generate(const PaintOpBuffer* paint_op_buffer,
return;
DiscardableImageGenerator generator(bounds.right(), bounds.bottom(),
- paint_op_buffer);
+ *paint_op_buffer);
image_id_to_rects_ = generator.TakeImageIdToRectsMap();
animated_images_metadata_ = generator.TakeAnimatedImagesMetadata();
paint_worklet_inputs_ = generator.TakePaintWorkletInputs();
diff --git a/chromium/cc/paint/discardable_image_map_unittest.cc b/chromium/cc/paint/discardable_image_map_unittest.cc
index 7d7d850f33b..10215bdcdc8 100644
--- a/chromium/cc/paint/discardable_image_map_unittest.cc
+++ b/chromium/cc/paint/discardable_image_map_unittest.cc
@@ -708,14 +708,8 @@ TEST_F(DiscardableImageMapTest, GathersDiscardableImagesFromNestedOps) {
PaintImage discardable_image2 =
CreateDiscardablePaintImage(gfx::Size(100, 100));
- scoped_refptr<DisplayItemList> display_list =
- new DisplayItemList(DisplayItemList::kToBeReleasedAsPaintOpBuffer);
- display_list->StartPaint();
- display_list->push<DrawImageOp>(discardable_image2, 100.f, 100.f);
- display_list->EndPaintOfUnpaired(gfx::Rect(100, 100, 100, 100));
- display_list->Finalize();
-
- sk_sp<PaintRecord> record2 = display_list->ReleaseAsRecord();
+ sk_sp<PaintRecord> record2 = sk_make_sp<PaintRecord>();
+ record2->push<DrawImageOp>(discardable_image2, 100.f, 100.f);
PaintOpBuffer root_buffer;
root_buffer.push<DrawRecordOp>(internal_record);
diff --git a/chromium/cc/paint/display_item_list.cc b/chromium/cc/paint/display_item_list.cc
index d0ebdc0cd22..186716bf836 100644
--- a/chromium/cc/paint/display_item_list.cc
+++ b/chromium/cc/paint/display_item_list.cc
@@ -13,6 +13,7 @@
#include "base/trace_event/traced_value.h"
#include "cc/base/math_util.h"
#include "cc/debug/picture_debug_util.h"
+#include "cc/paint/paint_op_buffer_iterator.h"
#include "cc/paint/solid_color_analyzer.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
@@ -39,7 +40,7 @@ void IterateTextContent(const PaintOpBuffer& buffer,
const gfx::Rect& rect) {
if (!buffer.has_draw_text_ops())
return;
- for (const PaintOp& op : PaintOpBuffer::Iterator(&buffer)) {
+ for (const PaintOp& op : buffer) {
if (op.GetType() == PaintOpType::DrawTextBlob) {
yield(static_cast<const DrawTextBlobOp&>(op), rect);
} else if (op.GetType() == PaintOpType::DrawRecord) {
@@ -69,20 +70,16 @@ void IterateTextContentByOffsets(const PaintOpBuffer& buffer,
}
} // namespace
-DisplayItemList::DisplayItemList(UsageHint usage_hint)
- : usage_hint_(usage_hint) {
- if (usage_hint_ == kTopLevelDisplayItemList) {
- visual_rects_.reserve(1024);
- offsets_.reserve(1024);
- paired_begin_stack_.reserve(32);
- }
+DisplayItemList::DisplayItemList() {
+ visual_rects_.reserve(1024);
+ offsets_.reserve(1024);
+ paired_begin_stack_.reserve(32);
}
DisplayItemList::~DisplayItemList() = default;
void DisplayItemList::Raster(SkCanvas* canvas,
ImageProvider* image_provider) const {
- DCHECK(usage_hint_ == kTopLevelDisplayItemList);
gfx::Rect canvas_playback_rect;
if (!GetCanvasClipBounds(canvas, &canvas_playback_rect))
return;
@@ -141,9 +138,6 @@ void DisplayItemList::EndPaintOfPairedEnd() {
DCHECK_LT(current_range_start_, paint_op_buffer_.size());
current_range_start_ = kNotPainting;
#endif
- if (usage_hint_ == kToBeReleasedAsPaintOpBuffer)
- return;
-
DCHECK(paired_begin_stack_.size());
size_t last_begin_index = paired_begin_stack_.back().first_index;
size_t last_begin_count = paired_begin_stack_.back().count;
@@ -167,6 +161,11 @@ void DisplayItemList::EndPaintOfPairedEnd() {
}
void DisplayItemList::Finalize() {
+ FinalizeImpl();
+ paint_op_buffer_.ShrinkToFit();
+}
+
+void DisplayItemList::FinalizeImpl() {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"DisplayItemList::Finalize");
#if DCHECK_IS_ON()
@@ -178,19 +177,17 @@ void DisplayItemList::Finalize() {
DCHECK_EQ(visual_rects_.size(), offsets_.size());
#endif
- if (usage_hint_ == kTopLevelDisplayItemList) {
- rtree_.Build(visual_rects_,
- [](const std::vector<gfx::Rect>& rects, size_t index) {
- return rects[index];
- },
- [this](const std::vector<gfx::Rect>& rects, size_t index) {
- // Ignore the given rects, since the payload comes from
- // offsets. However, the indices match, so we can just index
- // into offsets.
- return offsets_[index];
- });
- }
- paint_op_buffer_.ShrinkToFit();
+ rtree_.Build(
+ visual_rects_,
+ [](const std::vector<gfx::Rect>& rects, size_t index) {
+ return rects[index];
+ },
+ [this](const std::vector<gfx::Rect>& rects, size_t index) {
+ // Ignore the given rects, since the payload comes from
+ // offsets. However, the indices match, so we can just index
+ // into offsets.
+ return offsets_[index];
+ });
visual_rects_.clear();
visual_rects_.shrink_to_fit();
offsets_.clear();
@@ -198,6 +195,13 @@ void DisplayItemList::Finalize() {
paired_begin_stack_.shrink_to_fit();
}
+sk_sp<PaintRecord> DisplayItemList::FinalizeAndReleaseAsRecord() {
+ FinalizeImpl();
+ sk_sp<PaintRecord> record = paint_op_buffer_.MoveRetainingBufferIfPossible();
+ Reset();
+ return record;
+}
+
void DisplayItemList::EmitTraceSnapshot() const {
bool include_items;
TRACE_EVENT_CATEGORY_GROUP_ENABLED(
@@ -241,7 +245,7 @@ void DisplayItemList::AddToValue(base::trace_event::TracedValue* state,
PlaybackParams params(nullptr, SkM44());
std::map<size_t, gfx::Rect> visual_rects = rtree_.GetAllBoundsForTracing();
- for (const PaintOp& op : PaintOpBuffer::Iterator(&paint_op_buffer_)) {
+ for (const PaintOp& op : paint_op_buffer_) {
state->BeginDictionary();
state->SetString("name", PaintOpTypeToString(op.GetType()));
@@ -284,8 +288,6 @@ void DisplayItemList::AddToValue(base::trace_event::TracedValue* state,
}
void DisplayItemList::GenerateDiscardableImagesMetadata() {
- DCHECK(usage_hint_ == kTopLevelDisplayItemList);
-
gfx::Rect bounds;
if (rtree_.has_valid_bounds()) {
bounds = rtree_.GetBoundsOrDie();
@@ -314,18 +316,9 @@ void DisplayItemList::Reset() {
paired_begin_stack_.shrink_to_fit();
}
-sk_sp<PaintRecord> DisplayItemList::ReleaseAsRecord() {
- sk_sp<PaintRecord> record =
- sk_make_sp<PaintOpBuffer>(std::move(paint_op_buffer_));
-
- Reset();
- return record;
-}
-
bool DisplayItemList::GetColorIfSolidInRect(const gfx::Rect& rect,
SkColor4f* color,
int max_ops_to_analyze) {
- DCHECK(usage_hint_ == kTopLevelDisplayItemList);
std::vector<size_t>* offsets_to_use = nullptr;
std::vector<size_t> offsets;
if (rtree_.has_valid_bounds() && !rect.Contains(rtree_.GetBoundsOrDie())) {
@@ -364,7 +357,7 @@ DirectlyCompositedImageResultForPaintOpBuffer(const PaintOpBuffer& op_buffer) {
bool transpose_image_size = false;
absl::optional<DisplayItemList::DirectlyCompositedImageResult> result;
- for (const PaintOp& op : PaintOpBuffer::Iterator(&op_buffer)) {
+ for (const PaintOp& op : op_buffer) {
switch (op.GetType()) {
case PaintOpType::Save:
case PaintOpType::Restore:
diff --git a/chromium/cc/paint/display_item_list.h b/chromium/cc/paint/display_item_list.h
index 2453e78f22f..8a862bcb980 100644
--- a/chromium/cc/paint/display_item_list.h
+++ b/chromium/cc/paint/display_item_list.h
@@ -17,6 +17,7 @@
#include "cc/paint/discardable_image_map.h"
#include "cc/paint/image_id.h"
#include "cc/paint/paint_export.h"
+#include "cc/paint/paint_op.h"
#include "cc/paint/paint_op_buffer.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/skia/include/core/SkPicture.h"
@@ -49,11 +50,7 @@ namespace cc {
class CC_PAINT_EXPORT DisplayItemList
: public base::RefCountedThreadSafe<DisplayItemList> {
public:
- // TODO(vmpstr): It would be cool if we didn't need this, and instead used
- // PaintOpBuffer directly when we needed to release this as a paint op buffer.
- enum UsageHint { kTopLevelDisplayItemList, kToBeReleasedAsPaintOpBuffer };
-
- explicit DisplayItemList(UsageHint = kTopLevelDisplayItemList);
+ DisplayItemList();
DisplayItemList(const DisplayItemList&) = delete;
DisplayItemList& operator=(const DisplayItemList&) = delete;
@@ -85,8 +82,7 @@ class CC_PAINT_EXPORT DisplayItemList
DCHECK(IsPainting());
#endif
size_t offset = paint_op_buffer_.next_op_offset();
- if (usage_hint_ == kTopLevelDisplayItemList)
- offsets_.push_back(offset);
+ offsets_.push_back(offset);
const T& op = paint_op_buffer_.push<T>(std::forward<Args>(args)...);
DCHECK(op.IsValid());
return offset;
@@ -105,9 +101,6 @@ class CC_PAINT_EXPORT DisplayItemList
DCHECK(IsPainting());
current_range_start_ = kNotPainting;
#endif
- if (usage_hint_ == kToBeReleasedAsPaintOpBuffer)
- return;
-
visual_rects_.resize(paint_op_buffer_.size(), visual_rect);
GrowCurrentBeginItemVisualRect(visual_rect);
}
@@ -118,9 +111,6 @@ class CC_PAINT_EXPORT DisplayItemList
DCHECK_LT(current_range_start_, paint_op_buffer_.size());
current_range_start_ = kNotPainting;
#endif
- if (usage_hint_ == kToBeReleasedAsPaintOpBuffer)
- return;
-
DCHECK_LT(visual_rects_.size(), paint_op_buffer_.size());
size_t count = paint_op_buffer_.size() - visual_rects_.size();
paired_begin_stack_.push_back({visual_rects_.size(), count});
@@ -132,6 +122,10 @@ class CC_PAINT_EXPORT DisplayItemList
// Called after all items are appended, to process the items.
void Finalize();
+ // Calls Finalize(), and returns a PaintRecord from this DisplayItemList,
+ // leaving |this| in an empty state.
+ sk_sp<PaintRecord> FinalizeAndReleaseAsRecord();
+
struct DirectlyCompositedImageResult {
// See PictureLayerImpl::direct_composited_image_default_raster_scale_.
gfx::Vector2dF default_raster_scale;
@@ -175,10 +169,6 @@ class CC_PAINT_EXPORT DisplayItemList
return visual_rects_[static_cast<size_t>(index)];
}
- // Generate a PaintRecord from this DisplayItemList, leaving |this| in
- // an empty state.
- sk_sp<PaintRecord> ReleaseAsRecord();
-
// If a rectangle is solid color, returns that color. |max_ops_to_analyze|
// indicates the maximum number of draw ops we consider when determining if a
// rectangle is solid color.
@@ -218,11 +208,14 @@ class CC_PAINT_EXPORT DisplayItemList
// If we're currently within a paired display item block, unions the
// given visual rect with the begin display item's visual rect.
void GrowCurrentBeginItemVisualRect(const gfx::Rect& visual_rect) {
- DCHECK_EQ(usage_hint_, kTopLevelDisplayItemList);
if (!paired_begin_stack_.empty())
visual_rects_[paired_begin_stack_.back().first_index].Union(visual_rect);
}
+ // Shared between Finalize() and FinalizeAndReleaseAsRecord(). Does not modify
+ // `paint_op_buffer_`.
+ void FinalizeImpl();
+
// RTree stores indices into the paint op buffer.
// TODO(vmpstr): Update the rtree to store offsets instead.
RTree<size_t> rtree_;
@@ -253,8 +246,6 @@ class CC_PAINT_EXPORT DisplayItemList
size_t current_range_start_ = kNotPainting;
#endif
- UsageHint usage_hint_;
-
friend class base::RefCountedThreadSafe<DisplayItemList>;
FRIEND_TEST_ALL_PREFIXES(DisplayItemListTest, BytesUsed);
};
diff --git a/chromium/cc/paint/display_item_list_unittest.cc b/chromium/cc/paint/display_item_list_unittest.cc
index de2f0e00503..5b0dada0371 100644
--- a/chromium/cc/paint/display_item_list_unittest.cc
+++ b/chromium/cc/paint/display_item_list_unittest.cc
@@ -1139,7 +1139,7 @@ TEST_F(DisplayItemListTest, TotalOpCount) {
list->StartPaint();
list->push<SaveOp>();
list->push<TranslateOp>(10.f, 20.f);
- list->push<DrawRecordOp>(sub_list->ReleaseAsRecord());
+ list->push<DrawRecordOp>(sub_list->FinalizeAndReleaseAsRecord());
list->push<RestoreOp>();
list->EndPaintOfUnpaired(gfx::Rect());
EXPECT_EQ(8u, list->TotalOpCount());
@@ -1161,7 +1161,7 @@ TEST_F(DisplayItemListTest, AreaOfDrawText) {
sub_list->StartPaint();
sub_list->push<DrawTextBlobOp>(text_blob1, 0.0f, 0.0f, PaintFlags());
sub_list->EndPaintOfUnpaired(gfx::Rect());
- auto record = sub_list->ReleaseAsRecord();
+ auto record = sub_list->FinalizeAndReleaseAsRecord();
list->StartPaint();
list->push<SaveOp>();
diff --git a/chromium/cc/paint/filter_operation.cc b/chromium/cc/paint/filter_operation.cc
index 98ade01be59..5eb6354f29b 100644
--- a/chromium/cc/paint/filter_operation.cc
+++ b/chromium/cc/paint/filter_operation.cc
@@ -15,6 +15,7 @@
#include "base/values.h"
#include "cc/base/math_util.h"
#include "ui/gfx/animation/tween.h"
+#include "ui/gfx/geometry/outsets_f.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/skia_conversions.h"
@@ -29,8 +30,7 @@ bool FilterOperation::operator==(const FilterOperation& other) const {
if (type_ == BLUR)
return amount_ == other.amount_ && blur_tile_mode_ == other.blur_tile_mode_;
if (type_ == DROP_SHADOW) {
- return amount_ == other.amount_ &&
- drop_shadow_offset_ == other.drop_shadow_offset_ &&
+ return amount_ == other.amount_ && offset_ == other.offset_ &&
drop_shadow_color_ == other.drop_shadow_color_;
}
if (type_ == REFERENCE) {
@@ -40,9 +40,8 @@ bool FilterOperation::operator==(const FilterOperation& other) const {
return shape_ == other.shape_ && amount_ == other.amount_ &&
outer_threshold_ == other.outer_threshold_;
}
- if (type_ == STRETCH) {
- return amount_ == other.amount_ &&
- outer_threshold_ == other.outer_threshold_;
+ if (type_ == OFFSET) {
+ return offset_ == other.offset_;
}
return amount_ == other.amount_;
}
@@ -53,12 +52,13 @@ FilterOperation::FilterOperation(FilterType type, float amount)
: type_(type),
amount_(amount),
outer_threshold_(0),
- drop_shadow_offset_(0, 0),
+ offset_(0, 0),
drop_shadow_color_(SkColors::kTransparent),
zoom_inset_(0) {
DCHECK_NE(type_, DROP_SHADOW);
DCHECK_NE(type_, COLOR_MATRIX);
DCHECK_NE(type_, REFERENCE);
+ DCHECK_NE(type_, OFFSET);
matrix_.fill(0.0f);
}
@@ -68,7 +68,7 @@ FilterOperation::FilterOperation(FilterType type,
: type_(type),
amount_(amount),
outer_threshold_(0),
- drop_shadow_offset_(0, 0),
+ offset_(0, 0),
drop_shadow_color_(SkColors::kTransparent),
zoom_inset_(0),
blur_tile_mode_(tile_mode) {
@@ -83,7 +83,7 @@ FilterOperation::FilterOperation(FilterType type,
: type_(type),
amount_(stdDeviation),
outer_threshold_(0),
- drop_shadow_offset_(offset),
+ offset_(offset),
drop_shadow_color_(color),
zoom_inset_(0) {
DCHECK_EQ(type_, DROP_SHADOW);
@@ -94,7 +94,7 @@ FilterOperation::FilterOperation(FilterType type, const Matrix& matrix)
: type_(type),
amount_(0),
outer_threshold_(0),
- drop_shadow_offset_(0, 0),
+ offset_(0, 0),
drop_shadow_color_(SkColors::kTransparent),
matrix_(matrix),
zoom_inset_(0) {
@@ -105,23 +105,21 @@ FilterOperation::FilterOperation(FilterType type, float amount, int inset)
: type_(type),
amount_(amount),
outer_threshold_(0),
- drop_shadow_offset_(0, 0),
+ offset_(0, 0),
drop_shadow_color_(SkColors::kTransparent),
zoom_inset_(inset) {
DCHECK_EQ(type_, ZOOM);
matrix_.fill(0.0f);
}
-FilterOperation::FilterOperation(FilterType type,
- float amount,
- float outer_threshold)
+FilterOperation::FilterOperation(FilterType type, const gfx::Point& offset)
: type_(type),
- amount_(amount),
- outer_threshold_(outer_threshold),
- drop_shadow_offset_(0, 0),
+ amount_(0),
+ outer_threshold_(0),
+ offset_(offset),
drop_shadow_color_(SkColors::kTransparent),
zoom_inset_(0) {
- DCHECK_EQ(type_, STRETCH);
+ DCHECK_EQ(type_, OFFSET);
matrix_.fill(0.0f);
}
@@ -130,7 +128,7 @@ FilterOperation::FilterOperation(FilterType type,
: type_(type),
amount_(0),
outer_threshold_(0),
- drop_shadow_offset_(0, 0),
+ offset_(0, 0),
drop_shadow_color_(SkColors::kTransparent),
image_filter_(std::move(image_filter)),
zoom_inset_(0) {
@@ -145,7 +143,7 @@ FilterOperation::FilterOperation(FilterType type,
: type_(type),
amount_(inner_threshold),
outer_threshold_(outer_threshold),
- drop_shadow_offset_(0, 0),
+ offset_(0, 0),
drop_shadow_color_(SkColors::kTransparent),
zoom_inset_(0),
shape_(shape) {
@@ -193,8 +191,8 @@ static FilterOperation CreateNoOpFilter(FilterOperation::FilterType type) {
case FilterOperation::ALPHA_THRESHOLD:
return FilterOperation::CreateAlphaThresholdFilter(
FilterOperation::ShapeRects(), 1.f, 0.f);
- case FilterOperation::STRETCH:
- return FilterOperation::CreateStretchFilter(0.f, 0.f);
+ case FilterOperation::OFFSET:
+ return FilterOperation::CreateOffsetFilter(gfx::Point(0, 0));
}
NOTREACHED();
return FilterOperation::CreateEmptyFilter();
@@ -214,7 +212,6 @@ static float ClampAmountForFilterType(float amount,
case FilterOperation::CONTRAST:
case FilterOperation::BLUR:
case FilterOperation::DROP_SHADOW:
- case FilterOperation::STRETCH:
return std::max(amount, 0.f);
case FilterOperation::ZOOM:
return std::max(amount, 1.f);
@@ -222,6 +219,7 @@ static float ClampAmountForFilterType(float amount,
case FilterOperation::SATURATING_BRIGHTNESS:
return amount;
case FilterOperation::COLOR_MATRIX:
+ case FilterOperation::OFFSET:
case FilterOperation::REFERENCE:
NOTREACHED();
return amount;
@@ -263,13 +261,12 @@ FilterOperation FilterOperation::Blend(const FilterOperation* from,
if (to_op.type() == FilterOperation::BLUR) {
blended_filter.set_blur_tile_mode(to_op.blur_tile_mode());
} else if (to_op.type() == FilterOperation::DROP_SHADOW) {
- gfx::Point blended_offset(gfx::Tween::LinearIntValueBetween(
- progress, from_op.drop_shadow_offset().x(),
- to_op.drop_shadow_offset().x()),
- gfx::Tween::LinearIntValueBetween(
- progress, from_op.drop_shadow_offset().y(),
- to_op.drop_shadow_offset().y()));
- blended_filter.set_drop_shadow_offset(blended_offset);
+ gfx::Point blended_offset(
+ gfx::Tween::LinearIntValueBetween(progress, from_op.offset().x(),
+ to_op.offset().x()),
+ gfx::Tween::LinearIntValueBetween(progress, from_op.offset().y(),
+ to_op.offset().y()));
+ blended_filter.set_offset(blended_offset);
blended_filter.set_drop_shadow_color(gfx::Tween::ColorValueBetween(
progress, from_op.drop_shadow_color(), to_op.drop_shadow_color()));
} else if (to_op.type() == FilterOperation::ZOOM) {
@@ -305,7 +302,7 @@ void FilterOperation::AsValueInto(base::trace_event::TracedValue* value) const {
break;
case FilterOperation::DROP_SHADOW:
value->SetDouble("std_deviation", amount_);
- MathUtil::AddToTracedValue("offset", drop_shadow_offset_, value);
+ MathUtil::AddToTracedValue("offset", offset_, value);
// TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
value->SetInteger("color", drop_shadow_color_.toSkColor());
break;
@@ -331,7 +328,6 @@ void FilterOperation::AsValueInto(base::trace_event::TracedValue* value) const {
case FilterOperation::ALPHA_THRESHOLD: {
value->SetDouble("inner_threshold", amount_);
value->SetDouble("outer_threshold", outer_threshold_);
- std::unique_ptr<base::ListValue> shape_value(new base::ListValue());
value->BeginArray("shape");
for (const gfx::Rect& rect : shape_) {
value->AppendInteger(rect.x());
@@ -341,9 +337,8 @@ void FilterOperation::AsValueInto(base::trace_event::TracedValue* value) const {
}
value->EndArray();
} break;
- case FilterOperation::STRETCH:
- value->SetDouble("amount_x", amount_);
- value->SetDouble("amount_y", outer_threshold_);
+ case FilterOperation::OFFSET:
+ MathUtil::AddToTracedValue("offset", offset_, value);
break;
}
}
@@ -364,15 +359,16 @@ gfx::Rect MapRectInternal(const FilterOperation& op,
switch (op.type()) {
case FilterOperation::BLUR: {
SkVector spread = MapStdDeviation(op.amount(), matrix);
- // Mapping a blur forward requires an outset (negative inset) because a
- // smaller source rectangle gets blurred to a larger destination
- // rectangle.
- float sign =
- (direction == SkImageFilter::kForward_MapDirection) ? -1.0 : 1.0;
- float spread_x = std::abs(spread.x()) * sign;
- float spread_y = std::abs(spread.y()) * sign;
+ float spread_x = std::abs(spread.x());
+ float spread_y = std::abs(spread.y());
+
+ // Mapping a blur both forward/backward requires an outset. For the
+ // forward case this is the bounds that will be modified by the filter
+ // which is larger than `rect`. For the reverse case this is the pixels
+ // needed as input for the filter which is also larger than `rect`. See
+ // https://crbug.com/1385154.
gfx::RectF result(rect);
- result.Inset(gfx::InsetsF::VH(spread_y, spread_x));
+ result.Outset(gfx::OutsetsF::VH(spread_x, spread_y));
return gfx::ToEnclosingRect(result);
}
case FilterOperation::DROP_SHADOW: {
@@ -382,7 +378,7 @@ gfx::Rect MapRectInternal(const FilterOperation& op,
gfx::RectF result(rect);
result.Inset(gfx::InsetsF::VH(-spread_y, -spread_x));
- gfx::Point drop_shadow_offset = op.drop_shadow_offset();
+ gfx::Point drop_shadow_offset = op.offset();
SkVector mapped_drop_shadow_offset;
matrix.mapVector(drop_shadow_offset.x(), drop_shadow_offset.y(),
&mapped_drop_shadow_offset);
@@ -399,6 +395,15 @@ gfx::Rect MapRectInternal(const FilterOperation& op,
return gfx::SkIRectToRect(op.image_filter()->filter_bounds(
gfx::RectToSkIRect(rect), matrix, direction));
}
+ case FilterOperation::OFFSET: {
+ SkVector mapped_offset;
+ matrix.mapVector(op.offset().x(), op.offset().y(), &mapped_offset);
+ if (direction == SkImageFilter::kReverse_MapDirection)
+ mapped_offset = -mapped_offset;
+ return gfx::ToEnclosingRect(
+ gfx::RectF(rect) +
+ gfx::Vector2dF(mapped_offset.x(), mapped_offset.y()));
+ }
default:
return rect;
}
diff --git a/chromium/cc/paint/filter_operation.h b/chromium/cc/paint/filter_operation.h
index fdc7a009bf5..93b6c8fc754 100644
--- a/chromium/cc/paint/filter_operation.h
+++ b/chromium/cc/paint/filter_operation.h
@@ -49,8 +49,8 @@ class CC_PAINT_EXPORT FilterOperation {
REFERENCE,
SATURATING_BRIGHTNESS, // Not used in CSS/SVG.
ALPHA_THRESHOLD, // Not used in CSS/SVG.
- STRETCH, // Not used in CSS/SVG.
- FILTER_TYPE_LAST = STRETCH
+ OFFSET, // Not used in CSS/SVG.
+ FILTER_TYPE_LAST = OFFSET
};
FilterOperation();
@@ -68,13 +68,13 @@ class CC_PAINT_EXPORT FilterOperation {
}
float outer_threshold() const {
- DCHECK(type_ == ALPHA_THRESHOLD || type_ == STRETCH);
+ DCHECK_EQ(type_, ALPHA_THRESHOLD);
return outer_threshold_;
}
- gfx::Point drop_shadow_offset() const {
- DCHECK_EQ(type_, DROP_SHADOW);
- return drop_shadow_offset_;
+ gfx::Point offset() const {
+ DCHECK(type_ == DROP_SHADOW || type_ == OFFSET);
+ return offset_;
}
SkColor4f drop_shadow_color() const {
@@ -175,8 +175,8 @@ class CC_PAINT_EXPORT FilterOperation {
outer_threshold);
}
- static FilterOperation CreateStretchFilter(float amount_x, float amount_y) {
- return FilterOperation(STRETCH, amount_x, amount_y);
+ static FilterOperation CreateOffsetFilter(const gfx::Point& offset) {
+ return FilterOperation(OFFSET, offset);
}
bool operator==(const FilterOperation& other) const;
@@ -199,13 +199,13 @@ class CC_PAINT_EXPORT FilterOperation {
}
void set_outer_threshold(float outer_threshold) {
- DCHECK(type_ == ALPHA_THRESHOLD || type_ == STRETCH);
+ DCHECK_EQ(type_, ALPHA_THRESHOLD);
outer_threshold_ = outer_threshold;
}
- void set_drop_shadow_offset(const gfx::Point& offset) {
- DCHECK_EQ(type_, DROP_SHADOW);
- drop_shadow_offset_ = offset;
+ void set_offset(const gfx::Point& offset) {
+ DCHECK(type_ == DROP_SHADOW || type_ == OFFSET);
+ offset_ = offset;
}
void set_drop_shadow_color(SkColor4f color) {
@@ -273,7 +273,7 @@ class CC_PAINT_EXPORT FilterOperation {
FilterOperation(FilterType type, float amount, int inset);
- FilterOperation(FilterType type, float amount, float outer_threshold);
+ FilterOperation(FilterType type, const gfx::Point& offset);
FilterOperation(FilterType type, sk_sp<PaintFilter> image_filter);
@@ -285,7 +285,7 @@ class CC_PAINT_EXPORT FilterOperation {
FilterType type_;
float amount_;
float outer_threshold_;
- gfx::Point drop_shadow_offset_;
+ gfx::Point offset_;
SkColor4f drop_shadow_color_;
sk_sp<PaintFilter> image_filter_;
Matrix matrix_;
diff --git a/chromium/cc/paint/filter_operations.cc b/chromium/cc/paint/filter_operations.cc
index d7d3f932891..6cf836b35cb 100644
--- a/chromium/cc/paint/filter_operations.cc
+++ b/chromium/cc/paint/filter_operations.cc
@@ -84,7 +84,7 @@ bool FilterOperations::HasFilterThatMovesPixels() const {
case FilterOperation::BLUR:
case FilterOperation::DROP_SHADOW:
case FilterOperation::ZOOM:
- case FilterOperation::STRETCH:
+ case FilterOperation::OFFSET:
return true;
case FilterOperation::REFERENCE:
// TODO(hendrikw): SkImageFilter needs a function that tells us if the
@@ -118,10 +118,9 @@ float FilterOperations::MaximumPixelMovement() const {
continue;
case FilterOperation::DROP_SHADOW:
// |op.amount| here is the blur radius.
- max_movement =
- fmax(max_movement, fmax(std::abs(op.drop_shadow_offset().x()),
- std::abs(op.drop_shadow_offset().y())) +
- op.amount() * 3.f);
+ max_movement = fmax(max_movement, fmax(std::abs(op.offset().x()),
+ std::abs(op.offset().y())) +
+ op.amount() * 3.f);
continue;
case FilterOperation::ZOOM:
max_movement = fmax(max_movement, op.zoom_inset());
@@ -131,9 +130,12 @@ float FilterOperations::MaximumPixelMovement() const {
// the filter can move pixels. See crbug.com/523538 (sort of).
max_movement = fmax(max_movement, 100);
continue;
- case FilterOperation::STRETCH:
+ case FilterOperation::OFFSET:
+ // TODO(crbug/1379125): Work out how to correctly set maximum pixel
+ // movement when an offset filter may be combined with other pixel
+ // moving filters.
max_movement =
- fmax(max_movement, fmax(op.amount(), op.outer_threshold()));
+ fmax(std::abs(op.offset().x()), std::abs(op.offset().y()));
continue;
case FilterOperation::OPACITY:
case FilterOperation::COLOR_MATRIX:
@@ -180,7 +182,7 @@ bool FilterOperations::HasFilterThatAffectsOpacity() const {
case FilterOperation::BRIGHTNESS:
case FilterOperation::CONTRAST:
case FilterOperation::SATURATING_BRIGHTNESS:
- case FilterOperation::STRETCH:
+ case FilterOperation::OFFSET:
break;
}
}
diff --git a/chromium/cc/paint/filter_operations_unittest.cc b/chromium/cc/paint/filter_operations_unittest.cc
index d86c42d8fd3..f3bb0459070 100644
--- a/chromium/cc/paint/filter_operations_unittest.cc
+++ b/chromium/cc/paint/filter_operations_unittest.cc
@@ -39,14 +39,13 @@ TEST(FilterOperationsTest, MapRectBlurOverflow) {
TEST(FilterOperationsTest, MapRectReverseBlur) {
FilterOperations ops;
ops.Append(FilterOperation::CreateBlurFilter(20));
- EXPECT_EQ(gfx::Rect(60, 60, 30, 30),
- ops.MapRectReverse(gfx::Rect(0, 0, 150, 150), SkMatrix::I()));
- EXPECT_EQ(
- gfx::Rect(120, 120, 60, 60),
- ops.MapRectReverse(gfx::Rect(0, 0, 300, 300), SkMatrix::Scale(2, 2)));
+ EXPECT_EQ(gfx::Rect(-60, -60, 130, 130),
+ ops.MapRectReverse(gfx::Rect(0, 0, 10, 10), SkMatrix::I()));
+ EXPECT_EQ(gfx::Rect(-120, -120, 260, 260),
+ ops.MapRectReverse(gfx::Rect(0, 0, 20, 20), SkMatrix::Scale(2, 2)));
EXPECT_EQ(
- gfx::Rect(60, 50, 30, 30),
- ops.MapRectReverse(gfx::Rect(0, -10, 150, 150), SkMatrix::Scale(1, -1)));
+ gfx::Rect(-60, -70, 130, 130),
+ ops.MapRectReverse(gfx::Rect(0, -10, 10, 10), SkMatrix::Scale(1, -1)));
}
TEST(FilterOperationsTest, MapRectDropShadowReferenceFilter) {
@@ -214,6 +213,29 @@ TEST(FilterOperationsTest, MapRectReverseDropShadowDoesNotContract) {
ops.MapRectReverse(gfx::Rect(0, 0, 10, 10), SkMatrix::I()));
}
+TEST(FilterOperationsTest, MapRectOffset) {
+ FilterOperations ops;
+ ops.Append(FilterOperation::CreateOffsetFilter(gfx::Point(30, 40)));
+ EXPECT_EQ(gfx::Rect(30, 40, 10, 10),
+ ops.MapRect(gfx::Rect(0, 0, 10, 10), SkMatrix::I()));
+ EXPECT_EQ(gfx::Rect(60, 80, 20, 20),
+ ops.MapRect(gfx::Rect(0, 0, 20, 20), SkMatrix::Scale(2, 2)));
+ EXPECT_EQ(gfx::Rect(30, -50, 10, 10),
+ ops.MapRect(gfx::Rect(0, -10, 10, 10), SkMatrix::Scale(1, -1)));
+}
+
+TEST(FilterOperationsTest, MapRectReverseOffset) {
+ FilterOperations ops;
+ ops.Append(FilterOperation::CreateOffsetFilter(gfx::Point(30, 40)));
+ EXPECT_EQ(gfx::Rect(-30, -40, 10, 10),
+ ops.MapRectReverse(gfx::Rect(0, 0, 10, 10), SkMatrix::I()));
+ EXPECT_EQ(gfx::Rect(-60, -80, 20, 20),
+ ops.MapRectReverse(gfx::Rect(0, 0, 20, 20), SkMatrix::Scale(2, 2)));
+ EXPECT_EQ(
+ gfx::Rect(-30, 30, 10, 10),
+ ops.MapRectReverse(gfx::Rect(0, -10, 10, 10), SkMatrix::Scale(1, -1)));
+}
+
TEST(FilterOperationsTest, MapRectTypeConversionDoesNotOverflow) {
// Must be bigger than half of the positive range so that the width/height
// overflow happens, but small enough that there aren't other issues before
@@ -254,23 +276,23 @@ TEST(FilterOperationsTest, MapRectTypeConversionDoesNotOverflow) {
FilterOperation op = \
FilterOperation::Create##filter_name##Filter(a, b, c); \
EXPECT_EQ(FilterOperation::filter_type, op.type()); \
- EXPECT_EQ(a, op.drop_shadow_offset()); \
+ EXPECT_EQ(a, op.offset()); \
EXPECT_EQ(b, op.amount()); \
EXPECT_EQ(c, op.drop_shadow_color()); \
\
FilterOperation op2 = FilterOperation::CreateEmptyFilter(); \
op2.set_type(FilterOperation::filter_type); \
\
- EXPECT_NE(a, op2.drop_shadow_offset()); \
+ EXPECT_NE(a, op2.offset()); \
EXPECT_NE(b, op2.amount()); \
EXPECT_NE(c, op2.drop_shadow_color()); \
\
- op2.set_drop_shadow_offset(a); \
+ op2.set_offset(a); \
op2.set_amount(b); \
op2.set_drop_shadow_color(c); \
\
EXPECT_EQ(FilterOperation::filter_type, op2.type()); \
- EXPECT_EQ(a, op2.drop_shadow_offset()); \
+ EXPECT_EQ(a, op2.offset()); \
EXPECT_EQ(b, op2.amount()); \
EXPECT_EQ(c, op2.drop_shadow_color()); \
}
@@ -980,6 +1002,10 @@ TEST(FilterOperationsTest, MaximumPixelMovement) {
EXPECT_FLOAT_EQ(3.f, filters.MaximumPixelMovement());
filters.Clear();
+ filters.Append(FilterOperation::CreateOffsetFilter(gfx::Point(3, -4)));
+ EXPECT_FLOAT_EQ(4.0f, filters.MaximumPixelMovement());
+
+ filters.Clear();
filters.Append(FilterOperation::CreateReferenceFilter(
sk_make_sp<OffsetPaintFilter>(10, 10, nullptr)));
// max movement = 100.
diff --git a/chromium/cc/paint/image_transfer_cache_entry.cc b/chromium/cc/paint/image_transfer_cache_entry.cc
index 02091791220..e685ab15374 100644
--- a/chromium/cc/paint/image_transfer_cache_entry.cc
+++ b/chromium/cc/paint/image_transfer_cache_entry.cc
@@ -23,6 +23,7 @@
#include "third_party/skia/include/gpu/GrDirectContext.h"
#include "third_party/skia/include/gpu/GrYUVABackendTextures.h"
#include "ui/gfx/color_conversion_sk_filter_cache.h"
+#include "ui/gfx/hdr_metadata.h"
namespace cc {
namespace {
@@ -211,6 +212,16 @@ size_t TargetColorParamsSize(
target_color_params_size += sizeof(float);
// uint32_t for tone mapping enabled or disabled.
target_color_params_size += sizeof(uint32_t);
+ // uint32_t for whether or not there is HDR metadata.
+ target_color_params_size += sizeof(uint32_t);
+ if (target_color_params->hdr_metadata) {
+ // The x and y coordinates for primaries and white point.
+ target_color_params_size += 4 * 2 * sizeof(float);
+ // The minimum and maximum luminance.
+ target_color_params_size += 2 * sizeof(float);
+ // The CLL and FALL
+ target_color_params_size += 2 * sizeof(unsigned);
+ }
}
return target_color_params_size;
}
@@ -225,6 +236,26 @@ void WriteTargetColorParams(
writer.Write(target_color_params->sdr_max_luminance_nits);
writer.Write(target_color_params->hdr_max_luminance_relative);
writer.Write(target_color_params->enable_tone_mapping);
+
+ const uint32_t has_hdr_metadata = !!target_color_params->hdr_metadata;
+ writer.Write(has_hdr_metadata);
+ if (target_color_params->hdr_metadata) {
+ const auto& hdr_metadata = target_color_params->hdr_metadata;
+ writer.Write(hdr_metadata->max_content_light_level);
+ writer.Write(hdr_metadata->max_frame_average_light_level);
+
+ const auto& color_volume = hdr_metadata->color_volume_metadata;
+ writer.Write(color_volume.primaries.fRX);
+ writer.Write(color_volume.primaries.fRY);
+ writer.Write(color_volume.primaries.fGX);
+ writer.Write(color_volume.primaries.fGY);
+ writer.Write(color_volume.primaries.fBX);
+ writer.Write(color_volume.primaries.fBY);
+ writer.Write(color_volume.primaries.fWX);
+ writer.Write(color_volume.primaries.fWY);
+ writer.Write(color_volume.luminance_max);
+ writer.Write(color_volume.luminance_min);
+ }
}
}
@@ -248,6 +279,34 @@ bool ReadTargetColorParams(
reader.Read(&target_color_params->sdr_max_luminance_nits);
reader.Read(&target_color_params->hdr_max_luminance_relative);
reader.Read(&target_color_params->enable_tone_mapping);
+
+ uint32_t has_hdr_metadata = 0;
+ reader.Read(&has_hdr_metadata);
+ if (has_hdr_metadata) {
+ gfx::HDRMetadata hdr_metadata;
+ unsigned max_content_light_level = 0;
+ unsigned max_frame_average_light_level = 0;
+ reader.Read(&max_content_light_level);
+ reader.Read(&max_frame_average_light_level);
+
+ SkColorSpacePrimaries primaries = SkNamedPrimariesExt::kInvalid;
+ float luminance_max = 0;
+ float luminance_min = 0;
+ reader.Read(&primaries.fRX);
+ reader.Read(&primaries.fRY);
+ reader.Read(&primaries.fGX);
+ reader.Read(&primaries.fGY);
+ reader.Read(&primaries.fBX);
+ reader.Read(&primaries.fBY);
+ reader.Read(&primaries.fWX);
+ reader.Read(&primaries.fWY);
+ reader.Read(&luminance_max);
+ reader.Read(&luminance_min);
+
+ target_color_params->hdr_metadata = gfx::HDRMetadata(
+ gfx::ColorVolumeMetadata(primaries, luminance_max, luminance_min),
+ max_content_light_level, max_frame_average_light_level);
+ }
return true;
}
@@ -555,6 +614,10 @@ bool ServiceImageTransferCacheEntry::Deserialize(
image_ = MakeYUVImageFromUploadedPlanes(
context_, plane_images_, plane_config_, subsampling_.value(),
yuv_color_space_.value(), decoded_color_space);
+ if (!image_) {
+ DLOG(ERROR) << "Failed to make YUV image from planes.";
+ return false;
+ }
} else {
if (!ReadPixmap(reader, rgba_pixmap)) {
DLOG(ERROR) << "Failed to read pixmap";
@@ -580,18 +643,24 @@ bool ServiceImageTransferCacheEntry::Deserialize(
image_ = rgba_pixmap_image;
}
}
- DCHECK(image_);
+ CHECK(image_);
// Perform color conversion.
if (target_color_params) {
+ auto target_color_space = target_color_params->color_space.ToSkColorSpace();
+ if (!target_color_space) {
+ DLOG(ERROR) << "Invalid target color space.";
+ return false;
+ }
+
// TODO(https://crbug.com/1286088): Pass a shared cache as a parameter.
gfx::ColorConversionSkFilterCache cache;
- image_ = cache.ConvertImage(
- image_, target_color_params->color_space.ToSkColorSpace(),
- target_color_params->sdr_max_luminance_nits,
- target_color_params->hdr_max_luminance_relative,
- target_color_params->enable_tone_mapping,
- fits_on_gpu_ ? context_ : nullptr);
+ image_ = cache.ConvertImage(image_, target_color_space,
+ target_color_params->hdr_metadata,
+ target_color_params->sdr_max_luminance_nits,
+ target_color_params->hdr_max_luminance_relative,
+ target_color_params->enable_tone_mapping,
+ fits_on_gpu_ ? context_ : nullptr);
if (!image_) {
DLOG(ERROR) << "Failed image color conversion";
return false;
diff --git a/chromium/cc/paint/oop_pixeltest.cc b/chromium/cc/paint/oop_pixeltest.cc
index 627d80255e5..dcb668c9033 100644
--- a/chromium/cc/paint/oop_pixeltest.cc
+++ b/chromium/cc/paint/oop_pixeltest.cc
@@ -112,9 +112,10 @@ class OopPixelTest : public testing::Test,
raster_context_provider_ =
base::MakeRefCounted<viz::TestInProcessContextProvider>(
- viz::TestContextType::kGpuRaster, /*support_locking=*/true,
+ viz::TestContextType::kGpuRaster, /*support_locking=*/false,
&gr_shader_cache_, &activity_flags_);
- gpu::ContextResult result = raster_context_provider_->BindToCurrentThread();
+ gpu::ContextResult result =
+ raster_context_provider_->BindToCurrentSequence();
DCHECK_EQ(result, gpu::ContextResult::kSuccess);
const int raster_max_texture_size =
raster_context_provider_->ContextCapabilities().max_texture_size;
@@ -161,10 +162,6 @@ class OopPixelTest : public testing::Test,
SkBitmap Raster(scoped_refptr<DisplayItemList> display_item_list,
const RasterOptions& options) {
- GURL url("https://example.com/foo");
- viz::TestInProcessContextProvider::ScopedRasterContextLock lock(
- raster_context_provider_.get(), url.possibly_invalid_spec().c_str());
-
absl::optional<PlaybackImageProvider::Settings> settings;
settings.emplace(PlaybackImageProvider::Settings());
settings->raster_mode = options.image_provider_raster_mode;
@@ -627,6 +624,94 @@ TEST_F(OopPixelTest, DrawImageWithTargetColorSpace) {
EXPECT_NE(actual.getColor(0, 0), SkColors::kMagenta.toSkColor());
}
+TEST_F(OopPixelTest, DrawHdrImageWithMetadata) {
+ constexpr gfx::Size size(100, 100);
+ constexpr gfx::Rect rect(size);
+ float sdr_luminance = 250.f;
+ const float kPQMaxLuminance = 10000.f;
+
+ const skcms_TransferFunction pq = SkNamedTransferFn::kPQ;
+ skcms_TransferFunction pq_inv;
+ skcms_TransferFunction_invert(&pq, &pq_inv);
+
+ const float image_luminance = 1000.f;
+ const float image_pq_pixel =
+ skcms_TransferFunction_eval(&pq_inv, image_luminance / kPQMaxLuminance);
+
+ // Create `image` with pixel value `image_pq_pixel` and PQ color space.
+ sk_sp<SkImage> image;
+ {
+ SkBitmap bitmap;
+ bitmap.allocPixelsFlags(
+ SkImageInfo::MakeN32Premul(size.width(), size.height(),
+ SkColorSpace::MakeSRGB()),
+ SkBitmap::kZeroPixels_AllocFlag);
+
+ SkCanvas canvas(bitmap, SkSurfaceProps{});
+ SkColor4f color{image_pq_pixel, image_pq_pixel, image_pq_pixel, 1.f};
+ canvas.drawColor(color);
+
+ image = SkImage::MakeFromBitmap(bitmap);
+ image = image->reinterpretColorSpace(
+ SkColorSpace::MakeRGB(pq, SkNamedGamut::kSRGB));
+ }
+
+ // Create a DisplayItemList drawing `image`.
+ const PaintImage::Id kSomeId = 32;
+ auto builder =
+ PaintImageBuilder::WithDefault().set_image(image, 0).set_id(kSomeId);
+ auto paint_image = builder.TakePaintImage();
+ auto display_item_list = base::MakeRefCounted<DisplayItemList>();
+ display_item_list->StartPaint();
+ SkSamplingOptions sampling(
+ PaintFlags::FilterQualityToSkSamplingOptions(kDefaultFilterQuality));
+ display_item_list->push<DrawImageOp>(paint_image, 0.f, 0.f, sampling,
+ nullptr);
+ display_item_list->EndPaintOfUnpaired(rect);
+ display_item_list->Finalize();
+ RasterOptions options(rect.size());
+ {
+ options.target_color_params.color_space = gfx::ColorSpace::CreateSRGB();
+ options.target_color_params.enable_tone_mapping = true;
+ options.target_color_params.sdr_max_luminance_nits = sdr_luminance;
+ options.target_color_params.hdr_metadata = gfx::HDRMetadata();
+ }
+
+ // The exact value that `image_luminance` is mapped to may change as tone
+ // mapping is tweaked. When
+ constexpr float kCutoff = 0.95f;
+
+ // Draw using image HDR metadata indicating that `image_luminance` is the
+ // maximum luminance. The result should map the image to solid white (up
+ // to rounding error).
+ {
+ options.target_color_params.hdr_metadata->color_volume_metadata =
+ gfx::ColorVolumeMetadata(SkNamedPrimariesExt::kSRGB, image_luminance,
+ 0.f);
+
+ auto actual = Raster(display_item_list, options);
+ auto color = actual.getColor4f(0, 0);
+ EXPECT_GT(color.fR, kCutoff);
+ EXPECT_GT(color.fG, kCutoff);
+ EXPECT_GT(color.fB, kCutoff);
+ }
+
+ // Draw using image HDR metadata indicating that 10,000 nits is the maximum
+ // luminance. The result should map the image to something darker than solid
+ // white.
+ {
+ options.target_color_params.hdr_metadata->color_volume_metadata =
+ gfx::ColorVolumeMetadata(SkNamedPrimariesExt::kSRGB, kPQMaxLuminance,
+ 0.f);
+
+ auto actual = Raster(display_item_list, options);
+ auto color = actual.getColor4f(0, 0);
+ EXPECT_LT(color.fR, kCutoff);
+ EXPECT_LT(color.fG, kCutoff);
+ EXPECT_LT(color.fB, kCutoff);
+ }
+}
+
TEST_F(OopPixelTest, DrawImageWithSourceColorSpace) {
constexpr gfx::Rect rect(100, 100);
diff --git a/chromium/cc/paint/paint_filter.cc b/chromium/cc/paint/paint_filter.cc
index 4eff7b1f76a..a03ce02f13d 100644
--- a/chromium/cc/paint/paint_filter.cc
+++ b/chromium/cc/paint/paint_filter.cc
@@ -11,6 +11,7 @@
#include "base/memory/values_equivalent.h"
#include "base/no_destructor.h"
#include "base/notreached.h"
+#include "base/ranges/algorithm.h"
#include "base/types/optional_util.h"
#include "build/build_config.h"
#include "cc/paint/draw_image.h"
@@ -27,230 +28,11 @@
#include "third_party/skia/include/effects/SkImageFilters.h"
#include "third_party/skia/include/effects/SkPerlinNoiseShader.h"
#include "third_party/skia/include/effects/SkRuntimeEffect.h"
-#include "third_party/skia/src/effects/imagefilters/SkRuntimeImageFilter.h"
namespace cc {
namespace {
const bool kHasNoDiscardableImages = false;
-#if BUILDFLAG(IS_ANDROID)
-struct StretchShaderUniforms {
- // multiplier to apply to scale effect
- float uMaxStretchIntensity;
-
- // Maximum percentage to stretch beyond bounds of target
- float uStretchAffectedDistX;
- float uStretchAffectedDistY;
-
- // Distance stretched as a function of the normalized overscroll times
- // scale intensity
- float uDistanceStretchedX;
- float uDistanceStretchedY;
- float uInverseDistanceStretchedX;
- float uInverseDistanceStretchedY;
- float uDistDiffX;
-
- // Difference between the peak stretch amount and overscroll amount normalized
- float uDistDiffY;
-
- // Horizontal offset represented as a ratio of pixels divided by the target
- // width
- float uScrollX;
- // Vertical offset represented as a ratio of pixels divided by the target
- // height
- float uScrollY;
-
- // Normalized overscroll amount in the horizontal direction
- float uOverscrollX;
-
- // Normalized overscroll amount in the vertical direction
- float uOverscrollY;
- float viewportWidth; // target height in pixels
- float viewportHeight; // target width in pixels
-
- // uInterpolationStrength is the intensity of the interpolation.
- // if uInterpolationStrength is 0, then the stretch is constant for all the
- // uStretchAffectedDist. if uInterpolationStrength is 1, then stretch
- // intensity is interpolated based on the pixel position in the
- // uStretchAffectedDist area; The closer we are from the scroll anchor point,
- // the more it stretches, and the other way around.
- float uInterpolationStrength;
-};
-
-const char* kStretchShader = R"(
- uniform shader uContentTexture;
-
- // multiplier to apply to scale effect
- uniform float uMaxStretchIntensity;
-
- // Maximum percentage to stretch beyond bounds of target
- uniform float uStretchAffectedDistX;
- uniform float uStretchAffectedDistY;
-
- // Distance stretched as a function of the normalized overscroll times
- // scale intensity
- uniform float uDistanceStretchedX;
- uniform float uDistanceStretchedY;
- uniform float uInverseDistanceStretchedX;
- uniform float uInverseDistanceStretchedY;
- uniform float uDistDiffX;
-
- // Difference between the peak stretch amount and overscroll amount
- // normalized
- uniform float uDistDiffY;
-
- // Horizontal offset represented as a ratio of pixels divided by the target
- // width
- uniform float uScrollX;
- // Vertical offset represented as a ratio of pixels divided by the target
- // height
- uniform float uScrollY;
-
- // Normalized overscroll amount in the horizontal direction
- uniform float uOverscrollX;
-
- // Normalized overscroll amount in the vertical direction
- uniform float uOverscrollY;
- uniform float viewportWidth; // target height in pixels
- uniform float viewportHeight; // target width in pixels
-
- // uInterpolationStrength is the intensity of the interpolation.
- // if uInterpolationStrength is 0, then the stretch is constant for all the
- // uStretchAffectedDist. if uInterpolationStrength is 1, then stretch
- // intensity is interpolated based on the pixel position in the
- // uStretchAffectedDist area; The closer we are from the scroll anchor
- // point, the more it stretches, and the other way around.
- uniform float uInterpolationStrength;
-
- float easeInCubic(float t, float d) {
- float tmp = t * d;
- return tmp * tmp * tmp;
- }
-
- float computeOverscrollStart(
- float inPos,
- float overscroll,
- float uStretchAffectedDist,
- float uInverseStretchAffectedDist,
- float distanceStretched,
- float interpolationStrength
- ) {
- float offsetPos = uStretchAffectedDist - inPos;
- float posBasedVariation = mix(
- 1. ,easeInCubic(offsetPos, uInverseStretchAffectedDist),
- interpolationStrength);
- float stretchIntensity = overscroll * posBasedVariation;
- return distanceStretched - (offsetPos / (1. + stretchIntensity));
- }
-
- float computeOverscrollEnd(
- float inPos,
- float overscroll,
- float reverseStretchDist,
- float uStretchAffectedDist,
- float uInverseStretchAffectedDist,
- float distanceStretched,
- float interpolationStrength
- ) {
- float offsetPos = inPos - reverseStretchDist;
- float posBasedVariation = mix(
- 1. ,easeInCubic(offsetPos, uInverseStretchAffectedDist),
- interpolationStrength);
- float stretchIntensity = (-overscroll) * posBasedVariation;
- return 1 - (distanceStretched - (offsetPos / (1. + stretchIntensity)));
- }
-
- // Prefer usage of return values over out parameters as it enables
- // SKSL to properly inline method calls and works around potential GPU
- // driver issues on Wembly. See b/182566543 for details
- float computeOverscroll(
- float inPos,
- float overscroll,
- float uStretchAffectedDist,
- float uInverseStretchAffectedDist,
- float distanceStretched,
- float distanceDiff,
- float interpolationStrength
- ) {
- float outPos = inPos;
- if (overscroll > 0) {
- if (inPos <= uStretchAffectedDist) {
- outPos = computeOverscrollStart(
- inPos,
- overscroll,
- uStretchAffectedDist,
- uInverseStretchAffectedDist,
- distanceStretched,
- interpolationStrength
- );
- } else if (inPos >= distanceStretched) {
- outPos = distanceDiff + inPos;
- }
- }
- if (overscroll < 0) {
- float stretchAffectedDist = 1. - uStretchAffectedDist;
- if (inPos >= stretchAffectedDist) {
- outPos = computeOverscrollEnd(
- inPos,
- overscroll,
- stretchAffectedDist,
- uStretchAffectedDist,
- uInverseStretchAffectedDist,
- distanceStretched,
- interpolationStrength
- );
- } else if (inPos < stretchAffectedDist) {
- outPos = -distanceDiff + inPos;
- }
- }
- return outPos;
- }
-
- vec4 main(vec2 coord) {
- // Normalize SKSL pixel coordinate into a unit vector
- float inU = coord.x / viewportWidth;
- float inV = coord.y / viewportHeight;
- float outU;
- float outV;
- float stretchIntensity;
- // Add the normalized scroll position within scrolling list
- inU += uScrollX;
- inV += uScrollY;
- outU = inU;
- outV = inV;
- outU = computeOverscroll(
- inU,
- uOverscrollX,
- uStretchAffectedDistX,
- uInverseDistanceStretchedX,
- uDistanceStretchedX,
- uDistDiffX,
- uInterpolationStrength
- );
- outV = computeOverscroll(
- inV,
- uOverscrollY,
- uStretchAffectedDistY,
- uInverseDistanceStretchedY,
- uDistanceStretchedY,
- uDistDiffY,
- uInterpolationStrength
- );
- coord.x = outU * viewportWidth;
- coord.y = outV * viewportHeight;
- return uContentTexture.eval(coord);
- })";
-
-static const float CONTENT_DISTANCE_STRETCHED = 1.f;
-static const float INTERPOLATION_STRENGTH_VALUE = 0.7f;
-
-sk_sp<SkRuntimeEffect> getStretchEffect() {
- static base::NoDestructor<SkRuntimeEffect::Result> effect(
- SkRuntimeEffect::MakeForShader(SkString(kStretchShader)));
- return effect->effect;
-}
-#endif
-
bool AreScalarsEqual(SkScalar one, SkScalar two) {
return PaintOp::AreEqualEvenIfNaN(one, two);
}
@@ -335,8 +117,6 @@ std::string PaintFilter::TypeToString(Type type) {
return "kLightingPoint";
case Type::kLightingSpot:
return "kLightingSpot";
- case Type::kStretch:
- return "kStretch";
}
NOTREACHED();
return "Unknown";
@@ -453,9 +233,6 @@ bool PaintFilter::operator==(const PaintFilter& other) const {
case Type::kLightingSpot:
return *static_cast<const LightingSpotPaintFilter*>(this) ==
static_cast<const LightingSpotPaintFilter&>(other);
- case Type::kStretch:
- return *static_cast<const StretchPaintFilter*>(this) ==
- static_cast<const StretchPaintFilter&>(other);
}
NOTREACHED();
return true;
@@ -838,8 +615,8 @@ sk_sp<PaintFilter> MatrixConvolutionPaintFilter::SnapshotWithImagesInternal(
bool MatrixConvolutionPaintFilter::operator==(
const MatrixConvolutionPaintFilter& other) const {
return kernel_size_ == other.kernel_size_ &&
- std::equal(kernel_.container().begin(), kernel_.container().end(),
- other.kernel_.container().begin(), AreScalarsEqual) &&
+ base::ranges::equal(kernel_.container(), other.kernel_.container(),
+ AreScalarsEqual) &&
PaintOp::AreEqualEvenIfNaN(gain_, other.gain_) &&
PaintOp::AreEqualEvenIfNaN(bias_, other.bias_) &&
kernel_offset_ == other.kernel_offset_ &&
@@ -1574,78 +1351,4 @@ bool LightingSpotPaintFilter::operator==(
base::ValuesEquivalent(input_.get(), other.input_.get());
}
-StretchPaintFilter::StretchPaintFilter(SkScalar stretch_x,
- SkScalar stretch_y,
- SkScalar width,
- SkScalar height,
- sk_sp<PaintFilter> input,
- const CropRect* crop_rect)
- : PaintFilter(kType, crop_rect, HasDiscardableImages(input)),
- stretch_x_(stretch_x),
- stretch_y_(stretch_y),
- width_(width),
- height_(height),
- input_(std::move(input)) {
-#if BUILDFLAG(IS_ANDROID)
- float normOverScrollDistX = stretch_x_;
- float normOverScrollDistY = stretch_y_;
- float distanceStretchedX =
- CONTENT_DISTANCE_STRETCHED / (1 + std::abs(normOverScrollDistX));
- float distanceStretchedY =
- CONTENT_DISTANCE_STRETCHED / (1 + std::abs(normOverScrollDistY));
- float inverseDistanceStretchedX = 1.f / CONTENT_DISTANCE_STRETCHED;
- float inverseDistanceStretchedY = 1.f / CONTENT_DISTANCE_STRETCHED;
- float diffX = distanceStretchedX - CONTENT_DISTANCE_STRETCHED;
- float diffY = distanceStretchedY - CONTENT_DISTANCE_STRETCHED;
- StretchShaderUniforms uniforms;
-
- uniforms.uInterpolationStrength = INTERPOLATION_STRENGTH_VALUE;
- uniforms.uStretchAffectedDistX = CONTENT_DISTANCE_STRETCHED;
- uniforms.uStretchAffectedDistY = CONTENT_DISTANCE_STRETCHED;
- uniforms.uDistanceStretchedX = distanceStretchedX;
- uniforms.uDistanceStretchedY = distanceStretchedY;
- uniforms.uInverseDistanceStretchedX = inverseDistanceStretchedX;
- uniforms.uInverseDistanceStretchedY = inverseDistanceStretchedY;
- uniforms.uDistDiffX = diffX;
- uniforms.uDistDiffY = diffY;
- uniforms.uOverscrollX = normOverScrollDistX;
- uniforms.uOverscrollY = normOverScrollDistY;
- uniforms.uScrollX = 0;
- uniforms.uScrollY = 0;
- uniforms.viewportWidth = width;
- uniforms.viewportHeight = height;
- sk_sp<SkData> uniformVals = SkData::MakeWithCopy(&uniforms, sizeof(uniforms));
- cached_sk_filter_ = SkMakeRuntimeImageFilter(getStretchEffect(), uniformVals,
- GetSkFilter(input_.get()));
-#else // BUILDFLAG(IS_ANDROID)
- // Stretch filter is only used on android and removed from other platforms
- // to reduce size. See https://crbug.com/1226170.
-#endif // BUILDFLAG(IS_ANDROID)
-}
-
-StretchPaintFilter::~StretchPaintFilter() = default;
-
-size_t StretchPaintFilter::SerializedSize() const {
- base::CheckedNumeric<size_t> total_size =
- BaseSerializedSize() + sizeof(stretch_x_) + sizeof(stretch_y_) +
- sizeof(width_) + sizeof(height_);
- total_size += GetFilterSize(input_.get());
- return total_size.ValueOrDefault(0u);
-}
-
-sk_sp<PaintFilter> StretchPaintFilter::SnapshotWithImagesInternal(
- ImageProvider* image_provider) const {
- return sk_make_sp<StretchPaintFilter>(stretch_x_, stretch_y_, width_, height_,
- Snapshot(input_, image_provider),
- GetCropRect());
-}
-
-bool StretchPaintFilter::operator==(const StretchPaintFilter& other) const {
- return PaintOp::AreEqualEvenIfNaN(stretch_x_, other.stretch_x_) &&
- PaintOp::AreEqualEvenIfNaN(stretch_y_, other.stretch_y_) &&
- PaintOp::AreEqualEvenIfNaN(width_, other.width_) &&
- PaintOp::AreEqualEvenIfNaN(height_, other.height_) &&
- base::ValuesEquivalent(input_.get(), other.input_.get());
-}
-
} // namespace cc
diff --git a/chromium/cc/paint/paint_filter.h b/chromium/cc/paint/paint_filter.h
index 3f7936f01a7..a3d12e68b16 100644
--- a/chromium/cc/paint/paint_filter.h
+++ b/chromium/cc/paint/paint_filter.h
@@ -55,9 +55,8 @@ class CC_PAINT_EXPORT PaintFilter : public SkRefCnt {
kLightingDistant,
kLightingPoint,
kLightingSpot,
- kStretch,
- // Update the following if kStretch is not the max anymore.
- kMaxValue = kStretch
+ // Update the following if kLightingSpot is not the max anymore.
+ kMaxValue = kLightingSpot
};
enum class LightingType {
kDiffuse,
@@ -878,39 +877,6 @@ class CC_PAINT_EXPORT LightingSpotPaintFilter final : public PaintFilter {
sk_sp<PaintFilter> input_;
};
-class CC_PAINT_EXPORT StretchPaintFilter final : public PaintFilter {
- public:
- static constexpr Type kType = Type::kStretch;
- StretchPaintFilter(SkScalar stretch_x,
- SkScalar stretch_y,
- SkScalar width,
- SkScalar height,
- sk_sp<PaintFilter> input,
- const CropRect* crop_rect = nullptr);
- ~StretchPaintFilter() override;
-
- const sk_sp<PaintFilter>& input() const { return input_; }
-
- SkScalar stretch_x() const { return stretch_x_; }
- SkScalar stretch_y() const { return stretch_y_; }
- SkScalar width() const { return width_; }
- SkScalar height() const { return height_; }
-
- size_t SerializedSize() const override;
- bool operator==(const StretchPaintFilter& other) const;
-
- protected:
- sk_sp<PaintFilter> SnapshotWithImagesInternal(
- ImageProvider* image_provider) const override;
-
- private:
- SkScalar stretch_x_;
- SkScalar stretch_y_;
- SkScalar width_;
- SkScalar height_;
- sk_sp<PaintFilter> input_;
-};
-
} // namespace cc
#endif // CC_PAINT_PAINT_FILTER_H_
diff --git a/chromium/cc/paint/paint_filter_unittest.cc b/chromium/cc/paint/paint_filter_unittest.cc
index c88a719a3ab..a34c7be6701 100644
--- a/chromium/cc/paint/paint_filter_unittest.cc
+++ b/chromium/cc/paint/paint_filter_unittest.cc
@@ -5,7 +5,7 @@
#include "cc/paint/paint_filter.h"
#include "cc/paint/image_provider.h"
-#include "cc/paint/paint_op_buffer.h"
+#include "cc/paint/paint_op.h"
#include "cc/test/skia_common.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/effects/SkLumaColorFilter.h"
@@ -134,9 +134,6 @@ sk_sp<PaintFilter> CreateTestFilter(PaintFilter::Type filter_type,
PaintFilter::LightingType::kDiffuse, SkPoint3::Make(0.1f, 0.2f, 0.3f),
SkPoint3::Make(0.4f, 0.5f, 0.6f), 0.1f, 0.2f, SkColors::kWhite, 0.4f,
0.5f, 0.6f, image_filter, &crop_rect);
- case PaintFilter::Type::kStretch:
- return sk_make_sp<StretchPaintFilter>(0.1f, 0.2f, 100.f, 200.f,
- image_filter, &crop_rect);
}
NOTREACHED();
return nullptr;
diff --git a/chromium/cc/paint/paint_flags.cc b/chromium/cc/paint/paint_flags.cc
index f42ba0a134f..0a7c1831f5a 100644
--- a/chromium/cc/paint/paint_flags.cc
+++ b/chromium/cc/paint/paint_flags.cc
@@ -11,6 +11,7 @@
#include "cc/paint/paint_op_buffer.h"
#include "cc/paint/paint_op_writer.h"
#include "cc/paint/paint_shader.h"
+#include "third_party/skia/include/core/SkPathUtils.h"
namespace {
@@ -99,7 +100,7 @@ bool PaintFlags::getFillPath(const SkPath& src,
const SkRect* cull_rect,
SkScalar res_scale) const {
SkPaint paint = ToSkPaint();
- return paint.getFillPath(src, dst, cull_rect, res_scale);
+ return skpathutils::FillPathWithPaint(src, paint, dst, cull_rect, res_scale);
}
bool PaintFlags::IsSimpleOpacity() const {
diff --git a/chromium/cc/paint/paint_image.h b/chromium/cc/paint/paint_image.h
index bea6435d8fd..f412aa9785a 100644
--- a/chromium/cc/paint/paint_image.h
+++ b/chromium/cc/paint/paint_image.h
@@ -22,6 +22,7 @@
#include "ui/gfx/display_color_spaces.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/hdr_metadata.h"
class SkBitmap;
class SkColorSpace;
@@ -39,17 +40,7 @@ class PaintWorkletInput;
class TextureBacking;
using PaintRecord = PaintOpBuffer;
-enum class ImageType {
- kPNG,
- kJPEG,
- kWEBP,
- kGIF,
- kICO,
- kBMP,
- kAVIF,
- kJXL,
- kInvalid
-};
+enum class ImageType { kPNG, kJPEG, kWEBP, kGIF, kICO, kBMP, kAVIF, kInvalid };
enum class YUVSubsampling { k410, k411, k420, k422, k440, k444, kUnknown };
@@ -71,6 +62,9 @@ struct CC_PAINT_EXPORT ImageHeaderMetadata {
// The subsampling format used for the chroma planes, e.g., YUV 4:2:0.
YUVSubsampling yuv_subsampling = YUVSubsampling::kUnknown;
+ // The HDR metadata included with the image, if present.
+ absl::optional<gfx::HDRMetadata> hdr_metadata;
+
// The visible size of the image (i.e., the area that contains meaningful
// pixels).
gfx::Size image_size;
diff --git a/chromium/cc/paint/paint_op.cc b/chromium/cc/paint/paint_op.cc
new file mode 100644
index 00000000000..80bb723fc65
--- /dev/null
+++ b/chromium/cc/paint/paint_op.cc
@@ -0,0 +1,2864 @@
+// Copyright 2017 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/paint/paint_op.h"
+
+#include <algorithm>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/memory/raw_ptr.h"
+#include "base/notreached.h"
+#include "base/types/optional_util.h"
+#include "cc/paint/decoded_draw_image.h"
+#include "cc/paint/display_item_list.h"
+#include "cc/paint/image_provider.h"
+#include "cc/paint/paint_flags.h"
+#include "cc/paint/paint_image_builder.h"
+#include "cc/paint/paint_op_reader.h"
+#include "cc/paint/paint_op_writer.h"
+#include "cc/paint/paint_record.h"
+#include "cc/paint/skottie_serialization_history.h"
+#include "third_party/skia/include/core/SkAnnotation.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkColorSpace.h"
+#include "third_party/skia/include/core/SkImage.h"
+#include "third_party/skia/include/core/SkRegion.h"
+#include "third_party/skia/include/core/SkSerialProcs.h"
+#include "third_party/skia/include/core/SkTextBlob.h"
+#include "third_party/skia/include/docs/SkPDFDocument.h"
+#include "third_party/skia/include/private/chromium/GrSlug.h"
+#include "ui/gfx/geometry/skia_conversions.h"
+
+namespace cc {
+namespace {
+// In a future CL, convert DrawImage to explicitly take sampling instead of
+// quality
+PaintFlags::FilterQuality sampling_to_quality(
+ const SkSamplingOptions& sampling) {
+ if (sampling.useCubic) {
+ return PaintFlags::FilterQuality::kHigh;
+ }
+ if (sampling.mipmap != SkMipmapMode::kNone) {
+ return PaintFlags::FilterQuality::kMedium;
+ }
+ return sampling.filter == SkFilterMode::kLinear
+ ? PaintFlags::FilterQuality::kLow
+ : PaintFlags::FilterQuality::kNone;
+}
+
+DrawImage CreateDrawImage(const PaintImage& image,
+ const PaintFlags* flags,
+ const SkSamplingOptions& sampling,
+ const SkM44& matrix) {
+ if (!image)
+ return DrawImage();
+ return DrawImage(image, flags->useDarkModeForImage(),
+ SkIRect::MakeWH(image.width(), image.height()),
+ sampling_to_quality(sampling), matrix);
+}
+
+bool IsScaleAdjustmentIdentity(const SkSize& scale_adjustment) {
+ return std::abs(scale_adjustment.width() - 1.f) < FLT_EPSILON &&
+ std::abs(scale_adjustment.height() - 1.f) < FLT_EPSILON;
+}
+
+SkRect AdjustSrcRectForScale(SkRect original, SkSize scale_adjustment) {
+ if (IsScaleAdjustmentIdentity(scale_adjustment))
+ return original;
+
+ float x_scale = scale_adjustment.width();
+ float y_scale = scale_adjustment.height();
+ return SkRect::MakeXYWH(original.x() * x_scale, original.y() * y_scale,
+ original.width() * x_scale,
+ original.height() * y_scale);
+}
+
+SkRect MapRect(const SkMatrix& matrix, const SkRect& src) {
+ SkRect dst;
+ matrix.mapRect(&dst, src);
+ return dst;
+}
+
+void DrawImageRect(SkCanvas* canvas,
+ const SkImage* image,
+ const SkRect& src,
+ const SkRect& dst,
+ const SkSamplingOptions& options,
+ const SkPaint* paint,
+ SkCanvas::SrcRectConstraint constraint) {
+ if (!image)
+ return;
+ if (constraint == SkCanvas::kStrict_SrcRectConstraint &&
+ options.mipmap != SkMipmapMode::kNone &&
+ src.contains(SkRect::Make(image->dimensions()))) {
+ SkMatrix m;
+ m.setRectToRect(src, dst, SkMatrix::ScaleToFit::kFill_ScaleToFit);
+ canvas->save();
+ canvas->concat(m);
+ canvas->drawImage(image, 0, 0, options, paint);
+ canvas->restore();
+ return;
+ }
+ canvas->drawImageRect(image, src, dst, options, paint, constraint);
+}
+
+bool GrSlugAreEqual(sk_sp<GrSlug> left, sk_sp<GrSlug> right) {
+ if (!left && !right) {
+ return true;
+ }
+ if (left && right) {
+ auto left_data = left->serialize();
+ auto right_data = right->serialize();
+ return left_data->equals(right_data.get());
+ }
+ return false;
+}
+
+} // namespace
+
+#define TYPES(M) \
+ M(AnnotateOp) \
+ M(ClipPathOp) \
+ M(ClipRectOp) \
+ M(ClipRRectOp) \
+ M(ConcatOp) \
+ M(CustomDataOp) \
+ M(DrawColorOp) \
+ M(DrawDRRectOp) \
+ M(DrawImageOp) \
+ M(DrawImageRectOp) \
+ M(DrawIRectOp) \
+ M(DrawLineOp) \
+ M(DrawOvalOp) \
+ M(DrawPathOp) \
+ M(DrawRecordOp) \
+ M(DrawRectOp) \
+ M(DrawRRectOp) \
+ M(DrawSkottieOp) \
+ M(DrawTextBlobOp) \
+ M(NoopOp) \
+ M(RestoreOp) \
+ M(RotateOp) \
+ M(SaveOp) \
+ M(SaveLayerOp) \
+ M(SaveLayerAlphaOp) \
+ M(ScaleOp) \
+ M(SetMatrixOp) \
+ M(SetNodeIdOp) \
+ M(TranslateOp)
+
+static constexpr size_t kNumOpTypes =
+ static_cast<size_t>(PaintOpType::LastPaintOpType) + 1;
+
+// Verify that every op is in the TYPES macro.
+#define M(T) +1
+static_assert(kNumOpTypes == TYPES(M), "Missing op in list");
+#undef M
+
+#define M(T) sizeof(T),
+static const size_t g_type_to_size[kNumOpTypes] = {TYPES(M)};
+#undef M
+
+template <typename T, bool HasFlags>
+struct Rasterizer {
+ static void RasterWithFlags(const T* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const PlaybackParams& params) {
+ static_assert(
+ !T::kHasPaintFlags,
+ "This function should not be used for a PaintOp that has PaintFlags");
+ DCHECK(op->IsValid());
+ NOTREACHED();
+ }
+ static void Raster(const T* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params) {
+ static_assert(
+ !T::kHasPaintFlags,
+ "This function should not be used for a PaintOp that has PaintFlags");
+ DCHECK(op->IsValid());
+ T::Raster(op, canvas, params);
+ }
+};
+
+template <typename T>
+struct Rasterizer<T, true> {
+ static void RasterWithFlags(const T* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const PlaybackParams& params) {
+ static_assert(T::kHasPaintFlags,
+ "This function expects the PaintOp to have PaintFlags");
+ DCHECK(op->IsValid());
+ T::RasterWithFlags(op, flags, canvas, params);
+ }
+
+ static void Raster(const T* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params) {
+ static_assert(T::kHasPaintFlags,
+ "This function expects the PaintOp to have PaintFlags");
+ DCHECK(op->IsValid());
+ T::RasterWithFlags(op, &op->flags, canvas, params);
+ }
+};
+
+using RasterFunction = void (*)(const PaintOp* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params);
+#define M(T) \
+ [](const PaintOp* op, SkCanvas* canvas, const PlaybackParams& params) { \
+ Rasterizer<T, T::kHasPaintFlags>::Raster(static_cast<const T*>(op), \
+ canvas, params); \
+ },
+static const RasterFunction g_raster_functions[kNumOpTypes] = {TYPES(M)};
+#undef M
+
+using RasterWithFlagsFunction = void (*)(const PaintOp* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const PlaybackParams& params);
+#define M(T) \
+ [](const PaintOp* op, const PaintFlags* flags, SkCanvas* canvas, \
+ const PlaybackParams& params) { \
+ Rasterizer<T, T::kHasPaintFlags>::RasterWithFlags( \
+ static_cast<const T*>(op), flags, canvas, params); \
+ },
+static const RasterWithFlagsFunction
+ g_raster_with_flags_functions[kNumOpTypes] = {TYPES(M)};
+#undef M
+
+using SerializeFunction = size_t (*)(const PaintOp* op,
+ void* memory,
+ size_t size,
+ const PaintOp::SerializeOptions& options,
+ const PaintFlags* flags_to_serialize,
+ const SkM44& current_ctm,
+ const SkM44& original_ctm);
+
+#define M(T) &T::Serialize,
+static const SerializeFunction g_serialize_functions[kNumOpTypes] = {TYPES(M)};
+#undef M
+
+using DeserializeFunction =
+ PaintOp* (*)(const volatile void* input,
+ size_t input_size,
+ void* output,
+ size_t output_size,
+ const PaintOp::DeserializeOptions& options);
+
+#define M(T) &T::Deserialize,
+static const DeserializeFunction g_deserialize_functions[kNumOpTypes] = {
+ TYPES(M)};
+#undef M
+
+using EqualsFunction = bool (*)(const PaintOp* left, const PaintOp* right);
+#define M(T) &T::AreEqual,
+static const EqualsFunction g_equals_operator[kNumOpTypes] = {TYPES(M)};
+#undef M
+
+// Most state ops (matrix, clip, save, restore) have a trivial destructor.
+// TODO(enne): evaluate if we need the nullptr optimization or if
+// we even need to differentiate trivial destructors here.
+using VoidFunction = void (*)(PaintOp* op);
+#define M(T) \
+ !std::is_trivially_destructible<T>::value \
+ ? [](PaintOp* op) { static_cast<T*>(op)->~T(); } \
+ : static_cast<VoidFunction>(nullptr),
+static const VoidFunction g_destructor_functions[kNumOpTypes] = {TYPES(M)};
+#undef M
+
+#define M(T) T::kIsDrawOp,
+static bool g_is_draw_op[kNumOpTypes] = {TYPES(M)};
+#undef M
+
+#define M(T) T::kHasPaintFlags,
+static bool g_has_paint_flags[kNumOpTypes] = {TYPES(M)};
+#undef M
+
+#define M(T) \
+ static_assert(sizeof(T) <= sizeof(LargestPaintOp), \
+ #T " must be no bigger than LargestPaintOp");
+TYPES(M)
+#undef M
+
+#define M(T) \
+ static_assert(alignof(T) <= PaintOpBuffer::kPaintOpAlign, \
+ #T " must have alignment no bigger than PaintOpAlign");
+TYPES(M)
+#undef M
+
+using AnalyzeOpFunc = void (*)(PaintOpBuffer*, const PaintOp*);
+#define M(T) \
+ [](PaintOpBuffer* buffer, const PaintOp* op) { \
+ buffer->AnalyzeAddedOp(static_cast<const T*>(op)); \
+ },
+static const AnalyzeOpFunc g_analyze_op_functions[kNumOpTypes] = {TYPES(M)};
+#undef M
+
+#undef TYPES
+
+const SkRect PaintOp::kUnsetRect = {SK_ScalarInfinity, 0, 0, 0};
+const size_t PaintOp::kMaxSkip;
+
+std::string PaintOpTypeToString(PaintOpType type) {
+ switch (type) {
+ case PaintOpType::Annotate:
+ return "Annotate";
+ case PaintOpType::ClipPath:
+ return "ClipPath";
+ case PaintOpType::ClipRect:
+ return "ClipRect";
+ case PaintOpType::ClipRRect:
+ return "ClipRRect";
+ case PaintOpType::Concat:
+ return "Concat";
+ case PaintOpType::CustomData:
+ return "CustomData";
+ case PaintOpType::DrawColor:
+ return "DrawColor";
+ case PaintOpType::DrawDRRect:
+ return "DrawDRRect";
+ case PaintOpType::DrawImage:
+ return "DrawImage";
+ case PaintOpType::DrawImageRect:
+ return "DrawImageRect";
+ case PaintOpType::DrawIRect:
+ return "DrawIRect";
+ case PaintOpType::DrawLine:
+ return "DrawLine";
+ case PaintOpType::DrawOval:
+ return "DrawOval";
+ case PaintOpType::DrawPath:
+ return "DrawPath";
+ case PaintOpType::DrawRecord:
+ return "DrawRecord";
+ case PaintOpType::DrawRect:
+ return "DrawRect";
+ case PaintOpType::DrawRRect:
+ return "DrawRRect";
+ case PaintOpType::DrawSkottie:
+ return "DrawSkottie";
+ case PaintOpType::DrawTextBlob:
+ return "DrawTextBlob";
+ case PaintOpType::Noop:
+ return "Noop";
+ case PaintOpType::Restore:
+ return "Restore";
+ case PaintOpType::Rotate:
+ return "Rotate";
+ case PaintOpType::Save:
+ return "Save";
+ case PaintOpType::SaveLayer:
+ return "SaveLayer";
+ case PaintOpType::SaveLayerAlpha:
+ return "SaveLayerAlpha";
+ case PaintOpType::Scale:
+ return "Scale";
+ case PaintOpType::SetMatrix:
+ return "SetMatrix";
+ case PaintOpType::SetNodeId:
+ return "SetNodeId";
+ case PaintOpType::Translate:
+ return "Translate";
+ }
+ return "UNKNOWN";
+}
+
+std::ostream& operator<<(std::ostream& os, PaintOpType type) {
+ return os << PaintOpTypeToString(type);
+}
+
+size_t AnnotateOp::Serialize(const PaintOp* base_op,
+ void* memory,
+ size_t size,
+ const SerializeOptions& options,
+ const PaintFlags* flags_to_serialize,
+ const SkM44& current_ctm,
+ const SkM44& original_ctm) {
+ auto* op = static_cast<const AnnotateOp*>(base_op);
+ PaintOpWriter helper(memory, size, options);
+ helper.Write(op->annotation_type);
+ helper.Write(op->rect);
+ helper.Write(op->data);
+ return helper.size();
+}
+
+size_t ClipPathOp::Serialize(const PaintOp* base_op,
+ void* memory,
+ size_t size,
+ const SerializeOptions& options,
+ const PaintFlags* flags_to_serialize,
+ const SkM44& current_ctm,
+ const SkM44& original_ctm) {
+ auto* op = static_cast<const ClipPathOp*>(base_op);
+ PaintOpWriter helper(memory, size, options);
+ helper.Write(op->path, op->use_cache);
+ helper.Write(op->op);
+ helper.Write(op->antialias);
+ return helper.size();
+}
+
+size_t ClipRectOp::Serialize(const PaintOp* base_op,
+ void* memory,
+ size_t size,
+ const SerializeOptions& options,
+ const PaintFlags* flags_to_serialize,
+ const SkM44& current_ctm,
+ const SkM44& original_ctm) {
+ auto* op = static_cast<const ClipRectOp*>(base_op);
+ PaintOpWriter helper(memory, size, options);
+ helper.Write(op->rect);
+ helper.Write(op->op);
+ helper.Write(op->antialias);
+ return helper.size();
+}
+
+size_t ClipRRectOp::Serialize(const PaintOp* base_op,
+ void* memory,
+ size_t size,
+ const SerializeOptions& options,
+ const PaintFlags* flags_to_serialize,
+ const SkM44& current_ctm,
+ const SkM44& original_ctm) {
+ auto* op = static_cast<const ClipRRectOp*>(base_op);
+ PaintOpWriter helper(memory, size, options);
+ helper.Write(op->rrect);
+ helper.Write(op->op);
+ helper.Write(op->antialias);
+ return helper.size();
+}
+
+size_t ConcatOp::Serialize(const PaintOp* base_op,
+ void* memory,
+ size_t size,
+ const SerializeOptions& options,
+ const PaintFlags* flags_to_serialize,
+ const SkM44& current_ctm,
+ const SkM44& original_ctm) {
+ auto* op = static_cast<const ConcatOp*>(base_op);
+ PaintOpWriter helper(memory, size, options);
+ helper.Write(op->matrix);
+ return helper.size();
+}
+
+size_t CustomDataOp::Serialize(const PaintOp* base_op,
+ void* memory,
+ size_t size,
+ const SerializeOptions& options,
+ const PaintFlags* flags_to_serialize,
+ const SkM44& current_ctm,
+ const SkM44& original_ctm) {
+ auto* op = static_cast<const CustomDataOp*>(base_op);
+ PaintOpWriter helper(memory, size, options);
+ helper.Write(op->id);
+ return helper.size();
+}
+
+size_t DrawColorOp::Serialize(const PaintOp* base_op,
+ void* memory,
+ size_t size,
+ const SerializeOptions& options,
+ const PaintFlags* flags_to_serialize,
+ const SkM44& current_ctm,
+ const SkM44& original_ctm) {
+ auto* op = static_cast<const DrawColorOp*>(base_op);
+ PaintOpWriter helper(memory, size, options);
+ helper.Write(op->color);
+ helper.Write(op->mode);
+ return helper.size();
+}
+
+size_t DrawDRRectOp::Serialize(const PaintOp* base_op,
+ void* memory,
+ size_t size,
+ const SerializeOptions& options,
+ const PaintFlags* flags_to_serialize,
+ const SkM44& current_ctm,
+ const SkM44& original_ctm) {
+ auto* op = static_cast<const DrawDRRectOp*>(base_op);
+ PaintOpWriter helper(memory, size, options);
+ if (!flags_to_serialize)
+ flags_to_serialize = &op->flags;
+ helper.Write(*flags_to_serialize, current_ctm);
+ helper.Write(op->outer);
+ helper.Write(op->inner);
+ return helper.size();
+}
+
+size_t DrawImageOp::Serialize(const PaintOp* base_op,
+ void* memory,
+ size_t size,
+ const SerializeOptions& options,
+ const PaintFlags* flags_to_serialize,
+ const SkM44& current_ctm,
+ const SkM44& original_ctm) {
+ auto* op = static_cast<const DrawImageOp*>(base_op);
+ PaintOpWriter helper(memory, size, options);
+ if (!flags_to_serialize)
+ flags_to_serialize = &op->flags;
+ helper.Write(*flags_to_serialize, current_ctm);
+
+ SkSize scale_adjustment = SkSize::Make(1.f, 1.f);
+ helper.Write(
+ CreateDrawImage(op->image, flags_to_serialize, op->sampling, current_ctm),
+ &scale_adjustment);
+ helper.AssertAlignment(alignof(SkScalar));
+ helper.Write(scale_adjustment.width());
+ helper.Write(scale_adjustment.height());
+
+ helper.Write(op->left);
+ helper.Write(op->top);
+ helper.Write(op->sampling);
+ return helper.size();
+}
+
+size_t DrawImageRectOp::Serialize(const PaintOp* base_op,
+ void* memory,
+ size_t size,
+ const SerializeOptions& options,
+ const PaintFlags* flags_to_serialize,
+ const SkM44& current_ctm,
+ const SkM44& original_ctm) {
+ auto* op = static_cast<const DrawImageRectOp*>(base_op);
+ PaintOpWriter helper(memory, size, options);
+ if (!flags_to_serialize)
+ flags_to_serialize = &op->flags;
+ helper.Write(*flags_to_serialize, current_ctm);
+
+ // This adjustment mirrors DiscardableImageMap::GatherDiscardableImage logic.
+ SkM44 matrix = current_ctm * SkM44(SkMatrix::RectToRect(op->src, op->dst));
+ // 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, flags_to_serialize, op->sampling, matrix),
+ &scale_adjustment);
+ helper.AssertAlignment(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();
+}
+
+size_t DrawIRectOp::Serialize(const PaintOp* base_op,
+ void* memory,
+ size_t size,
+ const SerializeOptions& options,
+ const PaintFlags* flags_to_serialize,
+ const SkM44& current_ctm,
+ const SkM44& original_ctm) {
+ auto* op = static_cast<const DrawIRectOp*>(base_op);
+ PaintOpWriter helper(memory, size, options);
+ if (!flags_to_serialize)
+ flags_to_serialize = &op->flags;
+ helper.Write(*flags_to_serialize, current_ctm);
+ helper.Write(op->rect);
+ return helper.size();
+}
+
+size_t DrawLineOp::Serialize(const PaintOp* base_op,
+ void* memory,
+ size_t size,
+ const SerializeOptions& options,
+ const PaintFlags* flags_to_serialize,
+ const SkM44& current_ctm,
+ const SkM44& original_ctm) {
+ auto* op = static_cast<const DrawLineOp*>(base_op);
+ PaintOpWriter helper(memory, size, options);
+ if (!flags_to_serialize)
+ flags_to_serialize = &op->flags;
+ helper.Write(*flags_to_serialize, current_ctm);
+ helper.AssertAlignment(alignof(SkScalar));
+ helper.Write(op->x0);
+ helper.Write(op->y0);
+ helper.Write(op->x1);
+ helper.Write(op->y1);
+ return helper.size();
+}
+
+size_t DrawOvalOp::Serialize(const PaintOp* base_op,
+ void* memory,
+ size_t size,
+ const SerializeOptions& options,
+ const PaintFlags* flags_to_serialize,
+ const SkM44& current_ctm,
+ const SkM44& original_ctm) {
+ auto* op = static_cast<const DrawOvalOp*>(base_op);
+ PaintOpWriter helper(memory, size, options);
+ if (!flags_to_serialize)
+ flags_to_serialize = &op->flags;
+ helper.Write(*flags_to_serialize, current_ctm);
+ helper.Write(op->oval);
+ return helper.size();
+}
+
+size_t DrawPathOp::Serialize(const PaintOp* base_op,
+ void* memory,
+ size_t size,
+ const SerializeOptions& options,
+ const PaintFlags* flags_to_serialize,
+ const SkM44& current_ctm,
+ const SkM44& original_ctm) {
+ auto* op = static_cast<const DrawPathOp*>(base_op);
+ PaintOpWriter helper(memory, size, options);
+ if (!flags_to_serialize)
+ flags_to_serialize = &op->flags;
+ helper.Write(*flags_to_serialize, current_ctm);
+ helper.Write(op->path, op->use_cache);
+ helper.Write(op->sk_path_fill_type);
+ return helper.size();
+}
+
+size_t DrawRecordOp::Serialize(const PaintOp* op,
+ void* memory,
+ size_t size,
+ const SerializeOptions& options,
+ const PaintFlags* flags_to_serialize,
+ const SkM44& current_ctm,
+ const SkM44& original_ctm) {
+ // TODO(enne): these must be flattened. Serializing this will not do
+ // anything.
+ NOTREACHED();
+ return 0u;
+}
+
+size_t DrawRectOp::Serialize(const PaintOp* base_op,
+ void* memory,
+ size_t size,
+ const SerializeOptions& options,
+ const PaintFlags* flags_to_serialize,
+ const SkM44& current_ctm,
+ const SkM44& original_ctm) {
+ auto* op = static_cast<const DrawRectOp*>(base_op);
+ PaintOpWriter helper(memory, size, options);
+ if (!flags_to_serialize)
+ flags_to_serialize = &op->flags;
+ helper.Write(*flags_to_serialize, current_ctm);
+ helper.Write(op->rect);
+ return helper.size();
+}
+
+size_t DrawRRectOp::Serialize(const PaintOp* base_op,
+ void* memory,
+ size_t size,
+ const SerializeOptions& options,
+ const PaintFlags* flags_to_serialize,
+ const SkM44& current_ctm,
+ const SkM44& original_ctm) {
+ auto* op = static_cast<const DrawRRectOp*>(base_op);
+ PaintOpWriter helper(memory, size, options);
+ if (!flags_to_serialize)
+ flags_to_serialize = &op->flags;
+ helper.Write(*flags_to_serialize, current_ctm);
+ helper.Write(op->rrect);
+ return helper.size();
+}
+
+namespace {
+
+template <typename T>
+void SerializeSkottieMap(
+ const base::flat_map<SkottieResourceIdHash, T>& map,
+ PaintOpWriter& helper,
+ const base::RepeatingCallback<void(const T&, PaintOpWriter&)>&
+ value_serializer) {
+ // Write the size of the map first so that we know how many entries to read
+ // from the buffer during deserialization.
+ helper.WriteSize(map.size());
+ for (const auto& [resource_id, val] : map) {
+ helper.WriteSize(resource_id.GetUnsafeValue());
+ value_serializer.Run(val, helper);
+ }
+}
+
+void SerializeSkottieFrameData(const SkM44& current_ctm,
+ const SkottieFrameData& frame_data,
+ PaintOpWriter& helper) {
+ // |scale_adjustment| is not ultimately used; Skottie handles image
+ // scale adjustment internally when rastering.
+ SkSize scale_adjustment = SkSize::MakeEmpty();
+ DrawImage draw_image;
+ if (frame_data.image) {
+ draw_image = DrawImage(
+ frame_data.image, /*use_dark_mode=*/false,
+ SkIRect::MakeWH(frame_data.image.width(), frame_data.image.height()),
+ frame_data.quality, current_ctm);
+ }
+ helper.Write(draw_image, &scale_adjustment);
+ helper.Write(frame_data.quality);
+}
+
+} // namespace
+
+size_t DrawSkottieOp::Serialize(const PaintOp* base_op,
+ void* memory,
+ size_t size,
+ const SerializeOptions& options,
+ const PaintFlags* flags_to_serialize,
+ const SkM44& current_ctm,
+ const SkM44& original_ctm) {
+ auto* op = static_cast<const DrawSkottieOp*>(base_op);
+ PaintOpWriter helper(memory, size, options);
+ helper.Write(op->dst);
+ helper.Write(SkFloatToScalar(op->t));
+ helper.Write(op->skottie);
+
+ SkottieFrameDataMap images_to_serialize = op->images;
+ SkottieTextPropertyValueMap text_map_to_serialize = op->text_map;
+ if (options.skottie_serialization_history) {
+ options.skottie_serialization_history->FilterNewSkottieFrameState(
+ *op->skottie, images_to_serialize, text_map_to_serialize);
+ }
+
+ SerializeSkottieMap(
+ images_to_serialize, helper,
+ base::BindRepeating(&SerializeSkottieFrameData, std::cref(current_ctm)));
+ SerializeSkottieMap(
+ op->color_map, helper,
+ base::BindRepeating([](const SkColor& color, PaintOpWriter& helper) {
+ helper.Write(color);
+ }));
+ SerializeSkottieMap(
+ text_map_to_serialize, helper,
+ base::BindRepeating([](const SkottieTextPropertyValue& text_property_val,
+ PaintOpWriter& helper) {
+ helper.WriteSize(text_property_val.text().size());
+ // If there is not enough space in the underlying buffer, WriteData()
+ // will mark the |helper| as invalid and the buffer will keep growing
+ // until a max size is reached (currently 64MB which should be ample for
+ // text).
+ helper.WriteData(text_property_val.text().size(),
+ text_property_val.text().c_str());
+ helper.Write(gfx::RectFToSkRect(text_property_val.box()));
+ }));
+ return helper.size();
+}
+
+size_t DrawTextBlobOp::Serialize(const PaintOp* base_op,
+ void* memory,
+ size_t size,
+ const SerializeOptions& options,
+ const PaintFlags* flags_to_serialize,
+ const SkM44& current_ctm,
+ const SkM44& original_ctm) {
+ auto* op = static_cast<const DrawTextBlobOp*>(base_op);
+ PaintOpWriter helper(memory, size, options);
+ if (!flags_to_serialize)
+ flags_to_serialize = &op->flags;
+ helper.Write(*flags_to_serialize, current_ctm);
+ unsigned int count = op->extra_slugs.size() + 1;
+ helper.Write(count);
+ helper.Write(op->slug);
+ for (const auto& slug : op->extra_slugs) {
+ helper.Write(slug);
+ }
+ return helper.size();
+}
+
+size_t NoopOp::Serialize(const PaintOp* base_op,
+ void* memory,
+ size_t size,
+ const SerializeOptions& options,
+ const PaintFlags* flags_to_serialize,
+ const SkM44& current_ctm,
+ const SkM44& original_ctm) {
+ PaintOpWriter helper(memory, size, options);
+ return helper.size();
+}
+
+size_t RestoreOp::Serialize(const PaintOp* base_op,
+ void* memory,
+ size_t size,
+ const SerializeOptions& options,
+ const PaintFlags* flags_to_serialize,
+ const SkM44& current_ctm,
+ const SkM44& original_ctm) {
+ PaintOpWriter helper(memory, size, options);
+ return helper.size();
+}
+
+size_t RotateOp::Serialize(const PaintOp* base_op,
+ void* memory,
+ size_t size,
+ const SerializeOptions& options,
+ const PaintFlags* flags_to_serialize,
+ const SkM44& current_ctm,
+ const SkM44& original_ctm) {
+ auto* op = static_cast<const RotateOp*>(base_op);
+ PaintOpWriter helper(memory, size, options);
+ helper.Write(op->degrees);
+ return helper.size();
+}
+
+size_t SaveOp::Serialize(const PaintOp* base_op,
+ void* memory,
+ size_t size,
+ const SerializeOptions& options,
+ const PaintFlags* flags_to_serialize,
+ const SkM44& current_ctm,
+ const SkM44& original_ctm) {
+ PaintOpWriter helper(memory, size, options);
+ return helper.size();
+}
+
+size_t SaveLayerOp::Serialize(const PaintOp* base_op,
+ void* memory,
+ size_t size,
+ const SerializeOptions& options,
+ const PaintFlags* flags_to_serialize,
+ const SkM44& current_ctm,
+ const SkM44& original_ctm) {
+ auto* op = static_cast<const SaveLayerOp*>(base_op);
+ PaintOpWriter helper(memory, size, options);
+ if (!flags_to_serialize)
+ flags_to_serialize = &op->flags;
+ helper.Write(*flags_to_serialize, current_ctm);
+ helper.Write(op->bounds);
+ return helper.size();
+}
+
+size_t SaveLayerAlphaOp::Serialize(const PaintOp* base_op,
+ void* memory,
+ size_t size,
+ const SerializeOptions& options,
+ const PaintFlags* flags_to_serialize,
+ const SkM44& current_ctm,
+ const SkM44& original_ctm) {
+ auto* op = static_cast<const SaveLayerAlphaOp*>(base_op);
+ PaintOpWriter helper(memory, size, options);
+ helper.Write(op->bounds);
+ helper.Write(op->alpha);
+ return helper.size();
+}
+
+size_t ScaleOp::Serialize(const PaintOp* base_op,
+ void* memory,
+ size_t size,
+ const SerializeOptions& options,
+ const PaintFlags* flags_to_serialize,
+ const SkM44& current_ctm,
+ const SkM44& original_ctm) {
+ auto* op = static_cast<const ScaleOp*>(base_op);
+ PaintOpWriter helper(memory, size, options);
+ helper.Write(op->sx);
+ helper.Write(op->sy);
+ return helper.size();
+}
+
+size_t SetMatrixOp::Serialize(const PaintOp* base_op,
+ void* memory,
+ size_t size,
+ const SerializeOptions& options,
+ const PaintFlags* flags_to_serialize,
+ const SkM44& current_ctm,
+ const SkM44& original_ctm) {
+ auto* op = static_cast<const SetMatrixOp*>(base_op);
+ PaintOpWriter helper(memory, size, options);
+ // Use original_ctm here because SetMatrixOp replaces current_ctm
+ helper.Write(original_ctm * op->matrix);
+ return helper.size();
+}
+
+size_t SetNodeIdOp::Serialize(const PaintOp* base_op,
+ void* memory,
+ size_t size,
+ const SerializeOptions& options,
+ const PaintFlags* flags_to_serialize,
+ const SkM44& current_ctm,
+ const SkM44& original_ctm) {
+ auto* op = static_cast<const SetNodeIdOp*>(base_op);
+ PaintOpWriter helper(memory, size, options);
+ helper.Write(op->node_id);
+ return helper.size();
+}
+
+size_t TranslateOp::Serialize(const PaintOp* base_op,
+ void* memory,
+ size_t size,
+ const SerializeOptions& options,
+ const PaintFlags* flags_to_serialize,
+ const SkM44& current_ctm,
+ const SkM44& original_ctm) {
+ auto* op = static_cast<const TranslateOp*>(base_op);
+ PaintOpWriter helper(memory, size, options);
+ helper.Write(op->dx);
+ helper.Write(op->dy);
+ return helper.size();
+}
+
+template <typename T>
+void UpdateTypeAndSkip(T* op) {
+ op->type = static_cast<uint8_t>(T::kType);
+ op->skip = PaintOpBuffer::ComputeOpSkip(sizeof(T));
+}
+
+template <typename T>
+class PaintOpDeserializer {
+ public:
+ static_assert(std::is_base_of<PaintOp, T>::value, "T not a PaintOp.");
+
+ explicit PaintOpDeserializer(const volatile void* input,
+ size_t input_size,
+ const PaintOp::DeserializeOptions& options,
+ T* op)
+ : reader_(input, input_size, options), op_(op) {
+ DCHECK(op_);
+ }
+ PaintOpDeserializer(const PaintOpDeserializer&) = delete;
+ PaintOpDeserializer& operator=(const PaintOpDeserializer&) = delete;
+
+ ~PaintOpDeserializer() {
+ DCHECK(!op_)
+ << "FinalizeOp must be called before PaintOpDeserializer is destroyed. "
+ "type="
+ << T::kType;
+ }
+
+ PaintOp* FinalizeOp(bool force_invalid = false) {
+ DCHECK(op_) << "PaintOp has already been finalized. type=" << T::kType;
+
+ if (force_invalid || !reader_.valid() || !op_->IsValid()) {
+ op_->~T();
+ op_ = nullptr;
+ return nullptr;
+ }
+
+ UpdateTypeAndSkip(op_.get());
+ T* op_snapshot = op_;
+ op_ = nullptr;
+ return op_snapshot;
+ }
+
+ PaintOp* InvalidateAndFinalizeOp() {
+ return FinalizeOp(/*force_invalid=*/true);
+ }
+
+ T* operator->() { return op_; }
+
+ template <typename... Args>
+ void Read(Args&&... args) {
+ reader_.Read(std::forward<Args>(args)...);
+ }
+
+ void ReadData(size_t bytes, void* data) { reader_.ReadData(bytes, data); }
+
+ void ReadSize(size_t* size) { reader_.ReadSize(size); }
+
+ void AssertAlignment(size_t alignment) { reader_.AssertAlignment(alignment); }
+
+ private:
+ PaintOpReader reader_;
+ raw_ptr<T> op_;
+};
+
+PaintOp* AnnotateOp::Deserialize(const volatile void* input,
+ size_t input_size,
+ void* output,
+ size_t output_size,
+ const DeserializeOptions& options) {
+ DCHECK_GE(output_size, sizeof(AnnotateOp));
+ PaintOpDeserializer<AnnotateOp> deserializer(input, input_size, options,
+ new (output) AnnotateOp);
+
+ deserializer.Read(&deserializer->annotation_type);
+ deserializer.Read(&deserializer->rect);
+ deserializer.Read(&deserializer->data);
+ return deserializer.FinalizeOp();
+}
+
+PaintOp* ClipPathOp::Deserialize(const volatile void* input,
+ size_t input_size,
+ void* output,
+ size_t output_size,
+ const DeserializeOptions& options) {
+ DCHECK_GE(output_size, sizeof(ClipPathOp));
+ PaintOpDeserializer<ClipPathOp> deserializer(input, input_size, options,
+ new (output) ClipPathOp);
+
+ deserializer.Read(&deserializer->path);
+ deserializer.Read(&deserializer->op);
+ deserializer.Read(&deserializer->antialias);
+ return deserializer.FinalizeOp();
+}
+
+PaintOp* ClipRectOp::Deserialize(const volatile void* input,
+ size_t input_size,
+ void* output,
+ size_t output_size,
+ const DeserializeOptions& options) {
+ DCHECK_GE(output_size, sizeof(ClipRectOp));
+ PaintOpDeserializer<ClipRectOp> deserializer(input, input_size, options,
+ new (output) ClipRectOp);
+ deserializer.Read(&deserializer->rect);
+ deserializer.Read(&deserializer->op);
+ deserializer.Read(&deserializer->antialias);
+ return deserializer.FinalizeOp();
+}
+
+PaintOp* ClipRRectOp::Deserialize(const volatile void* input,
+ size_t input_size,
+ void* output,
+ size_t output_size,
+ const DeserializeOptions& options) {
+ DCHECK_GE(output_size, sizeof(ClipRRectOp));
+ PaintOpDeserializer<ClipRRectOp> deserializer(input, input_size, options,
+ new (output) ClipRRectOp);
+ deserializer.Read(&deserializer->rrect);
+ deserializer.Read(&deserializer->op);
+ deserializer.Read(&deserializer->antialias);
+ return deserializer.FinalizeOp();
+}
+
+PaintOp* ConcatOp::Deserialize(const volatile void* input,
+ size_t input_size,
+ void* output,
+ size_t output_size,
+ const DeserializeOptions& options) {
+ DCHECK_GE(output_size, sizeof(ConcatOp));
+ PaintOpDeserializer<ConcatOp> deserializer(input, input_size, options,
+ new (output) ConcatOp);
+ deserializer.Read(&deserializer->matrix);
+ return deserializer.FinalizeOp();
+}
+
+PaintOp* CustomDataOp::Deserialize(const volatile void* input,
+ size_t input_size,
+ void* output,
+ size_t output_size,
+ const DeserializeOptions& options) {
+ DCHECK_GE(output_size, sizeof(CustomDataOp));
+ PaintOpDeserializer<CustomDataOp> deserializer(input, input_size, options,
+ new (output) CustomDataOp);
+ deserializer.Read(&deserializer->id);
+ return deserializer.FinalizeOp();
+}
+
+PaintOp* DrawColorOp::Deserialize(const volatile void* input,
+ size_t input_size,
+ void* output,
+ size_t output_size,
+ const DeserializeOptions& options) {
+ DCHECK_GE(output_size, sizeof(DrawColorOp));
+ PaintOpDeserializer<DrawColorOp> deserializer(input, input_size, options,
+ new (output) DrawColorOp);
+ deserializer.Read(&deserializer->color);
+ deserializer.Read(&deserializer->mode);
+ return deserializer.FinalizeOp();
+}
+
+PaintOp* DrawDRRectOp::Deserialize(const volatile void* input,
+ size_t input_size,
+ void* output,
+ size_t output_size,
+ const DeserializeOptions& options) {
+ DCHECK_GE(output_size, sizeof(DrawDRRectOp));
+ PaintOpDeserializer<DrawDRRectOp> deserializer(input, input_size, options,
+ new (output) DrawDRRectOp);
+ deserializer.Read(&deserializer->flags);
+ deserializer.Read(&deserializer->outer);
+ deserializer.Read(&deserializer->inner);
+ return deserializer.FinalizeOp();
+}
+
+PaintOp* DrawImageOp::Deserialize(const volatile void* input,
+ size_t input_size,
+ void* output,
+ size_t output_size,
+ const DeserializeOptions& options) {
+ DCHECK_GE(output_size, sizeof(DrawImageOp));
+ PaintOpDeserializer<DrawImageOp> deserializer(input, input_size, options,
+ new (output) DrawImageOp);
+ deserializer.Read(&deserializer->flags);
+
+ deserializer.Read(&deserializer->image);
+ deserializer.AssertAlignment(alignof(SkScalar));
+ deserializer.Read(&deserializer->scale_adjustment.fWidth);
+ deserializer.Read(&deserializer->scale_adjustment.fHeight);
+
+ deserializer.Read(&deserializer->left);
+ deserializer.Read(&deserializer->top);
+ deserializer.Read(&deserializer->sampling);
+ return deserializer.FinalizeOp();
+}
+
+PaintOp* DrawImageRectOp::Deserialize(const volatile void* input,
+ size_t input_size,
+ void* output,
+ size_t output_size,
+ const DeserializeOptions& options) {
+ DCHECK_GE(output_size, sizeof(DrawImageRectOp));
+ PaintOpDeserializer<DrawImageRectOp> deserializer(
+ input, input_size, options, new (output) DrawImageRectOp);
+ deserializer.Read(&deserializer->flags);
+
+ deserializer.Read(&deserializer->image);
+ deserializer.AssertAlignment(alignof(SkScalar));
+ deserializer.Read(&deserializer->scale_adjustment.fWidth);
+ deserializer.Read(&deserializer->scale_adjustment.fHeight);
+
+ deserializer.Read(&deserializer->src);
+ deserializer.Read(&deserializer->dst);
+ deserializer.Read(&deserializer->sampling);
+ deserializer.Read(&deserializer->constraint);
+ return deserializer.FinalizeOp();
+}
+
+PaintOp* DrawIRectOp::Deserialize(const volatile void* input,
+ size_t input_size,
+ void* output,
+ size_t output_size,
+ const DeserializeOptions& options) {
+ DCHECK_GE(output_size, sizeof(DrawIRectOp));
+ PaintOpDeserializer<DrawIRectOp> deserializer(input, input_size, options,
+ new (output) DrawIRectOp);
+ deserializer.Read(&deserializer->flags);
+ deserializer.Read(&deserializer->rect);
+ return deserializer.FinalizeOp();
+}
+
+PaintOp* DrawLineOp::Deserialize(const volatile void* input,
+ size_t input_size,
+ void* output,
+ size_t output_size,
+ const DeserializeOptions& options) {
+ DCHECK_GE(output_size, sizeof(DrawLineOp));
+ PaintOpDeserializer<DrawLineOp> deserializer(input, input_size, options,
+ new (output) DrawLineOp);
+ deserializer.Read(&deserializer->flags);
+ deserializer.AssertAlignment(alignof(SkScalar));
+ deserializer.Read(&deserializer->x0);
+ deserializer.Read(&deserializer->y0);
+ deserializer.Read(&deserializer->x1);
+ deserializer.Read(&deserializer->y1);
+ return deserializer.FinalizeOp();
+}
+
+PaintOp* DrawOvalOp::Deserialize(const volatile void* input,
+ size_t input_size,
+ void* output,
+ size_t output_size,
+ const DeserializeOptions& options) {
+ DCHECK_GE(output_size, sizeof(DrawOvalOp));
+ PaintOpDeserializer<DrawOvalOp> deserializer(input, input_size, options,
+ new (output) DrawOvalOp);
+ deserializer.Read(&deserializer->flags);
+ deserializer.Read(&deserializer->oval);
+ return deserializer.FinalizeOp();
+}
+
+PaintOp* DrawPathOp::Deserialize(const volatile void* input,
+ size_t input_size,
+ void* output,
+ size_t output_size,
+ const DeserializeOptions& options) {
+ DCHECK_GE(output_size, sizeof(DrawPathOp));
+ PaintOpDeserializer<DrawPathOp> deserializer(input, input_size, options,
+ new (output) DrawPathOp);
+ deserializer.Read(&deserializer->flags);
+ deserializer.Read(&deserializer->path);
+ deserializer.Read(&deserializer->sk_path_fill_type);
+ deserializer->path.setFillType(
+ static_cast<SkPathFillType>(deserializer->sk_path_fill_type));
+ return deserializer.FinalizeOp();
+}
+
+PaintOp* DrawRecordOp::Deserialize(const volatile void* input,
+ size_t input_size,
+ void* output,
+ size_t output_size,
+ const DeserializeOptions& options) {
+ // TODO(enne): these must be flattened and not sent directly.
+ // TODO(enne): could also consider caching these service side.
+ return nullptr;
+}
+
+PaintOp* DrawRectOp::Deserialize(const volatile void* input,
+ size_t input_size,
+ void* output,
+ size_t output_size,
+ const DeserializeOptions& options) {
+ DCHECK_GE(output_size, sizeof(DrawRectOp));
+ PaintOpDeserializer<DrawRectOp> deserializer(input, input_size, options,
+ new (output) DrawRectOp);
+ deserializer.Read(&deserializer->flags);
+ deserializer.Read(&deserializer->rect);
+ return deserializer.FinalizeOp();
+}
+
+PaintOp* DrawRRectOp::Deserialize(const volatile void* input,
+ size_t input_size,
+ void* output,
+ size_t output_size,
+ const DeserializeOptions& options) {
+ DCHECK_GE(output_size, sizeof(DrawRRectOp));
+ PaintOpDeserializer<DrawRRectOp> deserializer(input, input_size, options,
+ new (output) DrawRRectOp);
+ deserializer.Read(&deserializer->flags);
+ deserializer.Read(&deserializer->rrect);
+ return deserializer.FinalizeOp();
+}
+
+namespace {
+
+// |max_map_size| is purely a safety mechanism to prevent disastrous behavior
+// (trying to allocate an enormous map, looping for long periods of time, etc)
+// in case the serialization buffer is corrupted somehow.
+template <typename T>
+bool DeserializeSkottieMap(
+ base::flat_map<SkottieResourceIdHash, T>& map,
+ absl::optional<size_t> max_map_size,
+ PaintOpDeserializer<DrawSkottieOp>& deserializer,
+ const base::RepeatingCallback<absl::optional<T>(
+ PaintOpDeserializer<DrawSkottieOp>&)>& value_deserializer) {
+ size_t map_size = 0;
+ deserializer.ReadSize(&map_size);
+ if (max_map_size && map_size > *max_map_size)
+ return false;
+
+ for (size_t i = 0; i < map_size; ++i) {
+ size_t resource_id_hash_raw = 0;
+ deserializer.ReadSize(&resource_id_hash_raw);
+ SkottieResourceIdHash resource_id_hash =
+ SkottieResourceIdHash::FromUnsafeValue(resource_id_hash_raw);
+ if (!resource_id_hash)
+ return false;
+
+ absl::optional<T> value = value_deserializer.Run(deserializer);
+ if (!value)
+ return false;
+
+ // Duplicate keys should not happen by design, but defend against it
+ // gracefully in case the underlying buffer is corrupted.
+ bool is_new_entry = map.emplace(resource_id_hash, std::move(*value)).second;
+ if (!is_new_entry)
+ return false;
+ }
+ return true;
+}
+
+absl::optional<SkottieFrameData> DeserializeSkottieFrameData(
+ PaintOpDeserializer<DrawSkottieOp>& deserializer) {
+ SkottieFrameData frame_data;
+ deserializer.Read(&frame_data.image);
+ deserializer.Read(&frame_data.quality);
+ return frame_data;
+}
+
+absl::optional<SkColor> DeserializeSkottieColor(
+ PaintOpDeserializer<DrawSkottieOp>& deserializer) {
+ SkColor color = SK_ColorTRANSPARENT;
+ deserializer.Read(&color);
+ return color;
+}
+
+absl::optional<SkottieTextPropertyValue> DeserializeSkottieTextPropertyValue(
+ PaintOpDeserializer<DrawSkottieOp>& deserializer) {
+ size_t text_size = 0u;
+ deserializer.ReadSize(&text_size);
+ std::string text(text_size, char());
+ deserializer.ReadData(text_size, const_cast<char*>(text.c_str()));
+ SkRect box;
+ deserializer.Read(&box);
+ return SkottieTextPropertyValue(std::move(text), gfx::SkRectToRectF(box));
+}
+
+} // namespace
+
+PaintOp* DrawSkottieOp::Deserialize(const volatile void* input,
+ size_t input_size,
+ void* output,
+ size_t output_size,
+ const DeserializeOptions& options) {
+ DCHECK_GE(output_size, sizeof(DrawSkottieOp));
+ PaintOpDeserializer<DrawSkottieOp> deserializer(input, input_size, options,
+ new (output) DrawSkottieOp);
+ deserializer.Read(&deserializer->dst);
+
+ SkScalar t;
+ deserializer.Read(&t);
+ deserializer->t = SkScalarToFloat(t);
+
+ deserializer.Read(&deserializer->skottie);
+ // The |skottie| object gets used below, so no point in continuing if it's
+ // invalid. That can lead to crashing or unexpected behavior.
+ if (!deserializer->skottie || !deserializer->skottie->is_valid())
+ return deserializer.InvalidateAndFinalizeOp();
+
+ size_t num_assets_in_animation =
+ deserializer->skottie->GetImageAssetMetadata().asset_storage().size();
+ size_t num_text_nodes_in_animation =
+ deserializer->skottie->GetTextNodeNames().size();
+ bool deserialized_all_maps =
+ DeserializeSkottieMap(
+ deserializer->images, /*max_map_size=*/num_assets_in_animation,
+ deserializer, base::BindRepeating(&DeserializeSkottieFrameData)) &&
+ DeserializeSkottieMap(deserializer->color_map,
+ /*max_map_size=*/absl::nullopt, deserializer,
+ base::BindRepeating(&DeserializeSkottieColor)) &&
+ DeserializeSkottieMap(
+ deserializer->text_map, /*max_map_size=*/num_text_nodes_in_animation,
+ deserializer,
+ base::BindRepeating(&DeserializeSkottieTextPropertyValue));
+ return deserialized_all_maps ? deserializer.FinalizeOp()
+ : deserializer.InvalidateAndFinalizeOp();
+}
+
+PaintOp* DrawTextBlobOp::Deserialize(const volatile void* input,
+ size_t input_size,
+ void* output,
+ size_t output_size,
+ const DeserializeOptions& options) {
+ DCHECK_GE(output_size, sizeof(DrawTextBlobOp));
+ PaintOpDeserializer<DrawTextBlobOp> deserializer(input, input_size, options,
+ new (output) DrawTextBlobOp);
+ deserializer.Read(&deserializer->flags);
+ unsigned int count = 0;
+ deserializer.Read(&count);
+ deserializer.Read(&deserializer->slug);
+ deserializer->extra_slugs.resize(count - 1);
+ for (auto& slug : deserializer->extra_slugs) {
+ deserializer.Read(&slug);
+ }
+ return deserializer.FinalizeOp();
+}
+
+PaintOp* NoopOp::Deserialize(const volatile void* input,
+ size_t input_size,
+ void* output,
+ size_t output_size,
+ const DeserializeOptions& options) {
+ DCHECK_GE(output_size, sizeof(NoopOp));
+ PaintOpDeserializer<NoopOp> deserializer(input, input_size, options,
+ new (output) NoopOp);
+ return deserializer.FinalizeOp();
+}
+
+PaintOp* RestoreOp::Deserialize(const volatile void* input,
+ size_t input_size,
+ void* output,
+ size_t output_size,
+ const DeserializeOptions& options) {
+ DCHECK_GE(output_size, sizeof(RestoreOp));
+ PaintOpDeserializer<RestoreOp> deserializer(input, input_size, options,
+ new (output) RestoreOp);
+ return deserializer.FinalizeOp();
+}
+
+PaintOp* RotateOp::Deserialize(const volatile void* input,
+ size_t input_size,
+ void* output,
+ size_t output_size,
+ const DeserializeOptions& options) {
+ DCHECK_GE(output_size, sizeof(RotateOp));
+ PaintOpDeserializer<RotateOp> deserializer(input, input_size, options,
+ new (output) RotateOp);
+ deserializer.Read(&deserializer->degrees);
+ return deserializer.FinalizeOp();
+}
+
+PaintOp* SaveOp::Deserialize(const volatile void* input,
+ size_t input_size,
+ void* output,
+ size_t output_size,
+ const DeserializeOptions& options) {
+ DCHECK_GE(output_size, sizeof(SaveOp));
+ PaintOpDeserializer<SaveOp> deserializer(input, input_size, options,
+ new (output) SaveOp);
+ return deserializer.FinalizeOp();
+}
+
+PaintOp* SaveLayerOp::Deserialize(const volatile void* input,
+ size_t input_size,
+ void* output,
+ size_t output_size,
+ const DeserializeOptions& options) {
+ DCHECK_GE(output_size, sizeof(SaveLayerOp));
+ PaintOpDeserializer<SaveLayerOp> deserializer(input, input_size, options,
+ new (output) SaveLayerOp);
+ deserializer.Read(&deserializer->flags);
+ deserializer.Read(&deserializer->bounds);
+ return deserializer.FinalizeOp();
+}
+
+PaintOp* SaveLayerAlphaOp::Deserialize(const volatile void* input,
+ size_t input_size,
+ void* output,
+ size_t output_size,
+ const DeserializeOptions& options) {
+ DCHECK_GE(output_size, sizeof(SaveLayerAlphaOp));
+ PaintOpDeserializer<SaveLayerAlphaOp> deserializer(
+ input, input_size, options, new (output) SaveLayerAlphaOp);
+ deserializer.Read(&deserializer->bounds);
+ deserializer.Read(&deserializer->alpha);
+ return deserializer.FinalizeOp();
+}
+
+PaintOp* ScaleOp::Deserialize(const volatile void* input,
+ size_t input_size,
+ void* output,
+ size_t output_size,
+ const DeserializeOptions& options) {
+ DCHECK_GE(output_size, sizeof(ScaleOp));
+ PaintOpDeserializer<ScaleOp> deserializer(input, input_size, options,
+ new (output) ScaleOp);
+ deserializer.Read(&deserializer->sx);
+ deserializer.Read(&deserializer->sy);
+ return deserializer.FinalizeOp();
+}
+
+PaintOp* SetMatrixOp::Deserialize(const volatile void* input,
+ size_t input_size,
+ void* output,
+ size_t output_size,
+ const DeserializeOptions& options) {
+ DCHECK_GE(output_size, sizeof(SetMatrixOp));
+ PaintOpDeserializer<SetMatrixOp> deserializer(input, input_size, options,
+ new (output) SetMatrixOp);
+ deserializer.Read(&deserializer->matrix);
+ return deserializer.FinalizeOp();
+}
+
+PaintOp* SetNodeIdOp::Deserialize(const volatile void* input,
+ size_t input_size,
+ void* output,
+ size_t output_size,
+ const DeserializeOptions& options) {
+ DCHECK_GE(output_size, sizeof(SetNodeIdOp));
+ PaintOpDeserializer<SetNodeIdOp> deserializer(input, input_size, options,
+ new (output) SetNodeIdOp);
+ deserializer.Read(&deserializer->node_id);
+ return deserializer.FinalizeOp();
+}
+
+PaintOp* TranslateOp::Deserialize(const volatile void* input,
+ size_t input_size,
+ void* output,
+ size_t output_size,
+ const DeserializeOptions& options) {
+ DCHECK_GE(output_size, sizeof(TranslateOp));
+ PaintOpDeserializer<TranslateOp> deserializer(input, input_size, options,
+ new (output) TranslateOp);
+ deserializer.Read(&deserializer->dx);
+ deserializer.Read(&deserializer->dy);
+ return deserializer.FinalizeOp();
+}
+
+void AnnotateOp::Raster(const AnnotateOp* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params) {
+ switch (op->annotation_type) {
+ case PaintCanvas::AnnotationType::URL:
+ SkAnnotateRectWithURL(canvas, op->rect, op->data.get());
+ break;
+ case PaintCanvas::AnnotationType::LINK_TO_DESTINATION:
+ SkAnnotateLinkToDestination(canvas, op->rect, op->data.get());
+ break;
+ case PaintCanvas::AnnotationType::NAMED_DESTINATION: {
+ SkPoint point = SkPoint::Make(op->rect.x(), op->rect.y());
+ SkAnnotateNamedDestination(canvas, point, op->data.get());
+ break;
+ }
+ }
+}
+
+void ClipPathOp::Raster(const ClipPathOp* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params) {
+ canvas->clipPath(op->path, op->op, op->antialias);
+}
+
+void ClipRectOp::Raster(const ClipRectOp* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params) {
+ canvas->clipRect(op->rect, op->op, op->antialias);
+}
+
+void ClipRRectOp::Raster(const ClipRRectOp* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params) {
+ canvas->clipRRect(op->rrect, op->op, op->antialias);
+}
+
+void ConcatOp::Raster(const ConcatOp* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params) {
+ canvas->concat(op->matrix);
+}
+
+void CustomDataOp::Raster(const CustomDataOp* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params) {
+ if (params.custom_callback)
+ params.custom_callback.Run(canvas, op->id);
+}
+
+void DrawColorOp::Raster(const DrawColorOp* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params) {
+ canvas->drawColor(op->color, op->mode);
+}
+
+void DrawDRRectOp::RasterWithFlags(const DrawDRRectOp* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const PlaybackParams& params) {
+ flags->DrawToSk(canvas, [op](SkCanvas* c, const SkPaint& p) {
+ c->drawDRRect(op->outer, op->inner, p);
+ });
+}
+
+void DrawImageOp::RasterWithFlags(const DrawImageOp* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const PlaybackParams& params) {
+ DCHECK(!op->image.IsPaintWorklet());
+ SkPaint paint = flags ? flags->ToSkPaint() : SkPaint();
+
+ if (!params.image_provider) {
+ const bool needs_scale = !IsScaleAdjustmentIdentity(op->scale_adjustment);
+ SkAutoCanvasRestore save_restore(canvas, needs_scale);
+ if (needs_scale) {
+ canvas->scale(1.f / op->scale_adjustment.width(),
+ 1.f / op->scale_adjustment.height());
+ }
+ 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()),
+ sampling_to_quality(op->sampling), canvas->getLocalToDevice());
+ auto scoped_result = params.image_provider->GetRasterContent(draw_image);
+ if (!scoped_result)
+ return;
+
+ const auto& decoded_image = scoped_result.decoded_image();
+ DCHECK(decoded_image.image());
+
+ DCHECK_EQ(0, static_cast<int>(decoded_image.src_rect_offset().width()));
+ DCHECK_EQ(0, static_cast<int>(decoded_image.src_rect_offset().height()));
+ SkSize scale_adjustment = SkSize::Make(
+ op->scale_adjustment.width() * decoded_image.scale_adjustment().width(),
+ op->scale_adjustment.height() *
+ decoded_image.scale_adjustment().height());
+ const bool needs_scale = !IsScaleAdjustmentIdentity(scale_adjustment);
+ SkAutoCanvasRestore save_restore(canvas, needs_scale);
+ if (needs_scale) {
+ canvas->scale(1.f / scale_adjustment.width(),
+ 1.f / scale_adjustment.height());
+ }
+ canvas->drawImage(decoded_image.image().get(), op->left, op->top,
+ PaintFlags::FilterQualityToSkSamplingOptions(
+ decoded_image.filter_quality()),
+ &paint);
+}
+
+void DrawImageRectOp::RasterWithFlags(const DrawImageRectOp* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const PlaybackParams& params) {
+ // TODO(crbug.com/931704): make sure to support the case where paint worklet
+ // generated images are used in other raster work such as canvas2d.
+ if (op->image.IsPaintWorklet()) {
+ // When rasterizing on the main thread (e.g. paint invalidation checking,
+ // see https://crbug.com/990382), an image provider may not be available, so
+ // we should draw nothing.
+ if (!params.image_provider)
+ return;
+ ImageProvider::ScopedResult result =
+ params.image_provider->GetRasterContent(DrawImage(op->image));
+
+ // Check that we are not using loopers with paint worklets, since converting
+ // PaintFlags to SkPaint drops loopers.
+ DCHECK(!flags->getLooper());
+ SkPaint paint = flags ? flags->ToSkPaint() : SkPaint();
+
+ DCHECK(IsScaleAdjustmentIdentity(op->scale_adjustment));
+ SkAutoCanvasRestore save_restore(canvas, true);
+ 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
+ // to the worklet thread even after main has torn down the worklet (e.g.
+ // because a navigation is happening). In that case the PaintWorklet jobs
+ // will fail and there will be no result to raster here. This state is
+ // transient as the next main frame commit will remove the PaintWorklets.
+ if (result && result.paint_record())
+ result.paint_record()->Playback(canvas, params);
+ return;
+ }
+
+ if (!params.image_provider) {
+ SkRect adjusted_src = AdjustSrcRectForScale(op->src, op->scale_adjustment);
+ flags->DrawToSk(canvas, [op, adjusted_src](SkCanvas* c, const SkPaint& 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();
+ DrawImageRect(c, sk_image.get(), adjusted_src, op->dst, op->sampling, &p,
+ op->constraint);
+ });
+ return;
+ }
+
+ SkM44 matrix = canvas->getLocalToDevice() *
+ SkM44(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,
+ sampling_to_quality(op->sampling), matrix);
+ auto scoped_result = params.image_provider->GetRasterContent(draw_image);
+ if (!scoped_result)
+ return;
+
+ const auto& decoded_image = scoped_result.decoded_image();
+ DCHECK(decoded_image.image());
+
+ SkSize scale_adjustment = SkSize::Make(
+ op->scale_adjustment.width() * decoded_image.scale_adjustment().width(),
+ op->scale_adjustment.height() *
+ decoded_image.scale_adjustment().height());
+ SkRect adjusted_src =
+ op->src.makeOffset(decoded_image.src_rect_offset().width(),
+ decoded_image.src_rect_offset().height());
+ adjusted_src = AdjustSrcRectForScale(adjusted_src, scale_adjustment);
+ flags->DrawToSk(canvas, [op, &decoded_image, adjusted_src](SkCanvas* c,
+ const SkPaint& p) {
+ SkSamplingOptions options = PaintFlags::FilterQualityToSkSamplingOptions(
+ decoded_image.filter_quality());
+ DrawImageRect(c, decoded_image.image().get(), adjusted_src, op->dst,
+ options, &p, op->constraint);
+ });
+}
+
+void DrawIRectOp::RasterWithFlags(const DrawIRectOp* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const PlaybackParams& params) {
+ flags->DrawToSk(canvas, [op](SkCanvas* c, const SkPaint& p) {
+ c->drawIRect(op->rect, p);
+ });
+}
+
+void DrawLineOp::RasterWithFlags(const DrawLineOp* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const PlaybackParams& params) {
+ SkPaint paint = flags->ToSkPaint();
+ flags->DrawToSk(canvas, [op](SkCanvas* c, const SkPaint& p) {
+ c->drawLine(op->x0, op->y0, op->x1, op->y1, p);
+ });
+}
+
+void DrawOvalOp::RasterWithFlags(const DrawOvalOp* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const PlaybackParams& params) {
+ flags->DrawToSk(canvas, [op](SkCanvas* c, const SkPaint& p) {
+ c->drawOval(op->oval, p);
+ });
+}
+
+void DrawPathOp::RasterWithFlags(const DrawPathOp* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const PlaybackParams& params) {
+ flags->DrawToSk(canvas, [op](SkCanvas* c, const SkPaint& p) {
+ c->drawPath(op->path, p);
+ });
+}
+
+void DrawRecordOp::Raster(const DrawRecordOp* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params) {
+ // Don't use drawPicture here, as it adds an implicit clip.
+ // TODO(enne): Temporary CHECK debugging for http://crbug.com/823835
+ CHECK(op->record);
+ op->record->Playback(canvas, params);
+}
+
+void DrawRectOp::RasterWithFlags(const DrawRectOp* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const PlaybackParams& params) {
+ flags->DrawToSk(canvas, [op](SkCanvas* c, const SkPaint& p) {
+ c->drawRect(op->rect, p);
+ });
+}
+
+void DrawRRectOp::RasterWithFlags(const DrawRRectOp* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const PlaybackParams& params) {
+ flags->DrawToSk(canvas, [op](SkCanvas* c, const SkPaint& p) {
+ c->drawRRect(op->rrect, p);
+ });
+}
+
+void DrawSkottieOp::Raster(const DrawSkottieOp* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params) {
+ // Binding unretained references in the callback is safe because Draw()'s API
+ // guarantees that the callback is invoked synchronously.
+ op->skottie->Draw(
+ canvas, op->t, op->dst,
+ base::BindRepeating(&DrawSkottieOp::GetImageAssetForRaster,
+ base::Unretained(op), canvas, std::cref(params)),
+ op->color_map, op->text_map);
+}
+
+SkottieWrapper::FrameDataFetchResult DrawSkottieOp::GetImageAssetForRaster(
+ SkCanvas* canvas,
+ const PlaybackParams& params,
+ SkottieResourceIdHash asset_id,
+ float t_frame,
+ sk_sp<SkImage>& sk_image,
+ SkSamplingOptions& sampling_out) const {
+ auto images_iter = images.find(asset_id);
+ if (images_iter == images.end())
+ return SkottieWrapper::FrameDataFetchResult::NO_UPDATE;
+
+ const SkottieFrameData& frame_data = images_iter->second;
+ if (!frame_data.image) {
+ sk_image = nullptr;
+ } else if (params.image_provider) {
+ // There is no use case for applying dark mode filters to skottie images
+ // currently.
+ DrawImage draw_image(
+ frame_data.image, /*use_dark_mode=*/false,
+ SkIRect::MakeWH(frame_data.image.width(), frame_data.image.height()),
+ frame_data.quality, canvas->getLocalToDevice());
+ auto scoped_result = params.image_provider->GetRasterContent(draw_image);
+ if (scoped_result) {
+ sk_image = scoped_result.decoded_image().image();
+ DCHECK(sk_image);
+ }
+ } else {
+ if (frame_data.image.IsTextureBacked()) {
+ sk_image = frame_data.image.GetAcceleratedSkImage();
+ DCHECK(sk_image || !canvas->recordingContext());
+ }
+ if (!sk_image)
+ sk_image = frame_data.image.GetSwSkImage();
+ }
+ sampling_out =
+ PaintFlags::FilterQualityToSkSamplingOptions(frame_data.quality);
+ return SkottieWrapper::FrameDataFetchResult::NEW_DATA_AVAILABLE;
+}
+
+void DrawTextBlobOp::RasterWithFlags(const DrawTextBlobOp* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const PlaybackParams& params) {
+ if (op->node_id)
+ SkPDF::SetNodeId(canvas, op->node_id);
+
+ // The PaintOpBuffer could be rasterized with different global matrix. It is
+ // used for over scall on Android. So we cannot reuse slugs, they have to be
+ // recreated.
+ if (params.is_analyzing) {
+ const_cast<DrawTextBlobOp*>(op)->slug.reset();
+ const_cast<DrawTextBlobOp*>(op)->extra_slugs.clear();
+ }
+
+ // flags may contain SkDrawLooper for shadow effect, so we need to convert
+ // SkTextBlob to slug for each run.
+ size_t i = 0;
+ flags->DrawToSk(canvas, [op, &params, &i](SkCanvas* c, const SkPaint& p) {
+ if (op->blob) {
+ c->drawTextBlob(op->blob.get(), op->x, op->y, p);
+ if (params.is_analyzing) {
+ auto s = GrSlug::ConvertBlob(c, *op->blob, {op->x, op->y}, p);
+ if (i == 0) {
+ const_cast<DrawTextBlobOp*>(op)->slug = std::move(s);
+ } else {
+ const_cast<DrawTextBlobOp*>(op)->extra_slugs.push_back(std::move(s));
+ }
+ }
+ } else if (i < 1 + op->extra_slugs.size()) {
+ DCHECK(!params.is_analyzing);
+ const auto& draw_slug = i == 0 ? op->slug : op->extra_slugs[i - 1];
+ if (draw_slug)
+ draw_slug->draw(c);
+ }
+ ++i;
+ });
+
+ if (op->node_id)
+ SkPDF::SetNodeId(canvas, 0);
+}
+
+void RestoreOp::Raster(const RestoreOp* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params) {
+ canvas->restore();
+}
+
+void RotateOp::Raster(const RotateOp* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params) {
+ canvas->rotate(op->degrees);
+}
+
+void SaveOp::Raster(const SaveOp* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params) {
+ canvas->save();
+}
+
+void SaveLayerOp::RasterWithFlags(const SaveLayerOp* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const PlaybackParams& params) {
+ // See PaintOp::kUnsetRect
+ SkPaint paint = flags->ToSkPaint();
+ bool unset = op->bounds.left() == SK_ScalarInfinity;
+ canvas->saveLayer(unset ? nullptr : &op->bounds, &paint);
+}
+
+void SaveLayerAlphaOp::Raster(const SaveLayerAlphaOp* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params) {
+ // See PaintOp::kUnsetRect
+ bool unset = op->bounds.left() == SK_ScalarInfinity;
+ absl::optional<SkPaint> paint;
+ if (op->alpha != 1.0f) {
+ paint.emplace();
+ paint->setAlpha(op->alpha * 255.0f);
+ }
+ SkCanvas::SaveLayerRec rec(unset ? nullptr : &op->bounds,
+ base::OptionalToPtr(paint));
+ if (params.save_layer_alpha_should_preserve_lcd_text.has_value() &&
+ *params.save_layer_alpha_should_preserve_lcd_text) {
+ rec.fSaveLayerFlags = SkCanvas::kPreserveLCDText_SaveLayerFlag |
+ SkCanvas::kInitWithPrevious_SaveLayerFlag;
+ }
+ canvas->saveLayer(rec);
+}
+
+void ScaleOp::Raster(const ScaleOp* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params) {
+ canvas->scale(op->sx, op->sy);
+}
+
+void SetMatrixOp::Raster(const SetMatrixOp* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params) {
+ canvas->setMatrix(params.original_ctm * op->matrix);
+}
+
+void SetNodeIdOp::Raster(const SetNodeIdOp* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params) {
+ SkPDF::SetNodeId(canvas, op->node_id);
+}
+
+void TranslateOp::Raster(const TranslateOp* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params) {
+ canvas->translate(op->dx, op->dy);
+}
+
+// static
+bool PaintOp::AreSkPointsEqual(const SkPoint& left, const SkPoint& right) {
+ if (!AreEqualEvenIfNaN(left.fX, right.fX))
+ return false;
+ if (!AreEqualEvenIfNaN(left.fY, right.fY))
+ return false;
+ return true;
+}
+
+// static
+bool PaintOp::AreSkPoint3sEqual(const SkPoint3& left, const SkPoint3& right) {
+ if (!AreEqualEvenIfNaN(left.fX, right.fX))
+ return false;
+ if (!AreEqualEvenIfNaN(left.fY, right.fY))
+ return false;
+ if (!AreEqualEvenIfNaN(left.fZ, right.fZ))
+ return false;
+ return true;
+}
+
+// static
+bool PaintOp::AreSkRectsEqual(const SkRect& left, const SkRect& right) {
+ if (!AreEqualEvenIfNaN(left.fLeft, right.fLeft))
+ return false;
+ if (!AreEqualEvenIfNaN(left.fTop, right.fTop))
+ return false;
+ if (!AreEqualEvenIfNaN(left.fRight, right.fRight))
+ return false;
+ if (!AreEqualEvenIfNaN(left.fBottom, right.fBottom))
+ return false;
+ return true;
+}
+
+// static
+bool PaintOp::AreSkRRectsEqual(const SkRRect& left, const SkRRect& right) {
+ char left_buffer[SkRRect::kSizeInMemory];
+ left.writeToMemory(left_buffer);
+ char right_buffer[SkRRect::kSizeInMemory];
+ right.writeToMemory(right_buffer);
+ return !memcmp(left_buffer, right_buffer, SkRRect::kSizeInMemory);
+}
+
+// static
+bool PaintOp::AreSkMatricesEqual(const SkMatrix& left, const SkMatrix& right) {
+ for (int i = 0; i < 9; ++i) {
+ if (!AreEqualEvenIfNaN(left.get(i), right.get(i)))
+ return false;
+ }
+
+ // If a serialized matrix says it is identity, then the original must have
+ // those values, as the serialization process clobbers the matrix values.
+ if (left.isIdentity()) {
+ if (SkMatrix::I() != left)
+ return false;
+ if (SkMatrix::I() != right)
+ return false;
+ }
+
+ if (left.getType() != right.getType())
+ return false;
+
+ return true;
+}
+
+// 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)
+ return !right && !left;
+
+ sk_sp<SkData> left_data = left->serialize();
+ sk_sp<SkData> right_data = right->serialize();
+ if (left_data->size() != right_data->size())
+ return false;
+ if (!left_data->equals(right_data.get()))
+ return false;
+ return true;
+}
+
+bool AnnotateOp::AreEqual(const PaintOp* base_left, const PaintOp* base_right) {
+ auto* left = static_cast<const AnnotateOp*>(base_left);
+ auto* right = static_cast<const AnnotateOp*>(base_right);
+ DCHECK(left->IsValid());
+ DCHECK(right->IsValid());
+ if (left->annotation_type != right->annotation_type)
+ return false;
+ if (!AreSkRectsEqual(left->rect, right->rect))
+ return false;
+ if (!left->data != !right->data)
+ return false;
+ if (left->data) {
+ if (left->data->size() != right->data->size())
+ return false;
+ if (0 !=
+ memcmp(left->data->data(), right->data->data(), right->data->size()))
+ return false;
+ }
+ return true;
+}
+
+bool ClipPathOp::AreEqual(const PaintOp* base_left, const PaintOp* base_right) {
+ auto* left = static_cast<const ClipPathOp*>(base_left);
+ auto* right = static_cast<const ClipPathOp*>(base_right);
+ DCHECK(left->IsValid());
+ DCHECK(right->IsValid());
+ if (left->path != right->path)
+ return false;
+ if (left->op != right->op)
+ return false;
+ if (left->antialias != right->antialias)
+ return false;
+ return true;
+}
+
+bool ClipRectOp::AreEqual(const PaintOp* base_left, const PaintOp* base_right) {
+ auto* left = static_cast<const ClipRectOp*>(base_left);
+ auto* right = static_cast<const ClipRectOp*>(base_right);
+ DCHECK(left->IsValid());
+ DCHECK(right->IsValid());
+ if (!AreSkRectsEqual(left->rect, right->rect))
+ return false;
+ if (left->op != right->op)
+ return false;
+ if (left->antialias != right->antialias)
+ return false;
+ return true;
+}
+
+bool ClipRRectOp::AreEqual(const PaintOp* base_left,
+ const PaintOp* base_right) {
+ auto* left = static_cast<const ClipRRectOp*>(base_left);
+ auto* right = static_cast<const ClipRRectOp*>(base_right);
+ DCHECK(left->IsValid());
+ DCHECK(right->IsValid());
+ if (!AreSkRRectsEqual(left->rrect, right->rrect))
+ return false;
+ if (left->op != right->op)
+ return false;
+ if (left->antialias != right->antialias)
+ return false;
+ return true;
+}
+
+bool ConcatOp::AreEqual(const PaintOp* base_left, const PaintOp* base_right) {
+ auto* left = static_cast<const ConcatOp*>(base_left);
+ auto* right = static_cast<const ConcatOp*>(base_right);
+ DCHECK(left->IsValid());
+ DCHECK(right->IsValid());
+ return AreSkM44sEqual(left->matrix, right->matrix);
+}
+
+bool CustomDataOp::AreEqual(const PaintOp* base_left,
+ const PaintOp* base_right) {
+ auto* left = static_cast<const CustomDataOp*>(base_left);
+ auto* right = static_cast<const CustomDataOp*>(base_right);
+ DCHECK(left->IsValid());
+ DCHECK(right->IsValid());
+ return left->id == right->id;
+}
+
+bool DrawColorOp::AreEqual(const PaintOp* base_left,
+ const PaintOp* base_right) {
+ auto* left = static_cast<const DrawColorOp*>(base_left);
+ auto* right = static_cast<const DrawColorOp*>(base_right);
+ DCHECK(left->IsValid());
+ DCHECK(right->IsValid());
+ return left->color == right->color;
+}
+
+bool DrawDRRectOp::AreEqual(const PaintOp* base_left,
+ const PaintOp* base_right) {
+ auto* left = static_cast<const DrawDRRectOp*>(base_left);
+ auto* right = static_cast<const DrawDRRectOp*>(base_right);
+ DCHECK(left->IsValid());
+ DCHECK(right->IsValid());
+ if (left->flags != right->flags)
+ return false;
+ if (!AreSkRRectsEqual(left->outer, right->outer))
+ return false;
+ if (!AreSkRRectsEqual(left->inner, right->inner))
+ return false;
+ return true;
+}
+
+bool DrawImageOp::AreEqual(const PaintOp* base_left,
+ const PaintOp* base_right) {
+ auto* left = static_cast<const DrawImageOp*>(base_left);
+ auto* right = static_cast<const DrawImageOp*>(base_right);
+ DCHECK(left->IsValid());
+ DCHECK(right->IsValid());
+ if (left->flags != right->flags)
+ return false;
+ // TODO(enne): Test PaintImage equality once implemented
+ if (!AreEqualEvenIfNaN(left->left, right->left))
+ return false;
+ if (!AreEqualEvenIfNaN(left->top, right->top))
+ return false;
+
+ // scale_adjustment intentionally omitted because it is added during
+ // serialization based on raster scale.
+ return true;
+}
+
+bool DrawImageRectOp::AreEqual(const PaintOp* base_left,
+ const PaintOp* base_right) {
+ auto* left = static_cast<const DrawImageRectOp*>(base_left);
+ auto* right = static_cast<const DrawImageRectOp*>(base_right);
+ DCHECK(left->IsValid());
+ DCHECK(right->IsValid());
+ if (left->flags != right->flags)
+ return false;
+ // TODO(enne): Test PaintImage equality once implemented
+ if (!AreSkRectsEqual(left->src, right->src))
+ return false;
+ if (!AreSkRectsEqual(left->dst, right->dst))
+ return false;
+
+ // scale_adjustment intentionally omitted because it is added during
+ // serialization based on raster scale.
+ return true;
+}
+
+bool DrawIRectOp::AreEqual(const PaintOp* base_left,
+ const PaintOp* base_right) {
+ auto* left = static_cast<const DrawIRectOp*>(base_left);
+ auto* right = static_cast<const DrawIRectOp*>(base_right);
+ DCHECK(left->IsValid());
+ DCHECK(right->IsValid());
+ if (left->flags != right->flags)
+ return false;
+ if (left->rect != right->rect)
+ return false;
+ return true;
+}
+
+bool DrawLineOp::AreEqual(const PaintOp* base_left, const PaintOp* base_right) {
+ auto* left = static_cast<const DrawLineOp*>(base_left);
+ auto* right = static_cast<const DrawLineOp*>(base_right);
+ DCHECK(left->IsValid());
+ DCHECK(right->IsValid());
+ if (left->flags != right->flags)
+ return false;
+ if (!AreEqualEvenIfNaN(left->x0, right->x0))
+ return false;
+ if (!AreEqualEvenIfNaN(left->y0, right->y0))
+ return false;
+ if (!AreEqualEvenIfNaN(left->x1, right->x1))
+ return false;
+ if (!AreEqualEvenIfNaN(left->y1, right->y1))
+ return false;
+ return true;
+}
+
+bool DrawOvalOp::AreEqual(const PaintOp* base_left, const PaintOp* base_right) {
+ auto* left = static_cast<const DrawOvalOp*>(base_left);
+ auto* right = static_cast<const DrawOvalOp*>(base_right);
+ DCHECK(left->IsValid());
+ DCHECK(right->IsValid());
+ if (left->flags != right->flags)
+ return false;
+ if (!AreSkRectsEqual(left->oval, right->oval))
+ return false;
+ return true;
+}
+
+bool DrawPathOp::AreEqual(const PaintOp* base_left, const PaintOp* base_right) {
+ auto* left = static_cast<const DrawPathOp*>(base_left);
+ auto* right = static_cast<const DrawPathOp*>(base_right);
+ DCHECK(left->IsValid());
+ DCHECK(right->IsValid());
+ if (left->flags != right->flags)
+ return false;
+ if (left->path != right->path)
+ return false;
+ return true;
+}
+
+bool DrawRecordOp::AreEqual(const PaintOp* base_left,
+ const PaintOp* base_right) {
+ auto* left = static_cast<const DrawRecordOp*>(base_left);
+ auto* right = static_cast<const DrawRecordOp*>(base_right);
+ DCHECK(left->IsValid());
+ DCHECK(right->IsValid());
+ if (!left->record != !right->record)
+ return false;
+ if (*left->record != *right->record)
+ return false;
+ return true;
+}
+
+bool DrawRectOp::AreEqual(const PaintOp* base_left, const PaintOp* base_right) {
+ auto* left = static_cast<const DrawRectOp*>(base_left);
+ auto* right = static_cast<const DrawRectOp*>(base_right);
+ DCHECK(left->IsValid());
+ DCHECK(right->IsValid());
+ if (left->flags != right->flags)
+ return false;
+ if (!AreSkRectsEqual(left->rect, right->rect))
+ return false;
+ return true;
+}
+
+bool DrawRRectOp::AreEqual(const PaintOp* base_left,
+ const PaintOp* base_right) {
+ auto* left = static_cast<const DrawRRectOp*>(base_left);
+ auto* right = static_cast<const DrawRRectOp*>(base_right);
+ DCHECK(left->IsValid());
+ DCHECK(right->IsValid());
+ if (left->flags != right->flags)
+ return false;
+ if (!AreSkRRectsEqual(left->rrect, right->rrect))
+ return false;
+ return true;
+}
+
+bool DrawSkottieOp::AreEqual(const PaintOp* base_left,
+ const PaintOp* base_right) {
+ auto* left = static_cast<const DrawSkottieOp*>(base_left);
+ auto* right = static_cast<const DrawSkottieOp*>(base_right);
+ DCHECK(left->IsValid());
+ DCHECK(right->IsValid());
+ // TODO(malaykeshav): Verify the skottie objects of each PaintOb are equal
+ // based on the serialized bytes.
+ if (left->t != right->t)
+ return false;
+ if (!AreSkRectsEqual(left->dst, right->dst))
+ return false;
+ if (left->images.size() != right->images.size())
+ return false;
+
+ auto left_iter = left->images.begin();
+ auto right_iter = right->images.begin();
+ for (; left_iter != left->images.end(); ++left_iter, ++right_iter) {
+ if (left_iter->first != right_iter->first ||
+ // PaintImage's comparison operator compares the underlying SkImage's
+ // pointer address. This does not necessarily hold in cases where the
+ // image's content may be the same, but it got realloacted to a
+ // different spot somewhere in memory via the transfer cache. The next
+ // best thing is to just compare the dimensions of the PaintImage.
+ left_iter->second.image.width() != right_iter->second.image.width() ||
+ left_iter->second.image.height() != right_iter->second.image.height() ||
+ left_iter->second.quality != right_iter->second.quality) {
+ return false;
+ }
+ }
+
+ if (left->color_map != right->color_map)
+ return false;
+
+ if (left->text_map != right->text_map)
+ return false;
+
+ return true;
+}
+
+bool DrawTextBlobOp::AreEqual(const PaintOp* base_left,
+ const PaintOp* base_right) {
+ auto* left = static_cast<const DrawTextBlobOp*>(base_left);
+ auto* right = static_cast<const DrawTextBlobOp*>(base_right);
+ DCHECK(left->IsValid());
+ DCHECK(right->IsValid());
+ if (left->flags != right->flags)
+ return false;
+ if (!AreEqualEvenIfNaN(left->x, right->x))
+ return false;
+ if (!AreEqualEvenIfNaN(left->y, right->y))
+ return false;
+ if (left->node_id != right->node_id)
+ return false;
+ return GrSlugAreEqual(left->slug, right->slug);
+}
+
+bool NoopOp::AreEqual(const PaintOp* base_left, const PaintOp* base_right) {
+ return true;
+}
+
+bool RestoreOp::AreEqual(const PaintOp* base_left, const PaintOp* base_right) {
+ return true;
+}
+
+bool RotateOp::AreEqual(const PaintOp* base_left, const PaintOp* base_right) {
+ auto* left = static_cast<const RotateOp*>(base_left);
+ auto* right = static_cast<const RotateOp*>(base_right);
+ DCHECK(left->IsValid());
+ DCHECK(right->IsValid());
+ if (!AreEqualEvenIfNaN(left->degrees, right->degrees))
+ return false;
+ return true;
+}
+
+bool SaveOp::AreEqual(const PaintOp* base_left, const PaintOp* base_right) {
+ return true;
+}
+
+bool SaveLayerOp::AreEqual(const PaintOp* base_left,
+ const PaintOp* base_right) {
+ auto* left = static_cast<const SaveLayerOp*>(base_left);
+ auto* right = static_cast<const SaveLayerOp*>(base_right);
+ DCHECK(left->IsValid());
+ DCHECK(right->IsValid());
+ if (left->flags != right->flags)
+ return false;
+ if (!AreSkRectsEqual(left->bounds, right->bounds))
+ return false;
+ return true;
+}
+
+bool SaveLayerAlphaOp::AreEqual(const PaintOp* base_left,
+ const PaintOp* base_right) {
+ auto* left = static_cast<const SaveLayerAlphaOp*>(base_left);
+ auto* right = static_cast<const SaveLayerAlphaOp*>(base_right);
+ DCHECK(left->IsValid());
+ DCHECK(right->IsValid());
+ if (!AreSkRectsEqual(left->bounds, right->bounds))
+ return false;
+ if (left->alpha != right->alpha)
+ return false;
+ return true;
+}
+
+bool ScaleOp::AreEqual(const PaintOp* base_left, const PaintOp* base_right) {
+ auto* left = static_cast<const ScaleOp*>(base_left);
+ auto* right = static_cast<const ScaleOp*>(base_right);
+ DCHECK(left->IsValid());
+ DCHECK(right->IsValid());
+ if (!AreEqualEvenIfNaN(left->sx, right->sx))
+ return false;
+ if (!AreEqualEvenIfNaN(left->sy, right->sy))
+ return false;
+ return true;
+}
+
+bool SetMatrixOp::AreEqual(const PaintOp* base_left,
+ const PaintOp* base_right) {
+ auto* left = static_cast<const SetMatrixOp*>(base_left);
+ auto* right = static_cast<const SetMatrixOp*>(base_right);
+ DCHECK(left->IsValid());
+ DCHECK(right->IsValid());
+ if (!AreSkM44sEqual(left->matrix, right->matrix))
+ return false;
+ return true;
+}
+
+bool SetNodeIdOp::AreEqual(const PaintOp* base_left,
+ const PaintOp* base_right) {
+ auto* left = static_cast<const SetNodeIdOp*>(base_left);
+ auto* right = static_cast<const SetNodeIdOp*>(base_right);
+
+ DCHECK(left->IsValid());
+ DCHECK(right->IsValid());
+ return left->node_id == right->node_id;
+}
+
+bool TranslateOp::AreEqual(const PaintOp* base_left,
+ const PaintOp* base_right) {
+ auto* left = static_cast<const TranslateOp*>(base_left);
+ auto* right = static_cast<const TranslateOp*>(base_right);
+ DCHECK(left->IsValid());
+ DCHECK(right->IsValid());
+ if (!AreEqualEvenIfNaN(left->dx, right->dx))
+ return false;
+ if (!AreEqualEvenIfNaN(left->dy, right->dy))
+ return false;
+ return true;
+}
+
+bool PaintOp::IsDrawOp() const {
+ return g_is_draw_op[type];
+}
+
+bool PaintOp::IsPaintOpWithFlags() const {
+ return g_has_paint_flags[type];
+}
+
+bool PaintOp::operator==(const PaintOp& other) const {
+ if (GetType() != other.GetType())
+ return false;
+ return g_equals_operator[type](this, &other);
+}
+
+// static
+bool PaintOp::TypeHasFlags(PaintOpType type) {
+ return g_has_paint_flags[static_cast<uint8_t>(type)];
+}
+
+void PaintOp::Raster(SkCanvas* canvas, const PlaybackParams& params) const {
+ g_raster_functions[type](this, canvas, params);
+}
+
+size_t PaintOp::Serialize(void* memory,
+ size_t size,
+ const SerializeOptions& options,
+ const PaintFlags* flags_to_serialize,
+ const SkM44& current_ctm,
+ const SkM44& original_ctm) const {
+ // Need at least enough room for a skip/type header.
+ if (size < 4)
+ return 0u;
+
+ DCHECK_EQ(0u,
+ reinterpret_cast<uintptr_t>(memory) % PaintOpBuffer::kPaintOpAlign);
+
+ size_t written = g_serialize_functions[type](this, memory, size, options,
+ flags_to_serialize, current_ctm,
+ original_ctm);
+ DCHECK_LE(written, size);
+ if (written < 4)
+ return 0u;
+
+ size_t aligned_written = ((written + PaintOpBuffer::kPaintOpAlign - 1) &
+ ~(PaintOpBuffer::kPaintOpAlign - 1));
+ if (aligned_written >= kMaxSkip)
+ return 0u;
+ if (aligned_written > size)
+ return 0u;
+
+ // Update skip and type now that the size is known.
+ uint32_t bytes_to_skip = static_cast<uint32_t>(aligned_written);
+ static_cast<uint32_t*>(memory)[0] = type | bytes_to_skip << 8;
+ return bytes_to_skip;
+}
+
+PaintOp* PaintOp::Deserialize(const volatile void* input,
+ size_t input_size,
+ void* output,
+ size_t output_size,
+ size_t* read_bytes,
+ const DeserializeOptions& options) {
+ DCHECK_GE(output_size, sizeof(LargestPaintOp));
+
+ uint8_t type;
+ uint32_t skip;
+ if (!PaintOpReader::ReadAndValidateOpHeader(input, input_size, &type, &skip))
+ return nullptr;
+
+ *read_bytes = skip;
+ return g_deserialize_functions[type](input, skip, output, output_size,
+ options);
+}
+
+PaintOp* PaintOp::DeserializeIntoPaintOpBuffer(
+ const volatile void* input,
+ size_t input_size,
+ PaintOpBuffer* buffer,
+ size_t* read_bytes,
+ const DeserializeOptions& options) {
+ uint8_t type;
+ uint32_t skip;
+ if (!PaintOpReader::ReadAndValidateOpHeader(input, input_size, &type,
+ &skip)) {
+ return nullptr;
+ }
+
+ size_t op_skip = PaintOpBuffer::ComputeOpSkip(g_type_to_size[type]);
+ if (auto* op = g_deserialize_functions[type](
+ input, skip, buffer->AllocatePaintOp(op_skip), op_skip, options)) {
+ g_analyze_op_functions[type](buffer, op);
+ *read_bytes = skip;
+ return op;
+ }
+
+ // The last allocated op has already been destroyed if it failed to
+ // deserialize. Update the buffer's op tracking to exclude it to avoid
+ // access during cleanup at destruction.
+ buffer->used_ -= op_skip;
+ buffer->op_count_--;
+ return nullptr;
+}
+
+// static
+bool PaintOp::GetBounds(const PaintOp& op, SkRect* rect) {
+ DCHECK(op.IsDrawOp());
+
+ switch (op.GetType()) {
+ case PaintOpType::DrawColor:
+ return false;
+ case PaintOpType::DrawDRRect: {
+ const auto& rect_op = static_cast<const DrawDRRectOp&>(op);
+ *rect = rect_op.outer.getBounds();
+ rect->sort();
+ return true;
+ }
+ case PaintOpType::DrawImage: {
+ const auto& image_op = static_cast<const DrawImageOp&>(op);
+ *rect = SkRect::MakeXYWH(image_op.left, image_op.top,
+ image_op.image.width(), image_op.image.height());
+ rect->sort();
+ return true;
+ }
+ case PaintOpType::DrawImageRect: {
+ const auto& image_rect_op = static_cast<const DrawImageRectOp&>(op);
+ *rect = image_rect_op.dst;
+ rect->sort();
+ return true;
+ }
+ case PaintOpType::DrawIRect: {
+ const auto& rect_op = static_cast<const DrawIRectOp&>(op);
+ *rect = SkRect::Make(rect_op.rect);
+ rect->sort();
+ return true;
+ }
+ case PaintOpType::DrawLine: {
+ const auto& line_op = static_cast<const DrawLineOp&>(op);
+ rect->setLTRB(line_op.x0, line_op.y0, line_op.x1, line_op.y1);
+ rect->sort();
+ return true;
+ }
+ case PaintOpType::DrawOval: {
+ const auto& oval_op = static_cast<const DrawOvalOp&>(op);
+ *rect = oval_op.oval;
+ rect->sort();
+ return true;
+ }
+ case PaintOpType::DrawPath: {
+ const auto& path_op = static_cast<const DrawPathOp&>(op);
+ *rect = path_op.path.getBounds();
+ rect->sort();
+ return true;
+ }
+ case PaintOpType::DrawRect: {
+ const auto& rect_op = static_cast<const DrawRectOp&>(op);
+ *rect = rect_op.rect;
+ rect->sort();
+ return true;
+ }
+ case PaintOpType::DrawRRect: {
+ const auto& rect_op = static_cast<const DrawRRectOp&>(op);
+ *rect = rect_op.rrect.rect();
+ rect->sort();
+ return true;
+ }
+ case PaintOpType::DrawRecord:
+ return false;
+ case PaintOpType::DrawSkottie: {
+ const auto& skottie_op = static_cast<const DrawSkottieOp&>(op);
+ *rect = skottie_op.dst;
+ rect->sort();
+ return true;
+ }
+ case PaintOpType::DrawTextBlob: {
+ const auto& text_op = static_cast<const DrawTextBlobOp&>(op);
+ *rect = text_op.blob->bounds().makeOffset(text_op.x, text_op.y);
+ rect->sort();
+ return true;
+ }
+ default:
+ NOTREACHED();
+ }
+ return false;
+}
+
+// static
+gfx::Rect PaintOp::ComputePaintRect(const PaintOp& op,
+ const SkRect& clip_rect,
+ const SkMatrix& ctm) {
+ gfx::Rect transformed_rect;
+ SkRect op_rect;
+ if (!op.IsDrawOp() || !PaintOp::GetBounds(op, &op_rect)) {
+ // If we can't provide a conservative bounding rect for the op, assume it
+ // covers the complete current clip.
+ // TODO(khushalsagar): See if we can do something better for non-draw ops.
+ transformed_rect = gfx::ToEnclosingRect(gfx::SkRectToRectF(clip_rect));
+ } else {
+ const PaintFlags* flags =
+ op.IsPaintOpWithFlags()
+ ? &(static_cast<const PaintOpWithFlags&>(op).flags)
+ : nullptr;
+ SkRect paint_rect = MapRect(ctm, op_rect);
+ if (flags) {
+ SkPaint paint = flags->ToSkPaint();
+ paint_rect = paint.canComputeFastBounds() && paint_rect.isFinite()
+ ? paint.computeFastBounds(paint_rect, &paint_rect)
+ : clip_rect;
+ }
+ // Clamp the image rect by the current clip rect.
+ if (!paint_rect.intersect(clip_rect))
+ return gfx::Rect();
+
+ transformed_rect = gfx::ToEnclosingRect(gfx::SkRectToRectF(paint_rect));
+ }
+
+ // During raster, we use the device clip bounds on the canvas, which outsets
+ // the actual clip by 1 due to the possibility of antialiasing. Account for
+ // this here by outsetting the image rect by 1. Note that this only affects
+ // queries into the rtree, which will now return images that only touch the
+ // bounds of the query rect.
+ //
+ // Note that it's not sufficient for us to inset the device clip bounds at
+ // raster time, since we might be sending a larger-than-one-item display
+ // item to skia, which means that skia will internally determine whether to
+ // raster the picture (using device clip bounds that are outset).
+ transformed_rect.Inset(-1);
+ return transformed_rect;
+}
+
+// static
+bool PaintOp::QuickRejectDraw(const PaintOp& op, const SkCanvas* canvas) {
+ if (!op.IsDrawOp())
+ return false;
+
+ SkRect rect;
+ if (!PaintOp::GetBounds(op, &rect))
+ return false;
+ if (!rect.isFinite())
+ return true;
+
+ if (op.IsPaintOpWithFlags()) {
+ 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);
+ }
+
+ return canvas->quickReject(rect);
+}
+
+// static
+bool PaintOp::OpHasDiscardableImages(const PaintOp& op) {
+ if (op.IsPaintOpWithFlags() && static_cast<const PaintOpWithFlags&>(op)
+ .HasDiscardableImagesFromFlags()) {
+ return true;
+ }
+
+ if (op.GetType() == PaintOpType::DrawImage &&
+ static_cast<const DrawImageOp&>(op).HasDiscardableImages()) {
+ return true;
+ } else if (op.GetType() == PaintOpType::DrawImageRect &&
+ static_cast<const DrawImageRectOp&>(op).HasDiscardableImages()) {
+ return true;
+ } else if (op.GetType() == PaintOpType::DrawRecord &&
+ static_cast<const DrawRecordOp&>(op).HasDiscardableImages()) {
+ return true;
+ } else if (op.GetType() == PaintOpType::DrawSkottie &&
+ static_cast<const DrawSkottieOp&>(op).HasDiscardableImages()) {
+ return true;
+ }
+
+ return false;
+}
+
+void PaintOp::DestroyThis() {
+ auto func = g_destructor_functions[type];
+ if (func)
+ func(this);
+}
+
+bool PaintOpWithFlags::HasDiscardableImagesFromFlags() const {
+ return flags.HasDiscardableImages();
+}
+
+void PaintOpWithFlags::RasterWithFlags(SkCanvas* canvas,
+ const PaintFlags* raster_flags,
+ const PlaybackParams& params) const {
+ g_raster_with_flags_functions[type](this, raster_flags, canvas, params);
+}
+
+int ClipPathOp::CountSlowPaths() const {
+ return antialias && !path.isConvex() ? 1 : 0;
+}
+
+int DrawLineOp::CountSlowPaths() const {
+ if (const SkPathEffect* effect = flags.getPathEffect().get()) {
+ SkPathEffect::DashInfo info;
+ SkPathEffect::DashType dashType = effect->asADash(&info);
+ if (flags.getStrokeCap() != PaintFlags::kRound_Cap &&
+ dashType == SkPathEffect::kDash_DashType && info.fCount == 2) {
+ // The PaintFlags will count this as 1, so uncount that here as
+ // this kind of line is special cased and not slow.
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int DrawPathOp::CountSlowPaths() const {
+ // This logic is copied from SkPathCounter instead of attempting to expose
+ // that from Skia.
+ if (!flags.isAntiAlias() || path.isConvex())
+ return 0;
+
+ PaintFlags::Style paintStyle = flags.getStyle();
+ const SkRect& pathBounds = path.getBounds();
+ if (paintStyle == PaintFlags::kStroke_Style && flags.getStrokeWidth() == 0) {
+ // AA hairline concave path is not slow.
+ return 0;
+ } else if (paintStyle == PaintFlags::kFill_Style &&
+ pathBounds.width() < 64.f && pathBounds.height() < 64.f &&
+ !path.isVolatile()) {
+ // AADF eligible concave path is not slow.
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+int DrawRecordOp::CountSlowPaths() const {
+ return record->num_slow_paths_up_to_min_for_MSAA();
+}
+
+bool DrawRecordOp::HasNonAAPaint() const {
+ return record->HasNonAAPaint();
+}
+
+bool DrawRecordOp::HasDrawTextOps() const {
+ return record->has_draw_text_ops();
+}
+
+bool DrawRecordOp::HasSaveLayerOps() const {
+ return record->has_save_layer_ops();
+}
+
+bool DrawRecordOp::HasSaveLayerAlphaOps() const {
+ return record->has_save_layer_alpha_ops();
+}
+
+bool DrawRecordOp::HasEffectsPreventingLCDTextForSaveLayerAlpha() const {
+ return record->has_effects_preventing_lcd_text_for_save_layer_alpha();
+}
+
+AnnotateOp::AnnotateOp() : PaintOp(kType) {}
+
+AnnotateOp::AnnotateOp(PaintCanvas::AnnotationType annotation_type,
+ const SkRect& rect,
+ sk_sp<SkData> data)
+ : PaintOp(kType),
+ annotation_type(annotation_type),
+ rect(rect),
+ data(std::move(data)) {}
+
+AnnotateOp::~AnnotateOp() = default;
+AnnotateOp::AnnotateOp(const AnnotateOp&) = default;
+AnnotateOp& AnnotateOp::operator=(const AnnotateOp&) = default;
+
+DrawImageOp::DrawImageOp() : PaintOpWithFlags(kType) {}
+
+DrawImageOp::DrawImageOp(const PaintImage& image, SkScalar left, SkScalar top)
+ : PaintOpWithFlags(kType, PaintFlags()),
+ image(image),
+ left(left),
+ top(top) {}
+
+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),
+ sampling(sampling) {}
+
+bool DrawImageOp::HasDiscardableImages() const {
+ return image && !image.IsTextureBacked();
+}
+
+DrawImageOp::~DrawImageOp() = default;
+
+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),
+ 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 {
+ return image && !image.IsTextureBacked();
+}
+
+DrawImageRectOp::~DrawImageRectOp() = default;
+
+DrawRecordOp::DrawRecordOp(sk_sp<const PaintRecord> record)
+ : PaintOp(kType), record(std::move(record)) {}
+
+DrawRecordOp::~DrawRecordOp() = default;
+DrawRecordOp::DrawRecordOp(const DrawRecordOp&) = default;
+DrawRecordOp& DrawRecordOp::operator=(const DrawRecordOp&) = default;
+
+size_t DrawRecordOp::AdditionalBytesUsed() const {
+ return record->bytes_used();
+}
+
+size_t DrawRecordOp::AdditionalOpCount() const {
+ return record->total_op_count();
+}
+
+DrawSkottieOp::DrawSkottieOp(scoped_refptr<SkottieWrapper> skottie,
+ SkRect dst,
+ float t,
+ SkottieFrameDataMap images,
+ const SkottieColorMap& color_map,
+ SkottieTextPropertyValueMap text_map)
+ : PaintOp(kType),
+ skottie(std::move(skottie)),
+ dst(dst),
+ t(t),
+ images(std::move(images)),
+ color_map(color_map),
+ text_map(std::move(text_map)) {}
+
+DrawSkottieOp::DrawSkottieOp() : PaintOp(kType) {}
+
+DrawSkottieOp::~DrawSkottieOp() = default;
+DrawSkottieOp::DrawSkottieOp(const DrawSkottieOp&) = default;
+DrawSkottieOp& DrawSkottieOp::operator=(const DrawSkottieOp&) = default;
+
+bool DrawSkottieOp::HasDiscardableImages() const {
+ return !images.empty();
+}
+
+bool DrawRecordOp::HasDiscardableImages() const {
+ return record->HasDiscardableImages();
+}
+
+DrawTextBlobOp::DrawTextBlobOp() : PaintOpWithFlags(kType) {}
+
+DrawTextBlobOp::DrawTextBlobOp(sk_sp<SkTextBlob> blob,
+ SkScalar x,
+ SkScalar y,
+ const PaintFlags& flags)
+ : PaintOpWithFlags(kType, flags), blob(std::move(blob)), x(x), y(y) {}
+
+DrawTextBlobOp::DrawTextBlobOp(sk_sp<SkTextBlob> blob,
+ SkScalar x,
+ SkScalar y,
+ NodeId node_id,
+ const PaintFlags& flags)
+ : PaintOpWithFlags(kType, flags),
+ blob(std::move(blob)),
+ x(x),
+ y(y),
+ node_id(node_id) {}
+
+DrawTextBlobOp::~DrawTextBlobOp() = default;
+DrawTextBlobOp::DrawTextBlobOp(const DrawTextBlobOp&) = default;
+DrawTextBlobOp& DrawTextBlobOp::operator=(const DrawTextBlobOp&) = default;
+
+} // namespace cc
diff --git a/chromium/cc/paint/paint_op.h b/chromium/cc/paint/paint_op.h
new file mode 100644
index 00000000000..5ca791a02ae
--- /dev/null
+++ b/chromium/cc/paint/paint_op.h
@@ -0,0 +1,1055 @@
+// Copyright 2017 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_PAINT_PAINT_OP_H_
+#define CC_PAINT_PAINT_OP_H_
+
+#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"
+#include "base/containers/stack_container.h"
+#include "base/debug/alias.h"
+#include "base/memory/raw_ptr.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/notreached.h"
+#include "cc/base/math_util.h"
+#include "cc/paint/node_id.h"
+#include "cc/paint/paint_canvas.h"
+#include "cc/paint/paint_export.h"
+#include "cc/paint/paint_flags.h"
+#include "cc/paint/paint_record.h"
+#include "cc/paint/skottie_color_map.h"
+#include "cc/paint/skottie_frame_data.h"
+#include "cc/paint/skottie_resource_metadata.h"
+#include "cc/paint/skottie_text_property_value.h"
+#include "cc/paint/skottie_wrapper.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/abseil-cpp/absl/types/variant.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/core/SkPath.h"
+#include "third_party/skia/include/core/SkRRect.h"
+#include "third_party/skia/include/core/SkRect.h"
+#include "third_party/skia/include/core/SkRefCnt.h"
+#include "third_party/skia/include/core/SkScalar.h"
+#include "ui/gfx/geometry/rect.h"
+
+class SkImage;
+class SkTextBlob;
+
+namespace cc {
+
+class CC_PAINT_EXPORT ThreadsafePath : public SkPath {
+ public:
+ explicit ThreadsafePath(const SkPath& path) : SkPath(path) {
+ updateBoundsCache();
+ }
+ ThreadsafePath() { updateBoundsCache(); }
+};
+
+// See PaintOp::Serialize/Deserialize for comments. Derived Serialize types
+// don't write the 4 byte type/skip header because they don't know how much
+// data they will need to write. PaintOp::Serialize itself must update it.
+#define HAS_SERIALIZATION_FUNCTIONS() \
+ static size_t Serialize( \
+ const PaintOp* op, void* memory, size_t size, \
+ const SerializeOptions& options, const PaintFlags* flags_to_serialize, \
+ const SkM44& current_ctm, const SkM44& original_ctm); \
+ static PaintOp* Deserialize(const volatile void* input, size_t input_size, \
+ void* output, size_t output_size, \
+ const DeserializeOptions& options)
+
+enum class PaintOpType : uint8_t {
+ Annotate,
+ ClipPath,
+ ClipRect,
+ ClipRRect,
+ Concat,
+ CustomData,
+ DrawColor,
+ DrawDRRect,
+ DrawImage,
+ DrawImageRect,
+ DrawIRect,
+ DrawLine,
+ DrawOval,
+ DrawPath,
+ DrawRecord,
+ DrawRect,
+ DrawRRect,
+ DrawSkottie,
+ DrawTextBlob,
+ Noop,
+ Restore,
+ Rotate,
+ Save,
+ SaveLayer,
+ SaveLayerAlpha,
+ Scale,
+ SetMatrix,
+ SetNodeId,
+ Translate,
+ LastPaintOpType = Translate,
+};
+
+CC_PAINT_EXPORT std::string PaintOpTypeToString(PaintOpType type);
+CC_PAINT_EXPORT std::ostream& operator<<(std::ostream&, PaintOpType);
+
+class CC_PAINT_EXPORT PaintOp {
+ public:
+ uint32_t type : 8;
+ uint32_t skip : 24;
+
+ using SerializeOptions = PaintOpBuffer::SerializeOptions;
+ using DeserializeOptions = PaintOpBuffer::DeserializeOptions;
+
+ explicit PaintOp(PaintOpType type) : type(static_cast<uint8_t>(type)) {}
+
+ PaintOpType GetType() const { return static_cast<PaintOpType>(type); }
+
+ // Subclasses should provide a static Raster() method which is called from
+ // here. The Raster method should take a const PaintOp* parameter. It is
+ // static with a pointer to the base type so that we can use it as a function
+ // pointer.
+ void Raster(SkCanvas* canvas, const PlaybackParams& params) const;
+ bool IsDrawOp() const;
+ bool IsPaintOpWithFlags() const;
+
+ bool operator==(const PaintOp& other) const;
+ bool operator!=(const PaintOp& other) const { return !(*this == other); }
+
+ // Indicates how PaintImages are serialized.
+ enum class SerializedImageType : uint8_t {
+ kNoImage,
+ kImageData,
+ kTransferCacheEntry,
+ kMailbox,
+ kLastType = kMailbox
+ };
+
+ // Subclasses should provide a static Serialize() method called from here.
+ // If the op can be serialized to |memory| in no more than |size| bytes,
+ // then return the number of bytes written. If it won't fit, return 0.
+ // If |flags_to_serialize| is non-null, it overrides any flags within the op.
+ // |current_ctm| is the transform that will affect the op when rasterized.
+ // |original_ctm| is the transform that SetMatrixOps must be made relative to.
+ size_t Serialize(void* memory,
+ size_t size,
+ const SerializeOptions& options,
+ const PaintFlags* flags_to_serialize,
+ const SkM44& current_ctm,
+ const SkM44& original_ctm) const;
+
+ // Deserializes a PaintOp of this type from a given buffer |input| of
+ // at most |input_size| bytes. Returns null on any errors.
+ // The PaintOp is deserialized into the |output| buffer and returned
+ // if valid. nullptr is returned if the deserialization fails.
+ // |output_size| must be at least LargestPaintOp + serialized->skip,
+ // to fit all ops. The caller is responsible for destroying these ops.
+ // After reading, it returns the number of bytes read in |read_bytes|.
+ static PaintOp* Deserialize(const volatile void* input,
+ size_t input_size,
+ void* output,
+ size_t output_size,
+ size_t* read_bytes,
+ const DeserializeOptions& options);
+ // Similar to the above, but deserializes into |buffer|.
+ static PaintOp* DeserializeIntoPaintOpBuffer(
+ const volatile void* input,
+ size_t input_size,
+ PaintOpBuffer* buffer,
+ size_t* read_bytes,
+ const DeserializeOptions& options);
+
+ // For draw ops, returns true if a conservative bounding rect can be provided
+ // for the op.
+ static bool GetBounds(const PaintOp& op, SkRect* rect);
+
+ // Returns the minimum conservative bounding rect that |op| draws to on a
+ // canvas. |clip_rect| and |ctm| are the current clip rect and transform on
+ // this canvas.
+ static gfx::Rect ComputePaintRect(const PaintOp& op,
+ const SkRect& clip_rect,
+ const SkMatrix& ctm);
+
+ // Returns true if the op lies outside the current clip and should be skipped.
+ // Should only be used with draw ops.
+ static bool QuickRejectDraw(const PaintOp& op, const SkCanvas* canvas);
+
+ // Returns true if executing this op will require decoding of any lazy
+ // generated images.
+ static bool OpHasDiscardableImages(const PaintOp& op);
+
+ // Returns true if the given op type has PaintFlags.
+ static bool TypeHasFlags(PaintOpType type);
+
+ int CountSlowPaths() const { return 0; }
+ int CountSlowPathsFromFlags() const { return 0; }
+
+ bool HasNonAAPaint() const { return false; }
+ bool HasDrawTextOps() const { return false; }
+ bool HasSaveLayerOps() const { return false; }
+ bool HasSaveLayerAlphaOps() const { return false; }
+ // Returns true if effects are present that would break LCD text or be broken
+ // by the flags for SaveLayerAlpha to preserving LCD text.
+ bool HasEffectsPreventingLCDTextForSaveLayerAlpha() const { return false; }
+
+ bool HasDiscardableImages() const { return false; }
+ bool HasDiscardableImagesFromFlags() const { return false; }
+
+ // Returns the number of bytes used by this op in referenced sub records
+ // and display lists. This doesn't count other objects like paths or blobs.
+ size_t AdditionalBytesUsed() const { return 0; }
+
+ // Returns the number of ops in referenced sub records and display lists.
+ size_t AdditionalOpCount() const { return 0; }
+
+ // Run the destructor for the derived op type. Ops are usually contained in
+ // memory buffers and so don't have their destructors run automatically.
+ void DestroyThis();
+
+ // DrawColor is more restrictive on the blend modes that can be used.
+ static bool IsValidDrawColorSkBlendMode(SkBlendMode mode) {
+ return static_cast<uint32_t>(mode) <=
+ static_cast<uint32_t>(SkBlendMode::kLastCoeffMode);
+ }
+
+ // PaintFlags can have more complex blend modes than DrawColor.
+ static bool IsValidPaintFlagsSkBlendMode(SkBlendMode mode) {
+ return static_cast<uint32_t>(mode) <=
+ static_cast<uint32_t>(SkBlendMode::kLastMode);
+ }
+
+ static bool IsValidSkClipOp(SkClipOp op) {
+ return static_cast<uint32_t>(op) <=
+ static_cast<uint32_t>(SkClipOp::kMax_EnumValue);
+ }
+
+ static bool IsValidPath(const SkPath& path) { return path.isValid(); }
+
+ static bool IsUnsetRect(const SkRect& rect) {
+ return rect.fLeft == SK_ScalarInfinity;
+ }
+
+ static bool IsValidOrUnsetRect(const SkRect& rect) {
+ return IsUnsetRect(rect) || rect.isFinite();
+ }
+
+ // PaintOp supports having nans, but some tests want to make sure
+ // that operator== is true on two objects. These helpers compare
+ // various types in a way where nan == nan is true.
+ static bool AreEqualEvenIfNaN(float left, float right) {
+ if (std::isnan(left) && std::isnan(right))
+ return true;
+ return left == right;
+ }
+ static bool AreSkPointsEqual(const SkPoint& left, const SkPoint& right);
+ static bool AreSkPoint3sEqual(const SkPoint3& left, const SkPoint3& right);
+ 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;
+ static constexpr bool kHasPaintFlags = false;
+ // Since skip and type fit in a uint32_t, this is the max size of skip.
+ static constexpr size_t kMaxSkip = static_cast<size_t>(1 << 24);
+ static const SkRect kUnsetRect;
+
+ protected:
+ ~PaintOp() = default;
+ PaintOp(const PaintOp&) = default;
+ PaintOp& operator=(const PaintOp&) = default;
+};
+
+class CC_PAINT_EXPORT PaintOpWithFlags : public PaintOp {
+ public:
+ static constexpr bool kHasPaintFlags = true;
+ PaintOpWithFlags(PaintOpType type, const PaintFlags& flags)
+ : PaintOp(type), flags(flags) {}
+
+ int CountSlowPathsFromFlags() const { return flags.getPathEffect() ? 1 : 0; }
+ bool HasNonAAPaint() const { return !flags.isAntiAlias(); }
+ bool HasDiscardableImagesFromFlags() const;
+
+ void RasterWithFlags(SkCanvas* canvas,
+ const PaintFlags* flags,
+ const PlaybackParams& params) const;
+
+ // Subclasses should provide a static RasterWithFlags() method which is called
+ // from the Raster() method. The RasterWithFlags() should use the SkPaint
+ // passed to it, instead of the |flags| member directly, as some callers may
+ // provide a modified PaintFlags. The RasterWithFlags() method is static with
+ // a const PaintOpWithFlags* parameter so that it can be used as a function
+ // pointer.
+ PaintFlags flags;
+
+ protected:
+ ~PaintOpWithFlags() = default;
+ PaintOpWithFlags(const PaintOpWithFlags&) = default;
+ PaintOpWithFlags& operator=(const PaintOpWithFlags&) = default;
+
+ explicit PaintOpWithFlags(PaintOpType type) : PaintOp(type) {}
+};
+
+class CC_PAINT_EXPORT AnnotateOp final : public PaintOp {
+ public:
+ static constexpr PaintOpType kType = PaintOpType::Annotate;
+ AnnotateOp(PaintCanvas::AnnotationType annotation_type,
+ const SkRect& rect,
+ sk_sp<SkData> data);
+ ~AnnotateOp();
+ AnnotateOp(const AnnotateOp&);
+ AnnotateOp& operator=(const AnnotateOp&);
+ static void Raster(const AnnotateOp* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params);
+ bool IsValid() const { return rect.isFinite(); }
+ static bool AreEqual(const PaintOp* left, const PaintOp* right);
+ HAS_SERIALIZATION_FUNCTIONS();
+
+ PaintCanvas::AnnotationType annotation_type;
+ SkRect rect;
+ sk_sp<SkData> data;
+
+ private:
+ AnnotateOp();
+};
+
+class CC_PAINT_EXPORT ClipPathOp final : public PaintOp {
+ public:
+ static constexpr PaintOpType kType = PaintOpType::ClipPath;
+ ClipPathOp(SkPath path,
+ SkClipOp op,
+ bool antialias,
+ UsePaintCache use_paint_cache = UsePaintCache::kEnabled)
+ : PaintOp(kType),
+ path(path),
+ op(op),
+ antialias(antialias),
+ use_cache(use_paint_cache) {}
+ ClipPathOp(const ClipPathOp&) = default;
+ ClipPathOp& operator=(const ClipPathOp&) = default;
+ static void Raster(const ClipPathOp* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params);
+ bool IsValid() const { return IsValidSkClipOp(op) && IsValidPath(path); }
+ static bool AreEqual(const PaintOp* left, const PaintOp* right);
+ int CountSlowPaths() const;
+ bool HasNonAAPaint() const { return !antialias; }
+ HAS_SERIALIZATION_FUNCTIONS();
+
+ ThreadsafePath path;
+ SkClipOp op;
+ bool antialias;
+ UsePaintCache use_cache;
+
+ private:
+ ClipPathOp() : PaintOp(kType) {}
+};
+
+class CC_PAINT_EXPORT ClipRectOp final : public PaintOp {
+ public:
+ static constexpr PaintOpType kType = PaintOpType::ClipRect;
+ ClipRectOp(const SkRect& rect, SkClipOp op, bool antialias)
+ : PaintOp(kType), rect(rect), op(op), antialias(antialias) {}
+ ClipRectOp(const ClipRectOp&) = default;
+ ClipRectOp& operator=(const ClipRectOp&) = default;
+ static void Raster(const ClipRectOp* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params);
+ bool IsValid() const { return IsValidSkClipOp(op) && rect.isFinite(); }
+ static bool AreEqual(const PaintOp* left, const PaintOp* right);
+ HAS_SERIALIZATION_FUNCTIONS();
+
+ SkRect rect;
+ SkClipOp op;
+ bool antialias;
+
+ private:
+ ClipRectOp() : PaintOp(kType) {}
+};
+
+class CC_PAINT_EXPORT ClipRRectOp final : public PaintOp {
+ public:
+ static constexpr PaintOpType kType = PaintOpType::ClipRRect;
+ ClipRRectOp(const SkRRect& rrect, SkClipOp op, bool antialias)
+ : PaintOp(kType), rrect(rrect), op(op), antialias(antialias) {}
+ ClipRRectOp(const ClipRRectOp&) = default;
+ ClipRRectOp& operator=(const ClipRRectOp&) = default;
+ static void Raster(const ClipRRectOp* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params);
+ bool IsValid() const { return IsValidSkClipOp(op) && rrect.isValid(); }
+ static bool AreEqual(const PaintOp* left, const PaintOp* right);
+ bool HasNonAAPaint() const { return !antialias; }
+ HAS_SERIALIZATION_FUNCTIONS();
+
+ SkRRect rrect;
+ SkClipOp op;
+ bool antialias;
+
+ private:
+ ClipRRectOp() : PaintOp(kType) {}
+};
+
+class CC_PAINT_EXPORT ConcatOp final : public PaintOp {
+ public:
+ static constexpr PaintOpType kType = PaintOpType::Concat;
+ explicit ConcatOp(const SkM44& matrix) : PaintOp(kType), matrix(matrix) {}
+ ConcatOp(const ConcatOp&) = default;
+ ConcatOp& operator=(const ConcatOp&) = default;
+ static void Raster(const ConcatOp* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params);
+ bool IsValid() const { return true; }
+ static bool AreEqual(const PaintOp* left, const PaintOp* right);
+ HAS_SERIALIZATION_FUNCTIONS();
+
+ SkM44 matrix;
+
+ private:
+ ConcatOp() : PaintOp(kType) {}
+};
+
+class CC_PAINT_EXPORT CustomDataOp final : public PaintOp {
+ public:
+ static constexpr PaintOpType kType = PaintOpType::CustomData;
+ explicit CustomDataOp(uint32_t id) : PaintOp(kType), id(id) {}
+ CustomDataOp(const CustomDataOp&) = default;
+ CustomDataOp& operator=(const CustomDataOp&) = default;
+ static void Raster(const CustomDataOp* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params);
+ bool IsValid() const { return true; }
+ static bool AreEqual(const PaintOp* left, const PaintOp* right);
+ HAS_SERIALIZATION_FUNCTIONS();
+
+ // Stores user defined id as a placeholder op.
+ uint32_t id;
+
+ private:
+ CustomDataOp() : PaintOp(kType) {}
+};
+
+class CC_PAINT_EXPORT DrawColorOp final : public PaintOp {
+ public:
+ static constexpr PaintOpType kType = PaintOpType::DrawColor;
+ static constexpr bool kIsDrawOp = true;
+ DrawColorOp(SkColor4f color, SkBlendMode mode)
+ : PaintOp(kType), color(color), mode(mode) {}
+ DrawColorOp(const DrawColorOp&) = default;
+ DrawColorOp& operator=(const DrawColorOp&) = default;
+ static void Raster(const DrawColorOp* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params);
+ bool IsValid() const { return IsValidDrawColorSkBlendMode(mode); }
+ static bool AreEqual(const PaintOp* left, const PaintOp* right);
+ HAS_SERIALIZATION_FUNCTIONS();
+
+ SkColor4f color;
+ SkBlendMode mode;
+
+ private:
+ DrawColorOp() : PaintOp(kType) {}
+};
+
+class CC_PAINT_EXPORT DrawDRRectOp final : public PaintOpWithFlags {
+ public:
+ static constexpr PaintOpType kType = PaintOpType::DrawDRRect;
+ static constexpr bool kIsDrawOp = true;
+ DrawDRRectOp(const SkRRect& outer,
+ const SkRRect& inner,
+ const PaintFlags& flags)
+ : PaintOpWithFlags(kType, flags), outer(outer), inner(inner) {}
+ DrawDRRectOp(const DrawDRRectOp&) = default;
+ DrawDRRectOp& operator=(const DrawDRRectOp&) = default;
+ static void RasterWithFlags(const DrawDRRectOp* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const PlaybackParams& params);
+ bool IsValid() const {
+ return flags.IsValid() && outer.isValid() && inner.isValid();
+ }
+ static bool AreEqual(const PaintOp* left, const PaintOp* right);
+ HAS_SERIALIZATION_FUNCTIONS();
+
+ SkRRect outer;
+ SkRRect inner;
+
+ private:
+ DrawDRRectOp() : PaintOpWithFlags(kType) {}
+};
+
+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();
+ DrawImageOp(const DrawImageOp&) = default;
+ DrawImageOp& operator=(const DrawImageOp&) = default;
+ static void RasterWithFlags(const DrawImageOp* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const PlaybackParams& params);
+ bool IsValid() const {
+ return flags.IsValid() && SkScalarIsFinite(scale_adjustment.width()) &&
+ SkScalarIsFinite(scale_adjustment.height());
+ }
+ static bool AreEqual(const PaintOp* left, const PaintOp* right);
+ bool HasDiscardableImages() const;
+ bool HasNonAAPaint() const { return false; }
+ HAS_SERIALIZATION_FUNCTIONS();
+
+ PaintImage image;
+ SkScalar left;
+ SkScalar top;
+ SkSamplingOptions sampling;
+
+ private:
+ DrawImageOp();
+
+ // Scale that has already been applied to the decoded image during
+ // serialization. Used with OOP raster.
+ SkSize scale_adjustment = SkSize::Make(1.f, 1.f);
+};
+
+class CC_PAINT_EXPORT DrawImageRectOp final : public PaintOpWithFlags {
+ public:
+ static constexpr PaintOpType kType = PaintOpType::DrawImageRect;
+ static constexpr bool kIsDrawOp = true;
+ 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();
+ DrawImageRectOp(const DrawImageRectOp&) = default;
+ DrawImageRectOp& operator=(const DrawImageRectOp&) = default;
+ static void RasterWithFlags(const DrawImageRectOp* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const PlaybackParams& params);
+ bool IsValid() const {
+ return flags.IsValid() && src.isFinite() && dst.isFinite() &&
+ SkScalarIsFinite(scale_adjustment.width()) &&
+ SkScalarIsFinite(scale_adjustment.height());
+ }
+ static bool AreEqual(const PaintOp* left, const PaintOp* right);
+ bool HasDiscardableImages() const;
+ HAS_SERIALIZATION_FUNCTIONS();
+
+ PaintImage image;
+ SkRect src;
+ SkRect dst;
+ SkSamplingOptions sampling;
+ SkCanvas::SrcRectConstraint constraint;
+
+ private:
+ DrawImageRectOp();
+
+ // Scale that has already been applied to the decoded image during
+ // serialization. Used with OOP raster.
+ SkSize scale_adjustment = SkSize::Make(1.f, 1.f);
+};
+
+class CC_PAINT_EXPORT DrawIRectOp final : public PaintOpWithFlags {
+ public:
+ static constexpr PaintOpType kType = PaintOpType::DrawIRect;
+ static constexpr bool kIsDrawOp = true;
+ DrawIRectOp(const SkIRect& rect, const PaintFlags& flags)
+ : PaintOpWithFlags(kType, flags), rect(rect) {}
+ DrawIRectOp(const DrawIRectOp&) = default;
+ DrawIRectOp& operator=(const DrawIRectOp&) = default;
+ static void RasterWithFlags(const DrawIRectOp* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const PlaybackParams& params);
+ bool IsValid() const { return flags.IsValid(); }
+ static bool AreEqual(const PaintOp* left, const PaintOp* right);
+ bool HasNonAAPaint() const { return false; }
+ HAS_SERIALIZATION_FUNCTIONS();
+
+ SkIRect rect;
+
+ private:
+ DrawIRectOp() : PaintOpWithFlags(kType) {}
+};
+
+class CC_PAINT_EXPORT DrawLineOp final : public PaintOpWithFlags {
+ public:
+ static constexpr PaintOpType kType = PaintOpType::DrawLine;
+ static constexpr bool kIsDrawOp = true;
+ DrawLineOp(SkScalar x0,
+ SkScalar y0,
+ SkScalar x1,
+ SkScalar y1,
+ const PaintFlags& flags)
+ : PaintOpWithFlags(kType, flags), x0(x0), y0(y0), x1(x1), y1(y1) {}
+ DrawLineOp(const DrawLineOp&) = default;
+ DrawLineOp& operator=(const DrawLineOp&) = default;
+ static void RasterWithFlags(const DrawLineOp* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const PlaybackParams& params);
+ bool IsValid() const { return flags.IsValid(); }
+ static bool AreEqual(const PaintOp* left, const PaintOp* right);
+ HAS_SERIALIZATION_FUNCTIONS();
+
+ int CountSlowPaths() const;
+
+ SkScalar x0;
+ SkScalar y0;
+ SkScalar x1;
+ SkScalar y1;
+
+ private:
+ DrawLineOp() : PaintOpWithFlags(kType) {}
+};
+
+class CC_PAINT_EXPORT DrawOvalOp final : public PaintOpWithFlags {
+ public:
+ static constexpr PaintOpType kType = PaintOpType::DrawOval;
+ static constexpr bool kIsDrawOp = true;
+ DrawOvalOp(const SkRect& oval, const PaintFlags& flags)
+ : PaintOpWithFlags(kType, flags), oval(oval) {}
+ DrawOvalOp(const DrawOvalOp&) = default;
+ DrawOvalOp& operator=(const DrawOvalOp&) = default;
+ static void RasterWithFlags(const DrawOvalOp* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const PlaybackParams& params);
+ bool IsValid() const {
+ // Reproduce SkRRect::isValid without converting.
+ return flags.IsValid() && oval.isFinite() && oval.isSorted();
+ }
+ static bool AreEqual(const PaintOp* left, const PaintOp* right);
+ HAS_SERIALIZATION_FUNCTIONS();
+
+ SkRect oval;
+
+ private:
+ DrawOvalOp() : PaintOpWithFlags(kType) {}
+};
+
+class CC_PAINT_EXPORT DrawPathOp final : public PaintOpWithFlags {
+ public:
+ static constexpr PaintOpType kType = PaintOpType::DrawPath;
+ static constexpr bool kIsDrawOp = true;
+ DrawPathOp(const SkPath& path,
+ const PaintFlags& flags,
+ UsePaintCache use_paint_cache = UsePaintCache::kEnabled)
+ : PaintOpWithFlags(kType, flags),
+ path(path),
+ sk_path_fill_type(static_cast<uint8_t>(path.getFillType())),
+ use_cache(use_paint_cache) {}
+ DrawPathOp(const DrawPathOp&) = default;
+ DrawPathOp& operator=(const DrawPathOp&) = default;
+ static void RasterWithFlags(const DrawPathOp* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const PlaybackParams& params);
+ bool IsValid() const { return flags.IsValid() && IsValidPath(path); }
+ static bool AreEqual(const PaintOp* left, const PaintOp* right);
+ int CountSlowPaths() const;
+ HAS_SERIALIZATION_FUNCTIONS();
+
+ 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;
+ UsePaintCache use_cache;
+
+ private:
+ DrawPathOp() : PaintOpWithFlags(kType) {}
+};
+
+class CC_PAINT_EXPORT DrawRecordOp final : public PaintOp {
+ public:
+ static constexpr PaintOpType kType = PaintOpType::DrawRecord;
+ static constexpr bool kIsDrawOp = true;
+ explicit DrawRecordOp(sk_sp<const PaintRecord> record);
+ ~DrawRecordOp();
+ DrawRecordOp(const DrawRecordOp&);
+ DrawRecordOp& operator=(const DrawRecordOp&);
+ static void Raster(const DrawRecordOp* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params);
+ bool IsValid() const { return true; }
+ static bool AreEqual(const PaintOp* left, const PaintOp* right);
+ size_t AdditionalBytesUsed() const;
+ size_t AdditionalOpCount() const;
+ bool HasDiscardableImages() const;
+ int CountSlowPaths() const;
+ bool HasNonAAPaint() const;
+ bool HasDrawTextOps() const;
+ bool HasSaveLayerOps() const;
+ bool HasSaveLayerAlphaOps() const;
+ bool HasEffectsPreventingLCDTextForSaveLayerAlpha() const;
+ HAS_SERIALIZATION_FUNCTIONS();
+
+ sk_sp<const PaintRecord> record;
+};
+
+class CC_PAINT_EXPORT DrawRectOp final : public PaintOpWithFlags {
+ public:
+ static constexpr PaintOpType kType = PaintOpType::DrawRect;
+ static constexpr bool kIsDrawOp = true;
+ DrawRectOp(const SkRect& rect, const PaintFlags& flags)
+ : PaintOpWithFlags(kType, flags), rect(rect) {}
+ DrawRectOp(const DrawRectOp&) = default;
+ DrawRectOp& operator=(const DrawRectOp&) = default;
+ static void RasterWithFlags(const DrawRectOp* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const PlaybackParams& params);
+ bool IsValid() const { return flags.IsValid() && rect.isFinite(); }
+ static bool AreEqual(const PaintOp* left, const PaintOp* right);
+ HAS_SERIALIZATION_FUNCTIONS();
+
+ SkRect rect;
+
+ private:
+ DrawRectOp() : PaintOpWithFlags(kType) {}
+};
+
+class CC_PAINT_EXPORT DrawRRectOp final : public PaintOpWithFlags {
+ public:
+ static constexpr PaintOpType kType = PaintOpType::DrawRRect;
+ static constexpr bool kIsDrawOp = true;
+ DrawRRectOp(const SkRRect& rrect, const PaintFlags& flags)
+ : PaintOpWithFlags(kType, flags), rrect(rrect) {}
+ DrawRRectOp(const DrawRRectOp&) = default;
+ DrawRRectOp& operator=(const DrawRRectOp&) = default;
+ static void RasterWithFlags(const DrawRRectOp* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const PlaybackParams& params);
+ bool IsValid() const { return flags.IsValid() && rrect.isValid(); }
+ static bool AreEqual(const PaintOp* left, const PaintOp* right);
+ HAS_SERIALIZATION_FUNCTIONS();
+
+ SkRRect rrect;
+
+ private:
+ DrawRRectOp() : PaintOpWithFlags(kType) {}
+};
+
+class CC_PAINT_EXPORT DrawSkottieOp final : public PaintOp {
+ public:
+ static constexpr PaintOpType kType = PaintOpType::DrawSkottie;
+ static constexpr bool kIsDrawOp = true;
+ DrawSkottieOp(scoped_refptr<SkottieWrapper> skottie,
+ SkRect dst,
+ float t,
+ SkottieFrameDataMap images,
+ const SkottieColorMap& color_map,
+ SkottieTextPropertyValueMap text_map);
+ ~DrawSkottieOp();
+ DrawSkottieOp(const DrawSkottieOp&);
+ DrawSkottieOp& operator=(const DrawSkottieOp&);
+ static void Raster(const DrawSkottieOp* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params);
+ bool IsValid() const {
+ return !!skottie && !dst.isEmpty() && t >= 0 && t <= 1.f;
+ }
+ static bool AreEqual(const PaintOp* left, const PaintOp* right);
+ bool HasDiscardableImages() const;
+ HAS_SERIALIZATION_FUNCTIONS();
+
+ scoped_refptr<SkottieWrapper> skottie;
+ SkRect dst;
+ float t;
+ // Image to use for each asset in this frame of the animation. If an asset is
+ // missing, the most recently used image for that asset (from a previous
+ // DrawSkottieOp) gets reused when rendering this frame. Given that image
+ // assets generally do not change from frame to frame in most animations, that
+ // means in practice, this map is often empty.
+ SkottieFrameDataMap images;
+ // Node name hashes and corresponding colors to use for dynamic coloration.
+ SkottieColorMap color_map;
+ SkottieTextPropertyValueMap text_map;
+
+ private:
+ SkottieWrapper::FrameDataFetchResult GetImageAssetForRaster(
+ SkCanvas* canvas,
+ const PlaybackParams& params,
+ SkottieResourceIdHash asset_id,
+ float t_frame,
+ sk_sp<SkImage>& image_out,
+ SkSamplingOptions& sampling_out) const;
+
+ DrawSkottieOp();
+};
+
+// TODO(penghuang): Replace DrawTextBlobOp with DrawSlugOp, when GrSlug can be
+// serialized.
+class CC_PAINT_EXPORT DrawTextBlobOp final : public PaintOpWithFlags {
+ public:
+ static constexpr PaintOpType kType = PaintOpType::DrawTextBlob;
+ static constexpr bool kIsDrawOp = true;
+ DrawTextBlobOp(sk_sp<SkTextBlob> blob,
+ SkScalar x,
+ SkScalar y,
+ const PaintFlags& flags);
+ DrawTextBlobOp(sk_sp<SkTextBlob> blob,
+ SkScalar x,
+ SkScalar y,
+ NodeId node_id,
+ const PaintFlags& flags);
+ ~DrawTextBlobOp();
+ DrawTextBlobOp(const DrawTextBlobOp&);
+ DrawTextBlobOp& operator=(const DrawTextBlobOp&);
+ static void RasterWithFlags(const DrawTextBlobOp* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const PlaybackParams& params);
+ bool IsValid() const { return flags.IsValid(); }
+ bool HasDrawTextOps() const { return true; }
+ static bool AreEqual(const PaintOp* left, const PaintOp* right);
+ HAS_SERIALIZATION_FUNCTIONS();
+
+ sk_sp<SkTextBlob> blob;
+ sk_sp<GrSlug> slug;
+ std::vector<sk_sp<GrSlug>> extra_slugs;
+ SkScalar x;
+ SkScalar y;
+ // This field isn't serialized.
+ NodeId node_id = kInvalidNodeId;
+
+ private:
+ DrawTextBlobOp();
+};
+
+class CC_PAINT_EXPORT NoopOp final : public PaintOp {
+ public:
+ static constexpr PaintOpType kType = PaintOpType::Noop;
+ NoopOp() : PaintOp(kType) {}
+ NoopOp(const NoopOp&) = default;
+ NoopOp& operator=(const NoopOp&) = default;
+ static void Raster(const NoopOp* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params) {}
+ bool IsValid() const { return true; }
+ static bool AreEqual(const PaintOp* left, const PaintOp* right);
+ HAS_SERIALIZATION_FUNCTIONS();
+};
+
+class CC_PAINT_EXPORT RestoreOp final : public PaintOp {
+ public:
+ static constexpr PaintOpType kType = PaintOpType::Restore;
+ RestoreOp() : PaintOp(kType) {}
+ RestoreOp(const RestoreOp&) = default;
+ RestoreOp& operator=(const RestoreOp&) = default;
+ static void Raster(const RestoreOp* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params);
+ bool IsValid() const { return true; }
+ static bool AreEqual(const PaintOp* left, const PaintOp* right);
+ HAS_SERIALIZATION_FUNCTIONS();
+};
+
+class CC_PAINT_EXPORT RotateOp final : public PaintOp {
+ public:
+ static constexpr PaintOpType kType = PaintOpType::Rotate;
+ explicit RotateOp(SkScalar degrees) : PaintOp(kType), degrees(degrees) {}
+ RotateOp(const RotateOp&) = default;
+ RotateOp& operator=(const RotateOp&) = default;
+ static void Raster(const RotateOp* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params);
+ bool IsValid() const { return true; }
+ static bool AreEqual(const PaintOp* left, const PaintOp* right);
+ HAS_SERIALIZATION_FUNCTIONS();
+
+ SkScalar degrees;
+
+ private:
+ RotateOp() : PaintOp(kType) {}
+};
+
+class CC_PAINT_EXPORT SaveOp final : public PaintOp {
+ public:
+ static constexpr PaintOpType kType = PaintOpType::Save;
+ SaveOp() : PaintOp(kType) {}
+ SaveOp(const SaveOp&) = default;
+ SaveOp& operator=(const SaveOp&) = default;
+ static void Raster(const SaveOp* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params);
+ bool IsValid() const { return true; }
+ static bool AreEqual(const PaintOp* left, const PaintOp* right);
+ HAS_SERIALIZATION_FUNCTIONS();
+};
+
+class CC_PAINT_EXPORT SaveLayerOp final : public PaintOpWithFlags {
+ public:
+ static constexpr PaintOpType kType = PaintOpType::SaveLayer;
+ SaveLayerOp(const SkRect* bounds, const PaintFlags* flags)
+ : PaintOpWithFlags(kType, flags ? *flags : PaintFlags()),
+ bounds(bounds ? *bounds : kUnsetRect) {}
+ SaveLayerOp(const SaveLayerOp&) = default;
+ SaveLayerOp& operator=(const SaveLayerOp&) = default;
+ static void RasterWithFlags(const SaveLayerOp* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const PlaybackParams& params);
+ bool IsValid() const { return flags.IsValid() && IsValidOrUnsetRect(bounds); }
+ static bool AreEqual(const PaintOp* left, const PaintOp* right);
+ bool HasNonAAPaint() const { return false; }
+ // We simply assume any effects (or even no effects -- just starting an empty
+ // transparent layer) would break LCD text or be broken by the flags for
+ // SaveLayerAlpha to preserve LCD text.
+ bool HasEffectsPreventingLCDTextForSaveLayerAlpha() const { return true; }
+ bool HasSaveLayerOps() const { return true; }
+ HAS_SERIALIZATION_FUNCTIONS();
+
+ SkRect bounds;
+
+ private:
+ SaveLayerOp() : PaintOpWithFlags(kType) {}
+};
+
+class CC_PAINT_EXPORT SaveLayerAlphaOp final : public PaintOp {
+ public:
+ static constexpr PaintOpType kType = PaintOpType::SaveLayerAlpha;
+ template <class F, class = std::enable_if_t<std::is_same_v<F, float>>>
+ SaveLayerAlphaOp(const SkRect* bounds, F alpha)
+ : PaintOp(kType), bounds(bounds ? *bounds : kUnsetRect), alpha(alpha) {}
+ SaveLayerAlphaOp(const SaveLayerAlphaOp&) = default;
+ SaveLayerAlphaOp& operator=(const SaveLayerAlphaOp&) = default;
+ static void Raster(const SaveLayerAlphaOp* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params);
+ bool IsValid() const { return IsValidOrUnsetRect(bounds); }
+ static bool AreEqual(const PaintOp* left, const PaintOp* right);
+ bool HasSaveLayerOps() const { return true; }
+ bool HasSaveLayerAlphaOps() const { return true; }
+ HAS_SERIALIZATION_FUNCTIONS();
+
+ SkRect bounds;
+ float alpha;
+
+ private:
+ SaveLayerAlphaOp() : PaintOp(kType) {}
+};
+
+class CC_PAINT_EXPORT ScaleOp final : public PaintOp {
+ public:
+ static constexpr PaintOpType kType = PaintOpType::Scale;
+ ScaleOp(SkScalar sx, SkScalar sy) : PaintOp(kType), sx(sx), sy(sy) {}
+ ScaleOp(const ScaleOp&) = default;
+ ScaleOp& operator=(const ScaleOp&) = default;
+ static void Raster(const ScaleOp* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params);
+ bool IsValid() const { return true; }
+ static bool AreEqual(const PaintOp* left, const PaintOp* right);
+ HAS_SERIALIZATION_FUNCTIONS();
+
+ SkScalar sx;
+ SkScalar sy;
+
+ private:
+ ScaleOp() : PaintOp(kType) {}
+};
+
+class CC_PAINT_EXPORT SetMatrixOp final : public PaintOp {
+ public:
+ static constexpr PaintOpType kType = PaintOpType::SetMatrix;
+ explicit SetMatrixOp(const SkM44& matrix) : PaintOp(kType), matrix(matrix) {}
+ SetMatrixOp(const SetMatrixOp&) = default;
+ SetMatrixOp& operator=(const SetMatrixOp&) = default;
+ // 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).
+ //
+ // TODO(enne): Find some cleaner way to do this, possibly by making
+ // all SetMatrix calls Concat??
+ static void Raster(const SetMatrixOp* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params);
+ bool IsValid() const { return true; }
+ static bool AreEqual(const PaintOp* left, const PaintOp* right);
+ HAS_SERIALIZATION_FUNCTIONS();
+
+ SkM44 matrix;
+
+ private:
+ SetMatrixOp() : PaintOp(kType) {}
+};
+
+class CC_PAINT_EXPORT SetNodeIdOp final : public PaintOp {
+ public:
+ static constexpr PaintOpType kType = PaintOpType::SetNodeId;
+ explicit SetNodeIdOp(int node_id) : PaintOp(kType), node_id(node_id) {}
+ SetNodeIdOp(const SetNodeIdOp&) = default;
+ SetNodeIdOp& operator=(const SetNodeIdOp&) = default;
+ static void Raster(const SetNodeIdOp* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params);
+ bool IsValid() const { return true; }
+ static bool AreEqual(const PaintOp* left, const PaintOp* right);
+ HAS_SERIALIZATION_FUNCTIONS();
+
+ int node_id;
+
+ private:
+ SetNodeIdOp() : PaintOp(kType) {}
+};
+
+class CC_PAINT_EXPORT TranslateOp final : public PaintOp {
+ public:
+ static constexpr PaintOpType kType = PaintOpType::Translate;
+ TranslateOp(SkScalar dx, SkScalar dy) : PaintOp(kType), dx(dx), dy(dy) {}
+ TranslateOp(const TranslateOp&) = default;
+ TranslateOp& operator=(const TranslateOp&) = default;
+ static void Raster(const TranslateOp* op,
+ SkCanvas* canvas,
+ const PlaybackParams& params);
+ bool IsValid() const { return true; }
+ static bool AreEqual(const PaintOp* left, const PaintOp* right);
+ HAS_SERIALIZATION_FUNCTIONS();
+
+ SkScalar dx;
+ SkScalar dy;
+
+ private:
+ TranslateOp() : PaintOp(kType) {}
+};
+
+#undef HAS_SERIALIZATION_FUNCTIONS
+
+// TODO(vmpstr): Revisit this when sizes of DrawImageRectOp change.
+using LargestPaintOp =
+ typename std::conditional<(sizeof(DrawImageRectOp) > sizeof(DrawDRRectOp)),
+ DrawImageRectOp,
+ DrawDRRectOp>::type;
+
+} // namespace cc
+
+#endif // CC_PAINT_PAINT_OP_H_
diff --git a/chromium/cc/paint/paint_op_buffer.cc b/chromium/cc/paint/paint_op_buffer.cc
index ffa98746562..05eea334fe0 100644
--- a/chromium/cc/paint/paint_op_buffer.cc
+++ b/chromium/cc/paint/paint_op_buffer.cc
@@ -5,377 +5,22 @@
#include "cc/paint/paint_op_buffer.h"
#include <algorithm>
-#include <memory>
#include <utility>
-#include <vector>
-#include "base/bind.h"
-#include "base/memory/raw_ptr.h"
#include "base/notreached.h"
#include "base/types/optional_util.h"
-#include "cc/paint/decoded_draw_image.h"
-#include "cc/paint/display_item_list.h"
-#include "cc/paint/image_provider.h"
#include "cc/paint/paint_flags.h"
#include "cc/paint/paint_image_builder.h"
+#include "cc/paint/paint_op.h"
+#include "cc/paint/paint_op_buffer_iterator.h"
#include "cc/paint/paint_op_reader.h"
#include "cc/paint/paint_op_writer.h"
#include "cc/paint/paint_record.h"
#include "cc/paint/scoped_raster_flags.h"
#include "cc/paint/skottie_serialization_history.h"
-#include "third_party/abseil-cpp/absl/types/variant.h"
-#include "third_party/skia/include/core/SkAnnotation.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-#include "third_party/skia/include/core/SkColorSpace.h"
-#include "third_party/skia/include/core/SkImage.h"
-#include "third_party/skia/include/core/SkRegion.h"
-#include "third_party/skia/include/core/SkSerialProcs.h"
-#include "third_party/skia/include/core/SkTextBlob.h"
-#include "third_party/skia/include/docs/SkPDFDocument.h"
#include "third_party/skia/include/gpu/GrRecordingContext.h"
-#include "third_party/skia/include/private/chromium/GrSlug.h"
-#include "ui/gfx/geometry/skia_conversions.h"
namespace cc {
-namespace {
-// In a future CL, convert DrawImage to explicitly take sampling instead of
-// quality
-PaintFlags::FilterQuality sampling_to_quality(
- const SkSamplingOptions& sampling) {
- if (sampling.useCubic) {
- return PaintFlags::FilterQuality::kHigh;
- }
- if (sampling.mipmap != SkMipmapMode::kNone) {
- return PaintFlags::FilterQuality::kMedium;
- }
- return sampling.filter == SkFilterMode::kLinear
- ? PaintFlags::FilterQuality::kLow
- : PaintFlags::FilterQuality::kNone;
-}
-
-DrawImage CreateDrawImage(const PaintImage& image,
- const PaintFlags* flags,
- const SkSamplingOptions& sampling,
- const SkM44& matrix) {
- if (!image)
- return DrawImage();
- return DrawImage(image, flags->useDarkModeForImage(),
- SkIRect::MakeWH(image.width(), image.height()),
- sampling_to_quality(sampling), matrix);
-}
-
-bool IsScaleAdjustmentIdentity(const SkSize& scale_adjustment) {
- return std::abs(scale_adjustment.width() - 1.f) < FLT_EPSILON &&
- std::abs(scale_adjustment.height() - 1.f) < FLT_EPSILON;
-}
-
-SkRect AdjustSrcRectForScale(SkRect original, SkSize scale_adjustment) {
- if (IsScaleAdjustmentIdentity(scale_adjustment))
- return original;
-
- float x_scale = scale_adjustment.width();
- float y_scale = scale_adjustment.height();
- return SkRect::MakeXYWH(original.x() * x_scale, original.y() * y_scale,
- original.width() * x_scale,
- original.height() * y_scale);
-}
-
-SkRect MapRect(const SkMatrix& matrix, const SkRect& src) {
- SkRect dst;
- matrix.mapRect(&dst, src);
- return dst;
-}
-
-void DrawImageRect(SkCanvas* canvas,
- const SkImage* image,
- const SkRect& src,
- const SkRect& dst,
- const SkSamplingOptions& options,
- const SkPaint* paint,
- SkCanvas::SrcRectConstraint constraint) {
- if (!image)
- return;
- if (constraint == SkCanvas::kStrict_SrcRectConstraint &&
- options.mipmap != SkMipmapMode::kNone &&
- src.contains(SkRect::Make(image->dimensions()))) {
- SkMatrix m;
- m.setRectToRect(src, dst, SkMatrix::ScaleToFit::kFill_ScaleToFit);
- canvas->save();
- canvas->concat(m);
- canvas->drawImage(image, 0, 0, options, paint);
- canvas->restore();
- return;
- }
- canvas->drawImageRect(image, src, dst, options, paint, constraint);
-}
-
-bool GrSlugAreEqual(sk_sp<GrSlug> left, sk_sp<GrSlug> right) {
- if (!left && !right) {
- return true;
- }
- if (left && right) {
- auto left_data = left->serialize();
- auto right_data = right->serialize();
- return left_data->equals(right_data.get());
- }
- return false;
-}
-
-} // namespace
-
-#define TYPES(M) \
- M(AnnotateOp) \
- M(ClipPathOp) \
- M(ClipRectOp) \
- M(ClipRRectOp) \
- M(ConcatOp) \
- M(CustomDataOp) \
- M(DrawColorOp) \
- M(DrawDRRectOp) \
- M(DrawImageOp) \
- M(DrawImageRectOp) \
- M(DrawIRectOp) \
- M(DrawLineOp) \
- M(DrawOvalOp) \
- M(DrawPathOp) \
- M(DrawRecordOp) \
- M(DrawRectOp) \
- M(DrawRRectOp) \
- M(DrawSkottieOp) \
- M(DrawTextBlobOp) \
- M(NoopOp) \
- M(RestoreOp) \
- M(RotateOp) \
- M(SaveOp) \
- M(SaveLayerOp) \
- M(SaveLayerAlphaOp) \
- M(ScaleOp) \
- M(SetMatrixOp) \
- M(SetNodeIdOp) \
- M(TranslateOp)
-
-static constexpr size_t kNumOpTypes =
- static_cast<size_t>(PaintOpType::LastPaintOpType) + 1;
-
-// Verify that every op is in the TYPES macro.
-#define M(T) +1
-static_assert(kNumOpTypes == TYPES(M), "Missing op in list");
-#undef M
-
-#define M(T) sizeof(T),
-static const size_t g_type_to_size[kNumOpTypes] = {TYPES(M)};
-#undef M
-
-template <typename T, bool HasFlags>
-struct Rasterizer {
- static void RasterWithFlags(const T* op,
- const PaintFlags* flags,
- SkCanvas* canvas,
- const PlaybackParams& params) {
- static_assert(
- !T::kHasPaintFlags,
- "This function should not be used for a PaintOp that has PaintFlags");
- DCHECK(op->IsValid());
- NOTREACHED();
- }
- static void Raster(const T* op,
- SkCanvas* canvas,
- const PlaybackParams& params) {
- static_assert(
- !T::kHasPaintFlags,
- "This function should not be used for a PaintOp that has PaintFlags");
- DCHECK(op->IsValid());
- T::Raster(op, canvas, params);
- }
-};
-
-template <typename T>
-struct Rasterizer<T, true> {
- static void RasterWithFlags(const T* op,
- const PaintFlags* flags,
- SkCanvas* canvas,
- const PlaybackParams& params) {
- static_assert(T::kHasPaintFlags,
- "This function expects the PaintOp to have PaintFlags");
- DCHECK(op->IsValid());
- T::RasterWithFlags(op, flags, canvas, params);
- }
-
- static void Raster(const T* op,
- SkCanvas* canvas,
- const PlaybackParams& params) {
- static_assert(T::kHasPaintFlags,
- "This function expects the PaintOp to have PaintFlags");
- DCHECK(op->IsValid());
- T::RasterWithFlags(op, &op->flags, canvas, params);
- }
-};
-
-using RasterFunction = void (*)(const PaintOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params);
-#define M(T) \
- [](const PaintOp* op, SkCanvas* canvas, const PlaybackParams& params) { \
- Rasterizer<T, T::kHasPaintFlags>::Raster(static_cast<const T*>(op), \
- canvas, params); \
- },
-static const RasterFunction g_raster_functions[kNumOpTypes] = {TYPES(M)};
-#undef M
-
-using RasterWithFlagsFunction = void (*)(const PaintOp* op,
- const PaintFlags* flags,
- SkCanvas* canvas,
- const PlaybackParams& params);
-#define M(T) \
- [](const PaintOp* op, const PaintFlags* flags, SkCanvas* canvas, \
- const PlaybackParams& params) { \
- Rasterizer<T, T::kHasPaintFlags>::RasterWithFlags( \
- static_cast<const T*>(op), flags, canvas, params); \
- },
-static const RasterWithFlagsFunction
- g_raster_with_flags_functions[kNumOpTypes] = {TYPES(M)};
-#undef M
-
-using SerializeFunction = size_t (*)(const PaintOp* op,
- void* memory,
- size_t size,
- const PaintOp::SerializeOptions& options,
- const PaintFlags* flags_to_serialize,
- const SkM44& current_ctm,
- const SkM44& original_ctm);
-
-#define M(T) &T::Serialize,
-static const SerializeFunction g_serialize_functions[kNumOpTypes] = {TYPES(M)};
-#undef M
-
-using DeserializeFunction =
- PaintOp* (*)(const volatile void* input,
- size_t input_size,
- void* output,
- size_t output_size,
- const PaintOp::DeserializeOptions& options);
-
-#define M(T) &T::Deserialize,
-static const DeserializeFunction g_deserialize_functions[kNumOpTypes] = {
- TYPES(M)};
-#undef M
-
-using EqualsFunction = bool (*)(const PaintOp* left, const PaintOp* right);
-#define M(T) &T::AreEqual,
-static const EqualsFunction g_equals_operator[kNumOpTypes] = {TYPES(M)};
-#undef M
-
-// Most state ops (matrix, clip, save, restore) have a trivial destructor.
-// TODO(enne): evaluate if we need the nullptr optimization or if
-// we even need to differentiate trivial destructors here.
-using VoidFunction = void (*)(PaintOp* op);
-#define M(T) \
- !std::is_trivially_destructible<T>::value \
- ? [](PaintOp* op) { static_cast<T*>(op)->~T(); } \
- : static_cast<VoidFunction>(nullptr),
-static const VoidFunction g_destructor_functions[kNumOpTypes] = {TYPES(M)};
-#undef M
-
-#define M(T) T::kIsDrawOp,
-static bool g_is_draw_op[kNumOpTypes] = {TYPES(M)};
-#undef M
-
-#define M(T) T::kHasPaintFlags,
-static bool g_has_paint_flags[kNumOpTypes] = {TYPES(M)};
-#undef M
-
-#define M(T) \
- static_assert(sizeof(T) <= sizeof(LargestPaintOp), \
- #T " must be no bigger than LargestPaintOp");
-TYPES(M)
-#undef M
-
-#define M(T) \
- static_assert(alignof(T) <= PaintOpBuffer::PaintOpAlign, \
- #T " must have alignment no bigger than PaintOpAlign");
-TYPES(M)
-#undef M
-
-using AnalyzeOpFunc = void (*)(PaintOpBuffer*, const PaintOp*);
-#define M(T) \
- [](PaintOpBuffer* buffer, const PaintOp* op) { \
- buffer->AnalyzeAddedOp(static_cast<const T*>(op)); \
- },
-static const AnalyzeOpFunc g_analyze_op_functions[kNumOpTypes] = {TYPES(M)};
-#undef M
-
-#undef TYPES
-
-const SkRect PaintOp::kUnsetRect = {SK_ScalarInfinity, 0, 0, 0};
-const size_t PaintOp::kMaxSkip;
-
-std::string PaintOpTypeToString(PaintOpType type) {
- switch (type) {
- case PaintOpType::Annotate:
- return "Annotate";
- case PaintOpType::ClipPath:
- return "ClipPath";
- case PaintOpType::ClipRect:
- return "ClipRect";
- case PaintOpType::ClipRRect:
- return "ClipRRect";
- case PaintOpType::Concat:
- return "Concat";
- case PaintOpType::CustomData:
- return "CustomData";
- case PaintOpType::DrawColor:
- return "DrawColor";
- case PaintOpType::DrawDRRect:
- return "DrawDRRect";
- case PaintOpType::DrawImage:
- return "DrawImage";
- case PaintOpType::DrawImageRect:
- return "DrawImageRect";
- case PaintOpType::DrawIRect:
- return "DrawIRect";
- case PaintOpType::DrawLine:
- return "DrawLine";
- case PaintOpType::DrawOval:
- return "DrawOval";
- case PaintOpType::DrawPath:
- return "DrawPath";
- case PaintOpType::DrawRecord:
- return "DrawRecord";
- case PaintOpType::DrawRect:
- return "DrawRect";
- case PaintOpType::DrawRRect:
- return "DrawRRect";
- case PaintOpType::DrawSkottie:
- return "DrawSkottie";
- case PaintOpType::DrawTextBlob:
- return "DrawTextBlob";
- case PaintOpType::Noop:
- return "Noop";
- case PaintOpType::Restore:
- return "Restore";
- case PaintOpType::Rotate:
- return "Rotate";
- case PaintOpType::Save:
- return "Save";
- case PaintOpType::SaveLayer:
- return "SaveLayer";
- case PaintOpType::SaveLayerAlpha:
- return "SaveLayerAlpha";
- case PaintOpType::Scale:
- return "Scale";
- case PaintOpType::SetMatrix:
- return "SetMatrix";
- case PaintOpType::SetNodeId:
- return "SetNodeId";
- case PaintOpType::Translate:
- return "Translate";
- }
- return "UNKNOWN";
-}
-
-std::ostream& operator<<(std::ostream& os, PaintOpType type) {
- return os << PaintOpTypeToString(type);
-}
PlaybackParams::PlaybackParams(ImageProvider* image_provider)
: PlaybackParams(image_provider, SkM44()) {}
@@ -383,11 +28,13 @@ PlaybackParams::PlaybackParams(ImageProvider* image_provider)
PlaybackParams::PlaybackParams(ImageProvider* image_provider,
const SkM44& original_ctm,
CustomDataRasterCallback custom_callback,
- DidDrawOpCallback did_draw_op_callback)
+ DidDrawOpCallback did_draw_op_callback,
+ ConvertOpCallback convert_op_callback)
: image_provider(image_provider),
original_ctm(original_ctm),
custom_callback(custom_callback),
- did_draw_op_callback(did_draw_op_callback) {}
+ did_draw_op_callback(std::move(did_draw_op_callback)),
+ convert_op_callback(std::move(convert_op_callback)) {}
PlaybackParams::~PlaybackParams() = default;
@@ -395,7 +42,7 @@ PlaybackParams::PlaybackParams(const PlaybackParams& other) = default;
PlaybackParams& PlaybackParams::operator=(const PlaybackParams& other) =
default;
-PaintOp::SerializeOptions::SerializeOptions(
+PaintOpBuffer::SerializeOptions::SerializeOptions(
ImageProvider* image_provider,
TransferCacheSerializeHelper* transfer_cache,
ClientPaintCache* paint_cache,
@@ -416,13 +63,14 @@ PaintOp::SerializeOptions::SerializeOptions(
context_supports_distance_field_text),
max_texture_size(max_texture_size) {}
-PaintOp::SerializeOptions::SerializeOptions() = default;
-PaintOp::SerializeOptions::SerializeOptions(const SerializeOptions&) = default;
-PaintOp::SerializeOptions& PaintOp::SerializeOptions::operator=(
+PaintOpBuffer::SerializeOptions::SerializeOptions() = default;
+PaintOpBuffer::SerializeOptions::SerializeOptions(const SerializeOptions&) =
+ default;
+PaintOpBuffer::SerializeOptions& PaintOpBuffer::SerializeOptions::operator=(
const SerializeOptions&) = default;
-PaintOp::SerializeOptions::~SerializeOptions() = default;
+PaintOpBuffer::SerializeOptions::~SerializeOptions() = default;
-PaintOp::DeserializeOptions::DeserializeOptions(
+PaintOpBuffer::DeserializeOptions::DeserializeOptions(
TransferCacheDeserializeHelper* transfer_cache,
ServicePaintCache* paint_cache,
SkStrikeClient* strike_client,
@@ -438,2474 +86,6 @@ PaintOp::DeserializeOptions::DeserializeOptions(
DCHECK(scratch_buffer);
}
-size_t AnnotateOp::Serialize(const PaintOp* base_op,
- void* memory,
- size_t size,
- const SerializeOptions& options,
- const PaintFlags* flags_to_serialize,
- const SkM44& current_ctm,
- const SkM44& original_ctm) {
- auto* op = static_cast<const AnnotateOp*>(base_op);
- PaintOpWriter helper(memory, size, options);
- helper.Write(op->annotation_type);
- helper.Write(op->rect);
- helper.Write(op->data);
- return helper.size();
-}
-
-size_t ClipPathOp::Serialize(const PaintOp* base_op,
- void* memory,
- size_t size,
- const SerializeOptions& options,
- const PaintFlags* flags_to_serialize,
- const SkM44& current_ctm,
- const SkM44& original_ctm) {
- auto* op = static_cast<const ClipPathOp*>(base_op);
- PaintOpWriter helper(memory, size, options);
- helper.Write(op->path, op->use_cache);
- helper.Write(op->op);
- helper.Write(op->antialias);
- return helper.size();
-}
-
-size_t ClipRectOp::Serialize(const PaintOp* base_op,
- void* memory,
- size_t size,
- const SerializeOptions& options,
- const PaintFlags* flags_to_serialize,
- const SkM44& current_ctm,
- const SkM44& original_ctm) {
- auto* op = static_cast<const ClipRectOp*>(base_op);
- PaintOpWriter helper(memory, size, options);
- helper.Write(op->rect);
- helper.Write(op->op);
- helper.Write(op->antialias);
- return helper.size();
-}
-
-size_t ClipRRectOp::Serialize(const PaintOp* base_op,
- void* memory,
- size_t size,
- const SerializeOptions& options,
- const PaintFlags* flags_to_serialize,
- const SkM44& current_ctm,
- const SkM44& original_ctm) {
- auto* op = static_cast<const ClipRRectOp*>(base_op);
- PaintOpWriter helper(memory, size, options);
- helper.Write(op->rrect);
- helper.Write(op->op);
- helper.Write(op->antialias);
- return helper.size();
-}
-
-size_t ConcatOp::Serialize(const PaintOp* base_op,
- void* memory,
- size_t size,
- const SerializeOptions& options,
- const PaintFlags* flags_to_serialize,
- const SkM44& current_ctm,
- const SkM44& original_ctm) {
- auto* op = static_cast<const ConcatOp*>(base_op);
- PaintOpWriter helper(memory, size, options);
- helper.Write(op->matrix);
- return helper.size();
-}
-
-size_t CustomDataOp::Serialize(const PaintOp* base_op,
- void* memory,
- size_t size,
- const SerializeOptions& options,
- const PaintFlags* flags_to_serialize,
- const SkM44& current_ctm,
- const SkM44& original_ctm) {
- auto* op = static_cast<const CustomDataOp*>(base_op);
- PaintOpWriter helper(memory, size, options);
- helper.Write(op->id);
- return helper.size();
-}
-
-size_t DrawColorOp::Serialize(const PaintOp* base_op,
- void* memory,
- size_t size,
- const SerializeOptions& options,
- const PaintFlags* flags_to_serialize,
- const SkM44& current_ctm,
- const SkM44& original_ctm) {
- auto* op = static_cast<const DrawColorOp*>(base_op);
- PaintOpWriter helper(memory, size, options);
- helper.Write(op->color);
- helper.Write(op->mode);
- return helper.size();
-}
-
-size_t DrawDRRectOp::Serialize(const PaintOp* base_op,
- void* memory,
- size_t size,
- const SerializeOptions& options,
- const PaintFlags* flags_to_serialize,
- const SkM44& current_ctm,
- const SkM44& original_ctm) {
- auto* op = static_cast<const DrawDRRectOp*>(base_op);
- PaintOpWriter helper(memory, size, options);
- if (!flags_to_serialize)
- flags_to_serialize = &op->flags;
- helper.Write(*flags_to_serialize, current_ctm);
- helper.Write(op->outer);
- helper.Write(op->inner);
- return helper.size();
-}
-
-size_t DrawImageOp::Serialize(const PaintOp* base_op,
- void* memory,
- size_t size,
- const SerializeOptions& options,
- const PaintFlags* flags_to_serialize,
- const SkM44& current_ctm,
- const SkM44& original_ctm) {
- auto* op = static_cast<const DrawImageOp*>(base_op);
- PaintOpWriter helper(memory, size, options);
- if (!flags_to_serialize)
- flags_to_serialize = &op->flags;
- helper.Write(*flags_to_serialize, current_ctm);
-
- SkSize scale_adjustment = SkSize::Make(1.f, 1.f);
- helper.Write(
- CreateDrawImage(op->image, flags_to_serialize, op->sampling, current_ctm),
- &scale_adjustment);
- helper.AssertAlignment(alignof(SkScalar));
- helper.Write(scale_adjustment.width());
- helper.Write(scale_adjustment.height());
-
- helper.Write(op->left);
- helper.Write(op->top);
- helper.Write(op->sampling);
- return helper.size();
-}
-
-size_t DrawImageRectOp::Serialize(const PaintOp* base_op,
- void* memory,
- size_t size,
- const SerializeOptions& options,
- const PaintFlags* flags_to_serialize,
- const SkM44& current_ctm,
- const SkM44& original_ctm) {
- auto* op = static_cast<const DrawImageRectOp*>(base_op);
- PaintOpWriter helper(memory, size, options);
- if (!flags_to_serialize)
- flags_to_serialize = &op->flags;
- helper.Write(*flags_to_serialize, current_ctm);
-
- // This adjustment mirrors DiscardableImageMap::GatherDiscardableImage logic.
- SkM44 matrix = current_ctm * SkM44(SkMatrix::RectToRect(op->src, op->dst));
- // 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, flags_to_serialize, op->sampling, matrix),
- &scale_adjustment);
- helper.AssertAlignment(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();
-}
-
-size_t DrawIRectOp::Serialize(const PaintOp* base_op,
- void* memory,
- size_t size,
- const SerializeOptions& options,
- const PaintFlags* flags_to_serialize,
- const SkM44& current_ctm,
- const SkM44& original_ctm) {
- auto* op = static_cast<const DrawIRectOp*>(base_op);
- PaintOpWriter helper(memory, size, options);
- if (!flags_to_serialize)
- flags_to_serialize = &op->flags;
- helper.Write(*flags_to_serialize, current_ctm);
- helper.Write(op->rect);
- return helper.size();
-}
-
-size_t DrawLineOp::Serialize(const PaintOp* base_op,
- void* memory,
- size_t size,
- const SerializeOptions& options,
- const PaintFlags* flags_to_serialize,
- const SkM44& current_ctm,
- const SkM44& original_ctm) {
- auto* op = static_cast<const DrawLineOp*>(base_op);
- PaintOpWriter helper(memory, size, options);
- if (!flags_to_serialize)
- flags_to_serialize = &op->flags;
- helper.Write(*flags_to_serialize, current_ctm);
- helper.AssertAlignment(alignof(SkScalar));
- helper.Write(op->x0);
- helper.Write(op->y0);
- helper.Write(op->x1);
- helper.Write(op->y1);
- return helper.size();
-}
-
-size_t DrawOvalOp::Serialize(const PaintOp* base_op,
- void* memory,
- size_t size,
- const SerializeOptions& options,
- const PaintFlags* flags_to_serialize,
- const SkM44& current_ctm,
- const SkM44& original_ctm) {
- auto* op = static_cast<const DrawOvalOp*>(base_op);
- PaintOpWriter helper(memory, size, options);
- if (!flags_to_serialize)
- flags_to_serialize = &op->flags;
- helper.Write(*flags_to_serialize, current_ctm);
- helper.Write(op->oval);
- return helper.size();
-}
-
-size_t DrawPathOp::Serialize(const PaintOp* base_op,
- void* memory,
- size_t size,
- const SerializeOptions& options,
- const PaintFlags* flags_to_serialize,
- const SkM44& current_ctm,
- const SkM44& original_ctm) {
- auto* op = static_cast<const DrawPathOp*>(base_op);
- PaintOpWriter helper(memory, size, options);
- if (!flags_to_serialize)
- flags_to_serialize = &op->flags;
- helper.Write(*flags_to_serialize, current_ctm);
- helper.Write(op->path, op->use_cache);
- helper.Write(op->sk_path_fill_type);
- return helper.size();
-}
-
-size_t DrawRecordOp::Serialize(const PaintOp* op,
- void* memory,
- size_t size,
- const SerializeOptions& options,
- const PaintFlags* flags_to_serialize,
- const SkM44& current_ctm,
- const SkM44& original_ctm) {
- // TODO(enne): these must be flattened. Serializing this will not do
- // anything.
- NOTREACHED();
- return 0u;
-}
-
-size_t DrawRectOp::Serialize(const PaintOp* base_op,
- void* memory,
- size_t size,
- const SerializeOptions& options,
- const PaintFlags* flags_to_serialize,
- const SkM44& current_ctm,
- const SkM44& original_ctm) {
- auto* op = static_cast<const DrawRectOp*>(base_op);
- PaintOpWriter helper(memory, size, options);
- if (!flags_to_serialize)
- flags_to_serialize = &op->flags;
- helper.Write(*flags_to_serialize, current_ctm);
- helper.Write(op->rect);
- return helper.size();
-}
-
-size_t DrawRRectOp::Serialize(const PaintOp* base_op,
- void* memory,
- size_t size,
- const SerializeOptions& options,
- const PaintFlags* flags_to_serialize,
- const SkM44& current_ctm,
- const SkM44& original_ctm) {
- auto* op = static_cast<const DrawRRectOp*>(base_op);
- PaintOpWriter helper(memory, size, options);
- if (!flags_to_serialize)
- flags_to_serialize = &op->flags;
- helper.Write(*flags_to_serialize, current_ctm);
- helper.Write(op->rrect);
- return helper.size();
-}
-
-namespace {
-
-template <typename T>
-void SerializeSkottieMap(
- const base::flat_map<SkottieResourceIdHash, T>& map,
- PaintOpWriter& helper,
- const base::RepeatingCallback<void(const T&, PaintOpWriter&)>&
- value_serializer) {
- // Write the size of the map first so that we know how many entries to read
- // from the buffer during deserialization.
- helper.WriteSize(map.size());
- for (const auto& [resource_id, val] : map) {
- helper.WriteSize(resource_id.GetUnsafeValue());
- value_serializer.Run(val, helper);
- }
-}
-
-void SerializeSkottieFrameData(const SkM44& current_ctm,
- const SkottieFrameData& frame_data,
- PaintOpWriter& helper) {
- // |scale_adjustment| is not ultimately used; Skottie handles image
- // scale adjustment internally when rastering.
- SkSize scale_adjustment = SkSize::MakeEmpty();
- DrawImage draw_image;
- if (frame_data.image) {
- draw_image = DrawImage(
- frame_data.image, /*use_dark_mode=*/false,
- SkIRect::MakeWH(frame_data.image.width(), frame_data.image.height()),
- frame_data.quality, current_ctm);
- }
- helper.Write(draw_image, &scale_adjustment);
- helper.Write(frame_data.quality);
-}
-
-} // namespace
-
-size_t DrawSkottieOp::Serialize(const PaintOp* base_op,
- void* memory,
- size_t size,
- const SerializeOptions& options,
- const PaintFlags* flags_to_serialize,
- const SkM44& current_ctm,
- const SkM44& original_ctm) {
- auto* op = static_cast<const DrawSkottieOp*>(base_op);
- PaintOpWriter helper(memory, size, options);
- helper.Write(op->dst);
- helper.Write(SkFloatToScalar(op->t));
- helper.Write(op->skottie);
-
- SkottieFrameDataMap images_to_serialize = op->images;
- SkottieTextPropertyValueMap text_map_to_serialize = op->text_map;
- if (options.skottie_serialization_history) {
- options.skottie_serialization_history->FilterNewSkottieFrameState(
- *op->skottie, images_to_serialize, text_map_to_serialize);
- }
-
- SerializeSkottieMap(
- images_to_serialize, helper,
- base::BindRepeating(&SerializeSkottieFrameData, std::cref(current_ctm)));
- SerializeSkottieMap(
- op->color_map, helper,
- base::BindRepeating([](const SkColor& color, PaintOpWriter& helper) {
- helper.Write(color);
- }));
- SerializeSkottieMap(
- text_map_to_serialize, helper,
- base::BindRepeating([](const SkottieTextPropertyValue& text_property_val,
- PaintOpWriter& helper) {
- helper.WriteSize(text_property_val.text().size());
- // If there is not enough space in the underlying buffer, WriteData()
- // will mark the |helper| as invalid and the buffer will keep growing
- // until a max size is reached (currently 64MB which should be ample for
- // text).
- helper.WriteData(text_property_val.text().size(),
- text_property_val.text().c_str());
- helper.Write(gfx::RectFToSkRect(text_property_val.box()));
- }));
- return helper.size();
-}
-
-size_t DrawTextBlobOp::Serialize(const PaintOp* base_op,
- void* memory,
- size_t size,
- const SerializeOptions& options,
- const PaintFlags* flags_to_serialize,
- const SkM44& current_ctm,
- const SkM44& original_ctm) {
- auto* op = static_cast<const DrawTextBlobOp*>(base_op);
- PaintOpWriter helper(memory, size, options);
- if (!flags_to_serialize)
- flags_to_serialize = &op->flags;
- helper.Write(*flags_to_serialize, current_ctm);
- unsigned int count = op->extra_slugs.size() + 1;
- helper.Write(count);
- helper.Write(op->slug);
- for (const auto& slug : op->extra_slugs) {
- helper.Write(slug);
- }
- return helper.size();
-}
-
-size_t NoopOp::Serialize(const PaintOp* base_op,
- void* memory,
- size_t size,
- const SerializeOptions& options,
- const PaintFlags* flags_to_serialize,
- const SkM44& current_ctm,
- const SkM44& original_ctm) {
- PaintOpWriter helper(memory, size, options);
- return helper.size();
-}
-
-size_t RestoreOp::Serialize(const PaintOp* base_op,
- void* memory,
- size_t size,
- const SerializeOptions& options,
- const PaintFlags* flags_to_serialize,
- const SkM44& current_ctm,
- const SkM44& original_ctm) {
- PaintOpWriter helper(memory, size, options);
- return helper.size();
-}
-
-size_t RotateOp::Serialize(const PaintOp* base_op,
- void* memory,
- size_t size,
- const SerializeOptions& options,
- const PaintFlags* flags_to_serialize,
- const SkM44& current_ctm,
- const SkM44& original_ctm) {
- auto* op = static_cast<const RotateOp*>(base_op);
- PaintOpWriter helper(memory, size, options);
- helper.Write(op->degrees);
- return helper.size();
-}
-
-size_t SaveOp::Serialize(const PaintOp* base_op,
- void* memory,
- size_t size,
- const SerializeOptions& options,
- const PaintFlags* flags_to_serialize,
- const SkM44& current_ctm,
- const SkM44& original_ctm) {
- PaintOpWriter helper(memory, size, options);
- return helper.size();
-}
-
-size_t SaveLayerOp::Serialize(const PaintOp* base_op,
- void* memory,
- size_t size,
- const SerializeOptions& options,
- const PaintFlags* flags_to_serialize,
- const SkM44& current_ctm,
- const SkM44& original_ctm) {
- auto* op = static_cast<const SaveLayerOp*>(base_op);
- PaintOpWriter helper(memory, size, options);
- if (!flags_to_serialize)
- flags_to_serialize = &op->flags;
- helper.Write(*flags_to_serialize, current_ctm);
- helper.Write(op->bounds);
- return helper.size();
-}
-
-size_t SaveLayerAlphaOp::Serialize(const PaintOp* base_op,
- void* memory,
- size_t size,
- const SerializeOptions& options,
- const PaintFlags* flags_to_serialize,
- const SkM44& current_ctm,
- const SkM44& original_ctm) {
- auto* op = static_cast<const SaveLayerAlphaOp*>(base_op);
- PaintOpWriter helper(memory, size, options);
- helper.Write(op->bounds);
- helper.Write(op->alpha);
- return helper.size();
-}
-
-size_t ScaleOp::Serialize(const PaintOp* base_op,
- void* memory,
- size_t size,
- const SerializeOptions& options,
- const PaintFlags* flags_to_serialize,
- const SkM44& current_ctm,
- const SkM44& original_ctm) {
- auto* op = static_cast<const ScaleOp*>(base_op);
- PaintOpWriter helper(memory, size, options);
- helper.Write(op->sx);
- helper.Write(op->sy);
- return helper.size();
-}
-
-size_t SetMatrixOp::Serialize(const PaintOp* base_op,
- void* memory,
- size_t size,
- const SerializeOptions& options,
- const PaintFlags* flags_to_serialize,
- const SkM44& current_ctm,
- const SkM44& original_ctm) {
- auto* op = static_cast<const SetMatrixOp*>(base_op);
- PaintOpWriter helper(memory, size, options);
- // Use original_ctm here because SetMatrixOp replaces current_ctm
- helper.Write(original_ctm * op->matrix);
- return helper.size();
-}
-
-size_t SetNodeIdOp::Serialize(const PaintOp* base_op,
- void* memory,
- size_t size,
- const SerializeOptions& options,
- const PaintFlags* flags_to_serialize,
- const SkM44& current_ctm,
- const SkM44& original_ctm) {
- auto* op = static_cast<const SetNodeIdOp*>(base_op);
- PaintOpWriter helper(memory, size, options);
- helper.Write(op->node_id);
- return helper.size();
-}
-
-size_t TranslateOp::Serialize(const PaintOp* base_op,
- void* memory,
- size_t size,
- const SerializeOptions& options,
- const PaintFlags* flags_to_serialize,
- const SkM44& current_ctm,
- const SkM44& original_ctm) {
- auto* op = static_cast<const TranslateOp*>(base_op);
- PaintOpWriter helper(memory, size, options);
- helper.Write(op->dx);
- helper.Write(op->dy);
- return helper.size();
-}
-
-template <typename T>
-void UpdateTypeAndSkip(T* op) {
- op->type = static_cast<uint8_t>(T::kType);
- op->skip = PaintOpBuffer::ComputeOpSkip(sizeof(T));
-}
-
-template <typename T>
-class PaintOpDeserializer {
- public:
- static_assert(std::is_convertible<T, PaintOp>::value, "T not a PaintOp.");
-
- explicit PaintOpDeserializer(const volatile void* input,
- size_t input_size,
- const PaintOp::DeserializeOptions& options,
- T* op)
- : reader_(input, input_size, options), op_(op) {
- DCHECK(op_);
- }
- PaintOpDeserializer(const PaintOpDeserializer&) = delete;
- PaintOpDeserializer& operator=(const PaintOpDeserializer&) = delete;
-
- ~PaintOpDeserializer() {
- DCHECK(!op_)
- << "FinalizeOp must be called before PaintOpDeserializer is destroyed. "
- "type="
- << T::kType;
- }
-
- PaintOp* FinalizeOp(bool force_invalid = false) {
- DCHECK(op_) << "PaintOp has already been finalized. type=" << T::kType;
-
- if (force_invalid || !reader_.valid() || !op_->IsValid()) {
- op_->~T();
- op_ = nullptr;
- return nullptr;
- }
-
- UpdateTypeAndSkip(op_.get());
- T* op_snapshot = op_;
- op_ = nullptr;
- return op_snapshot;
- }
-
- PaintOp* InvalidateAndFinalizeOp() {
- return FinalizeOp(/*force_invalid=*/true);
- }
-
- T* operator->() { return op_; }
-
- template <typename... Args>
- void Read(Args&&... args) {
- reader_.Read(std::forward<Args>(args)...);
- }
-
- void ReadData(size_t bytes, void* data) { reader_.ReadData(bytes, data); }
-
- void ReadSize(size_t* size) { reader_.ReadSize(size); }
-
- void AssertAlignment(size_t alignment) { reader_.AssertAlignment(alignment); }
-
- private:
- PaintOpReader reader_;
- raw_ptr<T> op_;
-};
-
-PaintOp* AnnotateOp::Deserialize(const volatile void* input,
- size_t input_size,
- void* output,
- size_t output_size,
- const DeserializeOptions& options) {
- DCHECK_GE(output_size, sizeof(AnnotateOp));
- PaintOpDeserializer<AnnotateOp> deserializer(input, input_size, options,
- new (output) AnnotateOp);
-
- deserializer.Read(&deserializer->annotation_type);
- deserializer.Read(&deserializer->rect);
- deserializer.Read(&deserializer->data);
- return deserializer.FinalizeOp();
-}
-
-PaintOp* ClipPathOp::Deserialize(const volatile void* input,
- size_t input_size,
- void* output,
- size_t output_size,
- const DeserializeOptions& options) {
- DCHECK_GE(output_size, sizeof(ClipPathOp));
- PaintOpDeserializer<ClipPathOp> deserializer(input, input_size, options,
- new (output) ClipPathOp);
-
- deserializer.Read(&deserializer->path);
- deserializer.Read(&deserializer->op);
- deserializer.Read(&deserializer->antialias);
- return deserializer.FinalizeOp();
-}
-
-PaintOp* ClipRectOp::Deserialize(const volatile void* input,
- size_t input_size,
- void* output,
- size_t output_size,
- const DeserializeOptions& options) {
- DCHECK_GE(output_size, sizeof(ClipRectOp));
- PaintOpDeserializer<ClipRectOp> deserializer(input, input_size, options,
- new (output) ClipRectOp);
- deserializer.Read(&deserializer->rect);
- deserializer.Read(&deserializer->op);
- deserializer.Read(&deserializer->antialias);
- return deserializer.FinalizeOp();
-}
-
-PaintOp* ClipRRectOp::Deserialize(const volatile void* input,
- size_t input_size,
- void* output,
- size_t output_size,
- const DeserializeOptions& options) {
- DCHECK_GE(output_size, sizeof(ClipRRectOp));
- PaintOpDeserializer<ClipRRectOp> deserializer(input, input_size, options,
- new (output) ClipRRectOp);
- deserializer.Read(&deserializer->rrect);
- deserializer.Read(&deserializer->op);
- deserializer.Read(&deserializer->antialias);
- return deserializer.FinalizeOp();
-}
-
-PaintOp* ConcatOp::Deserialize(const volatile void* input,
- size_t input_size,
- void* output,
- size_t output_size,
- const DeserializeOptions& options) {
- DCHECK_GE(output_size, sizeof(ConcatOp));
- PaintOpDeserializer<ConcatOp> deserializer(input, input_size, options,
- new (output) ConcatOp);
- deserializer.Read(&deserializer->matrix);
- return deserializer.FinalizeOp();
-}
-
-PaintOp* CustomDataOp::Deserialize(const volatile void* input,
- size_t input_size,
- void* output,
- size_t output_size,
- const DeserializeOptions& options) {
- DCHECK_GE(output_size, sizeof(CustomDataOp));
- PaintOpDeserializer<CustomDataOp> deserializer(input, input_size, options,
- new (output) CustomDataOp);
- deserializer.Read(&deserializer->id);
- return deserializer.FinalizeOp();
-}
-
-PaintOp* DrawColorOp::Deserialize(const volatile void* input,
- size_t input_size,
- void* output,
- size_t output_size,
- const DeserializeOptions& options) {
- DCHECK_GE(output_size, sizeof(DrawColorOp));
- PaintOpDeserializer<DrawColorOp> deserializer(input, input_size, options,
- new (output) DrawColorOp);
- deserializer.Read(&deserializer->color);
- deserializer.Read(&deserializer->mode);
- return deserializer.FinalizeOp();
-}
-
-PaintOp* DrawDRRectOp::Deserialize(const volatile void* input,
- size_t input_size,
- void* output,
- size_t output_size,
- const DeserializeOptions& options) {
- DCHECK_GE(output_size, sizeof(DrawDRRectOp));
- PaintOpDeserializer<DrawDRRectOp> deserializer(input, input_size, options,
- new (output) DrawDRRectOp);
- deserializer.Read(&deserializer->flags);
- deserializer.Read(&deserializer->outer);
- deserializer.Read(&deserializer->inner);
- return deserializer.FinalizeOp();
-}
-
-PaintOp* DrawImageOp::Deserialize(const volatile void* input,
- size_t input_size,
- void* output,
- size_t output_size,
- const DeserializeOptions& options) {
- DCHECK_GE(output_size, sizeof(DrawImageOp));
- PaintOpDeserializer<DrawImageOp> deserializer(input, input_size, options,
- new (output) DrawImageOp);
- deserializer.Read(&deserializer->flags);
-
- deserializer.Read(&deserializer->image);
- deserializer.AssertAlignment(alignof(SkScalar));
- deserializer.Read(&deserializer->scale_adjustment.fWidth);
- deserializer.Read(&deserializer->scale_adjustment.fHeight);
-
- deserializer.Read(&deserializer->left);
- deserializer.Read(&deserializer->top);
- deserializer.Read(&deserializer->sampling);
- return deserializer.FinalizeOp();
-}
-
-PaintOp* DrawImageRectOp::Deserialize(const volatile void* input,
- size_t input_size,
- void* output,
- size_t output_size,
- const DeserializeOptions& options) {
- DCHECK_GE(output_size, sizeof(DrawImageRectOp));
- PaintOpDeserializer<DrawImageRectOp> deserializer(
- input, input_size, options, new (output) DrawImageRectOp);
- deserializer.Read(&deserializer->flags);
-
- deserializer.Read(&deserializer->image);
- deserializer.AssertAlignment(alignof(SkScalar));
- deserializer.Read(&deserializer->scale_adjustment.fWidth);
- deserializer.Read(&deserializer->scale_adjustment.fHeight);
-
- deserializer.Read(&deserializer->src);
- deserializer.Read(&deserializer->dst);
- deserializer.Read(&deserializer->sampling);
- deserializer.Read(&deserializer->constraint);
- return deserializer.FinalizeOp();
-}
-
-PaintOp* DrawIRectOp::Deserialize(const volatile void* input,
- size_t input_size,
- void* output,
- size_t output_size,
- const DeserializeOptions& options) {
- DCHECK_GE(output_size, sizeof(DrawIRectOp));
- PaintOpDeserializer<DrawIRectOp> deserializer(input, input_size, options,
- new (output) DrawIRectOp);
- deserializer.Read(&deserializer->flags);
- deserializer.Read(&deserializer->rect);
- return deserializer.FinalizeOp();
-}
-
-PaintOp* DrawLineOp::Deserialize(const volatile void* input,
- size_t input_size,
- void* output,
- size_t output_size,
- const DeserializeOptions& options) {
- DCHECK_GE(output_size, sizeof(DrawLineOp));
- PaintOpDeserializer<DrawLineOp> deserializer(input, input_size, options,
- new (output) DrawLineOp);
- deserializer.Read(&deserializer->flags);
- deserializer.AssertAlignment(alignof(SkScalar));
- deserializer.Read(&deserializer->x0);
- deserializer.Read(&deserializer->y0);
- deserializer.Read(&deserializer->x1);
- deserializer.Read(&deserializer->y1);
- return deserializer.FinalizeOp();
-}
-
-PaintOp* DrawOvalOp::Deserialize(const volatile void* input,
- size_t input_size,
- void* output,
- size_t output_size,
- const DeserializeOptions& options) {
- DCHECK_GE(output_size, sizeof(DrawOvalOp));
- PaintOpDeserializer<DrawOvalOp> deserializer(input, input_size, options,
- new (output) DrawOvalOp);
- deserializer.Read(&deserializer->flags);
- deserializer.Read(&deserializer->oval);
- return deserializer.FinalizeOp();
-}
-
-PaintOp* DrawPathOp::Deserialize(const volatile void* input,
- size_t input_size,
- void* output,
- size_t output_size,
- const DeserializeOptions& options) {
- DCHECK_GE(output_size, sizeof(DrawPathOp));
- PaintOpDeserializer<DrawPathOp> deserializer(input, input_size, options,
- new (output) DrawPathOp);
- deserializer.Read(&deserializer->flags);
- deserializer.Read(&deserializer->path);
- deserializer.Read(&deserializer->sk_path_fill_type);
- deserializer->path.setFillType(
- static_cast<SkPathFillType>(deserializer->sk_path_fill_type));
- return deserializer.FinalizeOp();
-}
-
-PaintOp* DrawRecordOp::Deserialize(const volatile void* input,
- size_t input_size,
- void* output,
- size_t output_size,
- const DeserializeOptions& options) {
- // TODO(enne): these must be flattened and not sent directly.
- // TODO(enne): could also consider caching these service side.
- return nullptr;
-}
-
-PaintOp* DrawRectOp::Deserialize(const volatile void* input,
- size_t input_size,
- void* output,
- size_t output_size,
- const DeserializeOptions& options) {
- DCHECK_GE(output_size, sizeof(DrawRectOp));
- PaintOpDeserializer<DrawRectOp> deserializer(input, input_size, options,
- new (output) DrawRectOp);
- deserializer.Read(&deserializer->flags);
- deserializer.Read(&deserializer->rect);
- return deserializer.FinalizeOp();
-}
-
-PaintOp* DrawRRectOp::Deserialize(const volatile void* input,
- size_t input_size,
- void* output,
- size_t output_size,
- const DeserializeOptions& options) {
- DCHECK_GE(output_size, sizeof(DrawRRectOp));
- PaintOpDeserializer<DrawRRectOp> deserializer(input, input_size, options,
- new (output) DrawRRectOp);
- deserializer.Read(&deserializer->flags);
- deserializer.Read(&deserializer->rrect);
- return deserializer.FinalizeOp();
-}
-
-namespace {
-
-// |max_map_size| is purely a safety mechanism to prevent disastrous behavior
-// (trying to allocate an enormous map, looping for long periods of time, etc)
-// in case the serialization buffer is corrupted somehow.
-template <typename T>
-bool DeserializeSkottieMap(
- base::flat_map<SkottieResourceIdHash, T>& map,
- absl::optional<size_t> max_map_size,
- PaintOpDeserializer<DrawSkottieOp>& deserializer,
- const base::RepeatingCallback<absl::optional<T>(
- PaintOpDeserializer<DrawSkottieOp>&)>& value_deserializer) {
- size_t map_size = 0;
- deserializer.ReadSize(&map_size);
- if (max_map_size && map_size > *max_map_size)
- return false;
-
- for (size_t i = 0; i < map_size; ++i) {
- size_t resource_id_hash_raw = 0;
- deserializer.ReadSize(&resource_id_hash_raw);
- SkottieResourceIdHash resource_id_hash =
- SkottieResourceIdHash::FromUnsafeValue(resource_id_hash_raw);
- if (!resource_id_hash)
- return false;
-
- absl::optional<T> value = value_deserializer.Run(deserializer);
- if (!value)
- return false;
-
- // Duplicate keys should not happen by design, but defend against it
- // gracefully in case the underlying buffer is corrupted.
- bool is_new_entry = map.emplace(resource_id_hash, std::move(*value)).second;
- if (!is_new_entry)
- return false;
- }
- return true;
-}
-
-absl::optional<SkottieFrameData> DeserializeSkottieFrameData(
- PaintOpDeserializer<DrawSkottieOp>& deserializer) {
- SkottieFrameData frame_data;
- deserializer.Read(&frame_data.image);
- deserializer.Read(&frame_data.quality);
- return frame_data;
-}
-
-absl::optional<SkColor> DeserializeSkottieColor(
- PaintOpDeserializer<DrawSkottieOp>& deserializer) {
- SkColor color = SK_ColorTRANSPARENT;
- deserializer.Read(&color);
- return color;
-}
-
-absl::optional<SkottieTextPropertyValue> DeserializeSkottieTextPropertyValue(
- PaintOpDeserializer<DrawSkottieOp>& deserializer) {
- size_t text_size = 0u;
- deserializer.ReadSize(&text_size);
- std::string text(text_size, char());
- deserializer.ReadData(text_size, const_cast<char*>(text.c_str()));
- SkRect box;
- deserializer.Read(&box);
- return SkottieTextPropertyValue(std::move(text), gfx::SkRectToRectF(box));
-}
-
-} // namespace
-
-PaintOp* DrawSkottieOp::Deserialize(const volatile void* input,
- size_t input_size,
- void* output,
- size_t output_size,
- const DeserializeOptions& options) {
- DCHECK_GE(output_size, sizeof(DrawSkottieOp));
- PaintOpDeserializer<DrawSkottieOp> deserializer(input, input_size, options,
- new (output) DrawSkottieOp);
- deserializer.Read(&deserializer->dst);
-
- SkScalar t;
- deserializer.Read(&t);
- deserializer->t = SkScalarToFloat(t);
-
- deserializer.Read(&deserializer->skottie);
- // The |skottie| object gets used below, so no point in continuing if it's
- // invalid. That can lead to crashing or unexpected behavior.
- if (!deserializer->skottie || !deserializer->skottie->is_valid())
- return deserializer.InvalidateAndFinalizeOp();
-
- size_t num_assets_in_animation =
- deserializer->skottie->GetImageAssetMetadata().asset_storage().size();
- size_t num_text_nodes_in_animation =
- deserializer->skottie->GetTextNodeNames().size();
- bool deserialized_all_maps =
- DeserializeSkottieMap(
- deserializer->images, /*max_map_size=*/num_assets_in_animation,
- deserializer, base::BindRepeating(&DeserializeSkottieFrameData)) &&
- DeserializeSkottieMap(deserializer->color_map,
- /*max_map_size=*/absl::nullopt, deserializer,
- base::BindRepeating(&DeserializeSkottieColor)) &&
- DeserializeSkottieMap(
- deserializer->text_map, /*max_map_size=*/num_text_nodes_in_animation,
- deserializer,
- base::BindRepeating(&DeserializeSkottieTextPropertyValue));
- return deserialized_all_maps ? deserializer.FinalizeOp()
- : deserializer.InvalidateAndFinalizeOp();
-}
-
-PaintOp* DrawTextBlobOp::Deserialize(const volatile void* input,
- size_t input_size,
- void* output,
- size_t output_size,
- const DeserializeOptions& options) {
- DCHECK_GE(output_size, sizeof(DrawTextBlobOp));
- PaintOpDeserializer<DrawTextBlobOp> deserializer(input, input_size, options,
- new (output) DrawTextBlobOp);
- deserializer.Read(&deserializer->flags);
- unsigned int count = 0;
- deserializer.Read(&count);
- deserializer.Read(&deserializer->slug);
- deserializer->extra_slugs.resize(count - 1);
- for (auto& slug : deserializer->extra_slugs) {
- deserializer.Read(&slug);
- }
- return deserializer.FinalizeOp();
-}
-
-PaintOp* NoopOp::Deserialize(const volatile void* input,
- size_t input_size,
- void* output,
- size_t output_size,
- const DeserializeOptions& options) {
- DCHECK_GE(output_size, sizeof(NoopOp));
- PaintOpDeserializer<NoopOp> deserializer(input, input_size, options,
- new (output) NoopOp);
- return deserializer.FinalizeOp();
-}
-
-PaintOp* RestoreOp::Deserialize(const volatile void* input,
- size_t input_size,
- void* output,
- size_t output_size,
- const DeserializeOptions& options) {
- DCHECK_GE(output_size, sizeof(RestoreOp));
- PaintOpDeserializer<RestoreOp> deserializer(input, input_size, options,
- new (output) RestoreOp);
- return deserializer.FinalizeOp();
-}
-
-PaintOp* RotateOp::Deserialize(const volatile void* input,
- size_t input_size,
- void* output,
- size_t output_size,
- const DeserializeOptions& options) {
- DCHECK_GE(output_size, sizeof(RotateOp));
- PaintOpDeserializer<RotateOp> deserializer(input, input_size, options,
- new (output) RotateOp);
- deserializer.Read(&deserializer->degrees);
- return deserializer.FinalizeOp();
-}
-
-PaintOp* SaveOp::Deserialize(const volatile void* input,
- size_t input_size,
- void* output,
- size_t output_size,
- const DeserializeOptions& options) {
- DCHECK_GE(output_size, sizeof(SaveOp));
- PaintOpDeserializer<SaveOp> deserializer(input, input_size, options,
- new (output) SaveOp);
- return deserializer.FinalizeOp();
-}
-
-PaintOp* SaveLayerOp::Deserialize(const volatile void* input,
- size_t input_size,
- void* output,
- size_t output_size,
- const DeserializeOptions& options) {
- DCHECK_GE(output_size, sizeof(SaveLayerOp));
- PaintOpDeserializer<SaveLayerOp> deserializer(input, input_size, options,
- new (output) SaveLayerOp);
- deserializer.Read(&deserializer->flags);
- deserializer.Read(&deserializer->bounds);
- return deserializer.FinalizeOp();
-}
-
-PaintOp* SaveLayerAlphaOp::Deserialize(const volatile void* input,
- size_t input_size,
- void* output,
- size_t output_size,
- const DeserializeOptions& options) {
- DCHECK_GE(output_size, sizeof(SaveLayerAlphaOp));
- PaintOpDeserializer<SaveLayerAlphaOp> deserializer(
- input, input_size, options, new (output) SaveLayerAlphaOp);
- deserializer.Read(&deserializer->bounds);
- deserializer.Read(&deserializer->alpha);
- return deserializer.FinalizeOp();
-}
-
-PaintOp* ScaleOp::Deserialize(const volatile void* input,
- size_t input_size,
- void* output,
- size_t output_size,
- const DeserializeOptions& options) {
- DCHECK_GE(output_size, sizeof(ScaleOp));
- PaintOpDeserializer<ScaleOp> deserializer(input, input_size, options,
- new (output) ScaleOp);
- deserializer.Read(&deserializer->sx);
- deserializer.Read(&deserializer->sy);
- return deserializer.FinalizeOp();
-}
-
-PaintOp* SetMatrixOp::Deserialize(const volatile void* input,
- size_t input_size,
- void* output,
- size_t output_size,
- const DeserializeOptions& options) {
- DCHECK_GE(output_size, sizeof(SetMatrixOp));
- PaintOpDeserializer<SetMatrixOp> deserializer(input, input_size, options,
- new (output) SetMatrixOp);
- deserializer.Read(&deserializer->matrix);
- return deserializer.FinalizeOp();
-}
-
-PaintOp* SetNodeIdOp::Deserialize(const volatile void* input,
- size_t input_size,
- void* output,
- size_t output_size,
- const DeserializeOptions& options) {
- DCHECK_GE(output_size, sizeof(SetNodeIdOp));
- PaintOpDeserializer<SetNodeIdOp> deserializer(input, input_size, options,
- new (output) SetNodeIdOp);
- deserializer.Read(&deserializer->node_id);
- return deserializer.FinalizeOp();
-}
-
-PaintOp* TranslateOp::Deserialize(const volatile void* input,
- size_t input_size,
- void* output,
- size_t output_size,
- const DeserializeOptions& options) {
- DCHECK_GE(output_size, sizeof(TranslateOp));
- PaintOpDeserializer<TranslateOp> deserializer(input, input_size, options,
- new (output) TranslateOp);
- deserializer.Read(&deserializer->dx);
- deserializer.Read(&deserializer->dy);
- return deserializer.FinalizeOp();
-}
-
-void AnnotateOp::Raster(const AnnotateOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params) {
- switch (op->annotation_type) {
- case PaintCanvas::AnnotationType::URL:
- SkAnnotateRectWithURL(canvas, op->rect, op->data.get());
- break;
- case PaintCanvas::AnnotationType::LINK_TO_DESTINATION:
- SkAnnotateLinkToDestination(canvas, op->rect, op->data.get());
- break;
- case PaintCanvas::AnnotationType::NAMED_DESTINATION: {
- SkPoint point = SkPoint::Make(op->rect.x(), op->rect.y());
- SkAnnotateNamedDestination(canvas, point, op->data.get());
- break;
- }
- }
-}
-
-void ClipPathOp::Raster(const ClipPathOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params) {
- canvas->clipPath(op->path, op->op, op->antialias);
-}
-
-void ClipRectOp::Raster(const ClipRectOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params) {
- canvas->clipRect(op->rect, op->op, op->antialias);
-}
-
-void ClipRRectOp::Raster(const ClipRRectOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params) {
- canvas->clipRRect(op->rrect, op->op, op->antialias);
-}
-
-void ConcatOp::Raster(const ConcatOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params) {
- canvas->concat(op->matrix);
-}
-
-void CustomDataOp::Raster(const CustomDataOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params) {
- if (params.custom_callback)
- params.custom_callback.Run(canvas, op->id);
-}
-
-void DrawColorOp::Raster(const DrawColorOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params) {
- canvas->drawColor(op->color, op->mode);
-}
-
-void DrawDRRectOp::RasterWithFlags(const DrawDRRectOp* op,
- const PaintFlags* flags,
- SkCanvas* canvas,
- const PlaybackParams& params) {
- flags->DrawToSk(canvas, [op](SkCanvas* c, const SkPaint& p) {
- c->drawDRRect(op->outer, op->inner, p);
- });
-}
-
-void DrawImageOp::RasterWithFlags(const DrawImageOp* op,
- const PaintFlags* flags,
- SkCanvas* canvas,
- const PlaybackParams& params) {
- DCHECK(!op->image.IsPaintWorklet());
- SkPaint paint = flags ? flags->ToSkPaint() : SkPaint();
-
- if (!params.image_provider) {
- const bool needs_scale = !IsScaleAdjustmentIdentity(op->scale_adjustment);
- SkAutoCanvasRestore save_restore(canvas, needs_scale);
- if (needs_scale) {
- canvas->scale(1.f / op->scale_adjustment.width(),
- 1.f / op->scale_adjustment.height());
- }
- 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()),
- sampling_to_quality(op->sampling), canvas->getLocalToDevice());
- auto scoped_result = params.image_provider->GetRasterContent(draw_image);
- if (!scoped_result)
- return;
-
- const auto& decoded_image = scoped_result.decoded_image();
- DCHECK(decoded_image.image());
-
- DCHECK_EQ(0, static_cast<int>(decoded_image.src_rect_offset().width()));
- DCHECK_EQ(0, static_cast<int>(decoded_image.src_rect_offset().height()));
- SkSize scale_adjustment = SkSize::Make(
- op->scale_adjustment.width() * decoded_image.scale_adjustment().width(),
- op->scale_adjustment.height() *
- decoded_image.scale_adjustment().height());
- const bool needs_scale = !IsScaleAdjustmentIdentity(scale_adjustment);
- SkAutoCanvasRestore save_restore(canvas, needs_scale);
- if (needs_scale) {
- canvas->scale(1.f / scale_adjustment.width(),
- 1.f / scale_adjustment.height());
- }
- canvas->drawImage(decoded_image.image().get(), op->left, op->top,
- PaintFlags::FilterQualityToSkSamplingOptions(
- decoded_image.filter_quality()),
- &paint);
-}
-
-void DrawImageRectOp::RasterWithFlags(const DrawImageRectOp* op,
- const PaintFlags* flags,
- SkCanvas* canvas,
- const PlaybackParams& params) {
- // TODO(crbug.com/931704): make sure to support the case where paint worklet
- // generated images are used in other raster work such as canvas2d.
- if (op->image.IsPaintWorklet()) {
- // When rasterizing on the main thread (e.g. paint invalidation checking,
- // see https://crbug.com/990382), an image provider may not be available, so
- // we should draw nothing.
- if (!params.image_provider)
- return;
- ImageProvider::ScopedResult result =
- params.image_provider->GetRasterContent(DrawImage(op->image));
-
- // Check that we are not using loopers with paint worklets, since converting
- // PaintFlags to SkPaint drops loopers.
- DCHECK(!flags->getLooper());
- SkPaint paint = flags ? flags->ToSkPaint() : SkPaint();
-
- DCHECK(IsScaleAdjustmentIdentity(op->scale_adjustment));
- SkAutoCanvasRestore save_restore(canvas, true);
- 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
- // to the worklet thread even after main has torn down the worklet (e.g.
- // because a navigation is happening). In that case the PaintWorklet jobs
- // will fail and there will be no result to raster here. This state is
- // transient as the next main frame commit will remove the PaintWorklets.
- if (result && result.paint_record())
- result.paint_record()->Playback(canvas, params);
- return;
- }
-
- if (!params.image_provider) {
- SkRect adjusted_src = AdjustSrcRectForScale(op->src, op->scale_adjustment);
- flags->DrawToSk(canvas, [op, adjusted_src](SkCanvas* c, const SkPaint& 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();
- DrawImageRect(c, sk_image.get(), adjusted_src, op->dst, op->sampling, &p,
- op->constraint);
- });
- return;
- }
-
- SkM44 matrix = canvas->getLocalToDevice() *
- SkM44(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,
- sampling_to_quality(op->sampling), matrix);
- auto scoped_result = params.image_provider->GetRasterContent(draw_image);
- if (!scoped_result)
- return;
-
- const auto& decoded_image = scoped_result.decoded_image();
- DCHECK(decoded_image.image());
-
- SkSize scale_adjustment = SkSize::Make(
- op->scale_adjustment.width() * decoded_image.scale_adjustment().width(),
- op->scale_adjustment.height() *
- decoded_image.scale_adjustment().height());
- SkRect adjusted_src =
- op->src.makeOffset(decoded_image.src_rect_offset().width(),
- decoded_image.src_rect_offset().height());
- adjusted_src = AdjustSrcRectForScale(adjusted_src, scale_adjustment);
- flags->DrawToSk(canvas, [op, &decoded_image, adjusted_src](SkCanvas* c,
- const SkPaint& p) {
- SkSamplingOptions options = PaintFlags::FilterQualityToSkSamplingOptions(
- decoded_image.filter_quality());
- DrawImageRect(c, decoded_image.image().get(), adjusted_src, op->dst,
- options, &p, op->constraint);
- });
-}
-
-void DrawIRectOp::RasterWithFlags(const DrawIRectOp* op,
- const PaintFlags* flags,
- SkCanvas* canvas,
- const PlaybackParams& params) {
- flags->DrawToSk(canvas, [op](SkCanvas* c, const SkPaint& p) {
- c->drawIRect(op->rect, p);
- });
-}
-
-void DrawLineOp::RasterWithFlags(const DrawLineOp* op,
- const PaintFlags* flags,
- SkCanvas* canvas,
- const PlaybackParams& params) {
- SkPaint paint = flags->ToSkPaint();
- flags->DrawToSk(canvas, [op](SkCanvas* c, const SkPaint& p) {
- c->drawLine(op->x0, op->y0, op->x1, op->y1, p);
- });
-}
-
-void DrawOvalOp::RasterWithFlags(const DrawOvalOp* op,
- const PaintFlags* flags,
- SkCanvas* canvas,
- const PlaybackParams& params) {
- flags->DrawToSk(canvas, [op](SkCanvas* c, const SkPaint& p) {
- c->drawOval(op->oval, p);
- });
-}
-
-void DrawPathOp::RasterWithFlags(const DrawPathOp* op,
- const PaintFlags* flags,
- SkCanvas* canvas,
- const PlaybackParams& params) {
- flags->DrawToSk(canvas, [op](SkCanvas* c, const SkPaint& p) {
- c->drawPath(op->path, p);
- });
-}
-
-void DrawRecordOp::Raster(const DrawRecordOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params) {
- // Don't use drawPicture here, as it adds an implicit clip.
- // TODO(enne): Temporary CHECK debugging for http://crbug.com/823835
- CHECK(op->record);
- op->record->Playback(canvas, params);
-}
-
-void DrawRectOp::RasterWithFlags(const DrawRectOp* op,
- const PaintFlags* flags,
- SkCanvas* canvas,
- const PlaybackParams& params) {
- flags->DrawToSk(canvas, [op](SkCanvas* c, const SkPaint& p) {
- c->drawRect(op->rect, p);
- });
-}
-
-void DrawRRectOp::RasterWithFlags(const DrawRRectOp* op,
- const PaintFlags* flags,
- SkCanvas* canvas,
- const PlaybackParams& params) {
- flags->DrawToSk(canvas, [op](SkCanvas* c, const SkPaint& p) {
- c->drawRRect(op->rrect, p);
- });
-}
-
-void DrawSkottieOp::Raster(const DrawSkottieOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params) {
- // Binding unretained references in the callback is safe because Draw()'s API
- // guarantees that the callback is invoked synchronously.
- op->skottie->Draw(
- canvas, op->t, op->dst,
- base::BindRepeating(&DrawSkottieOp::GetImageAssetForRaster,
- base::Unretained(op), canvas, std::cref(params)),
- op->color_map, op->text_map);
-}
-
-SkottieWrapper::FrameDataFetchResult DrawSkottieOp::GetImageAssetForRaster(
- SkCanvas* canvas,
- const PlaybackParams& params,
- SkottieResourceIdHash asset_id,
- float t_frame,
- sk_sp<SkImage>& sk_image,
- SkSamplingOptions& sampling_out) const {
- auto images_iter = images.find(asset_id);
- if (images_iter == images.end())
- return SkottieWrapper::FrameDataFetchResult::NO_UPDATE;
-
- const SkottieFrameData& frame_data = images_iter->second;
- if (!frame_data.image) {
- sk_image = nullptr;
- } else if (params.image_provider) {
- // There is no use case for applying dark mode filters to skottie images
- // currently.
- DrawImage draw_image(
- frame_data.image, /*use_dark_mode=*/false,
- SkIRect::MakeWH(frame_data.image.width(), frame_data.image.height()),
- frame_data.quality, canvas->getLocalToDevice());
- auto scoped_result = params.image_provider->GetRasterContent(draw_image);
- if (scoped_result) {
- sk_image = scoped_result.decoded_image().image();
- DCHECK(sk_image);
- }
- } else {
- if (frame_data.image.IsTextureBacked()) {
- sk_image = frame_data.image.GetAcceleratedSkImage();
- DCHECK(sk_image || !canvas->recordingContext());
- }
- if (!sk_image)
- sk_image = frame_data.image.GetSwSkImage();
- }
- sampling_out =
- PaintFlags::FilterQualityToSkSamplingOptions(frame_data.quality);
- return SkottieWrapper::FrameDataFetchResult::NEW_DATA_AVAILABLE;
-}
-
-void DrawTextBlobOp::RasterWithFlags(const DrawTextBlobOp* op,
- const PaintFlags* flags,
- SkCanvas* canvas,
- const PlaybackParams& params) {
- if (op->node_id)
- SkPDF::SetNodeId(canvas, op->node_id);
-
- // The PaintOpBuffer could be rasterized with different global matrix. It is
- // used for over scall on Android. So we cannot reuse slugs, they have to be
- // recreated.
- if (params.is_analyzing) {
- const_cast<DrawTextBlobOp*>(op)->slug.reset();
- const_cast<DrawTextBlobOp*>(op)->extra_slugs.clear();
- }
-
- // flags may contain SkDrawLooper for shadow effect, so we need to convert
- // SkTextBlob to slug for each run.
- size_t i = 0;
- flags->DrawToSk(canvas, [op, &params, &i](SkCanvas* c, const SkPaint& p) {
- if (op->blob) {
- c->drawTextBlob(op->blob.get(), op->x, op->y, p);
- if (params.is_analyzing) {
- auto s = GrSlug::ConvertBlob(c, *op->blob, {op->x, op->y}, p);
- if (i == 0) {
- const_cast<DrawTextBlobOp*>(op)->slug = std::move(s);
- } else {
- const_cast<DrawTextBlobOp*>(op)->extra_slugs.push_back(std::move(s));
- }
- }
- } else if (i < 1 + op->extra_slugs.size()) {
- DCHECK(!params.is_analyzing);
- const auto& draw_slug = i == 0 ? op->slug : op->extra_slugs[i - 1];
- if (draw_slug)
- draw_slug->draw(c);
- }
- ++i;
- });
-
- if (op->node_id)
- SkPDF::SetNodeId(canvas, 0);
-}
-
-void RestoreOp::Raster(const RestoreOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params) {
- canvas->restore();
-}
-
-void RotateOp::Raster(const RotateOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params) {
- canvas->rotate(op->degrees);
-}
-
-void SaveOp::Raster(const SaveOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params) {
- canvas->save();
-}
-
-void SaveLayerOp::RasterWithFlags(const SaveLayerOp* op,
- const PaintFlags* flags,
- SkCanvas* canvas,
- const PlaybackParams& params) {
- // See PaintOp::kUnsetRect
- SkPaint paint = flags->ToSkPaint();
- bool unset = op->bounds.left() == SK_ScalarInfinity;
- canvas->saveLayer(unset ? nullptr : &op->bounds, &paint);
-}
-
-void SaveLayerAlphaOp::Raster(const SaveLayerAlphaOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params) {
- // See PaintOp::kUnsetRect
- bool unset = op->bounds.left() == SK_ScalarInfinity;
- absl::optional<SkPaint> paint;
- if (op->alpha != 1.0f) {
- paint.emplace();
- paint->setAlpha(op->alpha * 255.0f);
- }
- SkCanvas::SaveLayerRec rec(unset ? nullptr : &op->bounds,
- base::OptionalToPtr(paint));
- if (params.save_layer_alpha_should_preserve_lcd_text.has_value() &&
- *params.save_layer_alpha_should_preserve_lcd_text) {
- rec.fSaveLayerFlags = SkCanvas::kPreserveLCDText_SaveLayerFlag |
- SkCanvas::kInitWithPrevious_SaveLayerFlag;
- }
- canvas->saveLayer(rec);
-}
-
-void ScaleOp::Raster(const ScaleOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params) {
- canvas->scale(op->sx, op->sy);
-}
-
-void SetMatrixOp::Raster(const SetMatrixOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params) {
- canvas->setMatrix(params.original_ctm * op->matrix);
-}
-
-void SetNodeIdOp::Raster(const SetNodeIdOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params) {
- SkPDF::SetNodeId(canvas, op->node_id);
-}
-
-void TranslateOp::Raster(const TranslateOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params) {
- canvas->translate(op->dx, op->dy);
-}
-
-// static
-bool PaintOp::AreSkPointsEqual(const SkPoint& left, const SkPoint& right) {
- if (!AreEqualEvenIfNaN(left.fX, right.fX))
- return false;
- if (!AreEqualEvenIfNaN(left.fY, right.fY))
- return false;
- return true;
-}
-
-// static
-bool PaintOp::AreSkPoint3sEqual(const SkPoint3& left, const SkPoint3& right) {
- if (!AreEqualEvenIfNaN(left.fX, right.fX))
- return false;
- if (!AreEqualEvenIfNaN(left.fY, right.fY))
- return false;
- if (!AreEqualEvenIfNaN(left.fZ, right.fZ))
- return false;
- return true;
-}
-
-// static
-bool PaintOp::AreSkRectsEqual(const SkRect& left, const SkRect& right) {
- if (!AreEqualEvenIfNaN(left.fLeft, right.fLeft))
- return false;
- if (!AreEqualEvenIfNaN(left.fTop, right.fTop))
- return false;
- if (!AreEqualEvenIfNaN(left.fRight, right.fRight))
- return false;
- if (!AreEqualEvenIfNaN(left.fBottom, right.fBottom))
- return false;
- return true;
-}
-
-// static
-bool PaintOp::AreSkRRectsEqual(const SkRRect& left, const SkRRect& right) {
- char left_buffer[SkRRect::kSizeInMemory];
- left.writeToMemory(left_buffer);
- char right_buffer[SkRRect::kSizeInMemory];
- right.writeToMemory(right_buffer);
- return !memcmp(left_buffer, right_buffer, SkRRect::kSizeInMemory);
-}
-
-// static
-bool PaintOp::AreSkMatricesEqual(const SkMatrix& left, const SkMatrix& right) {
- for (int i = 0; i < 9; ++i) {
- if (!AreEqualEvenIfNaN(left.get(i), right.get(i)))
- return false;
- }
-
- // If a serialized matrix says it is identity, then the original must have
- // those values, as the serialization process clobbers the matrix values.
- if (left.isIdentity()) {
- if (SkMatrix::I() != left)
- return false;
- if (SkMatrix::I() != right)
- return false;
- }
-
- if (left.getType() != right.getType())
- return false;
-
- return true;
-}
-
-// 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)
- return !right && !left;
-
- sk_sp<SkData> left_data = left->serialize();
- sk_sp<SkData> right_data = right->serialize();
- if (left_data->size() != right_data->size())
- return false;
- if (!left_data->equals(right_data.get()))
- return false;
- return true;
-}
-
-bool AnnotateOp::AreEqual(const PaintOp* base_left, const PaintOp* base_right) {
- auto* left = static_cast<const AnnotateOp*>(base_left);
- auto* right = static_cast<const AnnotateOp*>(base_right);
- DCHECK(left->IsValid());
- DCHECK(right->IsValid());
- if (left->annotation_type != right->annotation_type)
- return false;
- if (!AreSkRectsEqual(left->rect, right->rect))
- return false;
- if (!left->data != !right->data)
- return false;
- if (left->data) {
- if (left->data->size() != right->data->size())
- return false;
- if (0 !=
- memcmp(left->data->data(), right->data->data(), right->data->size()))
- return false;
- }
- return true;
-}
-
-bool ClipPathOp::AreEqual(const PaintOp* base_left, const PaintOp* base_right) {
- auto* left = static_cast<const ClipPathOp*>(base_left);
- auto* right = static_cast<const ClipPathOp*>(base_right);
- DCHECK(left->IsValid());
- DCHECK(right->IsValid());
- if (left->path != right->path)
- return false;
- if (left->op != right->op)
- return false;
- if (left->antialias != right->antialias)
- return false;
- return true;
-}
-
-bool ClipRectOp::AreEqual(const PaintOp* base_left, const PaintOp* base_right) {
- auto* left = static_cast<const ClipRectOp*>(base_left);
- auto* right = static_cast<const ClipRectOp*>(base_right);
- DCHECK(left->IsValid());
- DCHECK(right->IsValid());
- if (!AreSkRectsEqual(left->rect, right->rect))
- return false;
- if (left->op != right->op)
- return false;
- if (left->antialias != right->antialias)
- return false;
- return true;
-}
-
-bool ClipRRectOp::AreEqual(const PaintOp* base_left,
- const PaintOp* base_right) {
- auto* left = static_cast<const ClipRRectOp*>(base_left);
- auto* right = static_cast<const ClipRRectOp*>(base_right);
- DCHECK(left->IsValid());
- DCHECK(right->IsValid());
- if (!AreSkRRectsEqual(left->rrect, right->rrect))
- return false;
- if (left->op != right->op)
- return false;
- if (left->antialias != right->antialias)
- return false;
- return true;
-}
-
-bool ConcatOp::AreEqual(const PaintOp* base_left, const PaintOp* base_right) {
- auto* left = static_cast<const ConcatOp*>(base_left);
- auto* right = static_cast<const ConcatOp*>(base_right);
- DCHECK(left->IsValid());
- DCHECK(right->IsValid());
- return AreSkM44sEqual(left->matrix, right->matrix);
-}
-
-bool CustomDataOp::AreEqual(const PaintOp* base_left,
- const PaintOp* base_right) {
- auto* left = static_cast<const CustomDataOp*>(base_left);
- auto* right = static_cast<const CustomDataOp*>(base_right);
- DCHECK(left->IsValid());
- DCHECK(right->IsValid());
- return left->id == right->id;
-}
-
-bool DrawColorOp::AreEqual(const PaintOp* base_left,
- const PaintOp* base_right) {
- auto* left = static_cast<const DrawColorOp*>(base_left);
- auto* right = static_cast<const DrawColorOp*>(base_right);
- DCHECK(left->IsValid());
- DCHECK(right->IsValid());
- return left->color == right->color;
-}
-
-bool DrawDRRectOp::AreEqual(const PaintOp* base_left,
- const PaintOp* base_right) {
- auto* left = static_cast<const DrawDRRectOp*>(base_left);
- auto* right = static_cast<const DrawDRRectOp*>(base_right);
- DCHECK(left->IsValid());
- DCHECK(right->IsValid());
- if (left->flags != right->flags)
- return false;
- if (!AreSkRRectsEqual(left->outer, right->outer))
- return false;
- if (!AreSkRRectsEqual(left->inner, right->inner))
- return false;
- return true;
-}
-
-bool DrawImageOp::AreEqual(const PaintOp* base_left,
- const PaintOp* base_right) {
- auto* left = static_cast<const DrawImageOp*>(base_left);
- auto* right = static_cast<const DrawImageOp*>(base_right);
- DCHECK(left->IsValid());
- DCHECK(right->IsValid());
- if (left->flags != right->flags)
- return false;
- // TODO(enne): Test PaintImage equality once implemented
- if (!AreEqualEvenIfNaN(left->left, right->left))
- return false;
- if (!AreEqualEvenIfNaN(left->top, right->top))
- return false;
-
- // scale_adjustment intentionally omitted because it is added during
- // serialization based on raster scale.
- return true;
-}
-
-bool DrawImageRectOp::AreEqual(const PaintOp* base_left,
- const PaintOp* base_right) {
- auto* left = static_cast<const DrawImageRectOp*>(base_left);
- auto* right = static_cast<const DrawImageRectOp*>(base_right);
- DCHECK(left->IsValid());
- DCHECK(right->IsValid());
- if (left->flags != right->flags)
- return false;
- // TODO(enne): Test PaintImage equality once implemented
- if (!AreSkRectsEqual(left->src, right->src))
- return false;
- if (!AreSkRectsEqual(left->dst, right->dst))
- return false;
-
- // scale_adjustment intentionally omitted because it is added during
- // serialization based on raster scale.
- return true;
-}
-
-bool DrawIRectOp::AreEqual(const PaintOp* base_left,
- const PaintOp* base_right) {
- auto* left = static_cast<const DrawIRectOp*>(base_left);
- auto* right = static_cast<const DrawIRectOp*>(base_right);
- DCHECK(left->IsValid());
- DCHECK(right->IsValid());
- if (left->flags != right->flags)
- return false;
- if (left->rect != right->rect)
- return false;
- return true;
-}
-
-bool DrawLineOp::AreEqual(const PaintOp* base_left, const PaintOp* base_right) {
- auto* left = static_cast<const DrawLineOp*>(base_left);
- auto* right = static_cast<const DrawLineOp*>(base_right);
- DCHECK(left->IsValid());
- DCHECK(right->IsValid());
- if (left->flags != right->flags)
- return false;
- if (!AreEqualEvenIfNaN(left->x0, right->x0))
- return false;
- if (!AreEqualEvenIfNaN(left->y0, right->y0))
- return false;
- if (!AreEqualEvenIfNaN(left->x1, right->x1))
- return false;
- if (!AreEqualEvenIfNaN(left->y1, right->y1))
- return false;
- return true;
-}
-
-bool DrawOvalOp::AreEqual(const PaintOp* base_left, const PaintOp* base_right) {
- auto* left = static_cast<const DrawOvalOp*>(base_left);
- auto* right = static_cast<const DrawOvalOp*>(base_right);
- DCHECK(left->IsValid());
- DCHECK(right->IsValid());
- if (left->flags != right->flags)
- return false;
- if (!AreSkRectsEqual(left->oval, right->oval))
- return false;
- return true;
-}
-
-bool DrawPathOp::AreEqual(const PaintOp* base_left, const PaintOp* base_right) {
- auto* left = static_cast<const DrawPathOp*>(base_left);
- auto* right = static_cast<const DrawPathOp*>(base_right);
- DCHECK(left->IsValid());
- DCHECK(right->IsValid());
- if (left->flags != right->flags)
- return false;
- if (left->path != right->path)
- return false;
- return true;
-}
-
-bool DrawRecordOp::AreEqual(const PaintOp* base_left,
- const PaintOp* base_right) {
- auto* left = static_cast<const DrawRecordOp*>(base_left);
- auto* right = static_cast<const DrawRecordOp*>(base_right);
- DCHECK(left->IsValid());
- DCHECK(right->IsValid());
- if (!left->record != !right->record)
- return false;
- if (*left->record != *right->record)
- return false;
- return true;
-}
-
-bool DrawRectOp::AreEqual(const PaintOp* base_left, const PaintOp* base_right) {
- auto* left = static_cast<const DrawRectOp*>(base_left);
- auto* right = static_cast<const DrawRectOp*>(base_right);
- DCHECK(left->IsValid());
- DCHECK(right->IsValid());
- if (left->flags != right->flags)
- return false;
- if (!AreSkRectsEqual(left->rect, right->rect))
- return false;
- return true;
-}
-
-bool DrawRRectOp::AreEqual(const PaintOp* base_left,
- const PaintOp* base_right) {
- auto* left = static_cast<const DrawRRectOp*>(base_left);
- auto* right = static_cast<const DrawRRectOp*>(base_right);
- DCHECK(left->IsValid());
- DCHECK(right->IsValid());
- if (left->flags != right->flags)
- return false;
- if (!AreSkRRectsEqual(left->rrect, right->rrect))
- return false;
- return true;
-}
-
-bool DrawSkottieOp::AreEqual(const PaintOp* base_left,
- const PaintOp* base_right) {
- auto* left = static_cast<const DrawSkottieOp*>(base_left);
- auto* right = static_cast<const DrawSkottieOp*>(base_right);
- DCHECK(left->IsValid());
- DCHECK(right->IsValid());
- // TODO(malaykeshav): Verify the skottie objects of each PaintOb are equal
- // based on the serialized bytes.
- if (left->t != right->t)
- return false;
- if (!AreSkRectsEqual(left->dst, right->dst))
- return false;
- if (left->images.size() != right->images.size())
- return false;
-
- auto left_iter = left->images.begin();
- auto right_iter = right->images.begin();
- for (; left_iter != left->images.end(); ++left_iter, ++right_iter) {
- if (left_iter->first != right_iter->first ||
- // PaintImage's comparison operator compares the underlying SkImage's
- // pointer address. This does not necessarily hold in cases where the
- // image's content may be the same, but it got realloacted to a
- // different spot somewhere in memory via the transfer cache. The next
- // best thing is to just compare the dimensions of the PaintImage.
- left_iter->second.image.width() != right_iter->second.image.width() ||
- left_iter->second.image.height() != right_iter->second.image.height() ||
- left_iter->second.quality != right_iter->second.quality) {
- return false;
- }
- }
-
- if (left->color_map != right->color_map)
- return false;
-
- if (left->text_map != right->text_map)
- return false;
-
- return true;
-}
-
-bool DrawTextBlobOp::AreEqual(const PaintOp* base_left,
- const PaintOp* base_right) {
- auto* left = static_cast<const DrawTextBlobOp*>(base_left);
- auto* right = static_cast<const DrawTextBlobOp*>(base_right);
- DCHECK(left->IsValid());
- DCHECK(right->IsValid());
- if (left->flags != right->flags)
- return false;
- if (!AreEqualEvenIfNaN(left->x, right->x))
- return false;
- if (!AreEqualEvenIfNaN(left->y, right->y))
- return false;
- if (left->node_id != right->node_id)
- return false;
- return GrSlugAreEqual(left->slug, right->slug);
-}
-
-bool NoopOp::AreEqual(const PaintOp* base_left, const PaintOp* base_right) {
- return true;
-}
-
-bool RestoreOp::AreEqual(const PaintOp* base_left, const PaintOp* base_right) {
- return true;
-}
-
-bool RotateOp::AreEqual(const PaintOp* base_left, const PaintOp* base_right) {
- auto* left = static_cast<const RotateOp*>(base_left);
- auto* right = static_cast<const RotateOp*>(base_right);
- DCHECK(left->IsValid());
- DCHECK(right->IsValid());
- if (!AreEqualEvenIfNaN(left->degrees, right->degrees))
- return false;
- return true;
-}
-
-bool SaveOp::AreEqual(const PaintOp* base_left, const PaintOp* base_right) {
- return true;
-}
-
-bool SaveLayerOp::AreEqual(const PaintOp* base_left,
- const PaintOp* base_right) {
- auto* left = static_cast<const SaveLayerOp*>(base_left);
- auto* right = static_cast<const SaveLayerOp*>(base_right);
- DCHECK(left->IsValid());
- DCHECK(right->IsValid());
- if (left->flags != right->flags)
- return false;
- if (!AreSkRectsEqual(left->bounds, right->bounds))
- return false;
- return true;
-}
-
-bool SaveLayerAlphaOp::AreEqual(const PaintOp* base_left,
- const PaintOp* base_right) {
- auto* left = static_cast<const SaveLayerAlphaOp*>(base_left);
- auto* right = static_cast<const SaveLayerAlphaOp*>(base_right);
- DCHECK(left->IsValid());
- DCHECK(right->IsValid());
- if (!AreSkRectsEqual(left->bounds, right->bounds))
- return false;
- if (left->alpha != right->alpha)
- return false;
- return true;
-}
-
-bool ScaleOp::AreEqual(const PaintOp* base_left, const PaintOp* base_right) {
- auto* left = static_cast<const ScaleOp*>(base_left);
- auto* right = static_cast<const ScaleOp*>(base_right);
- DCHECK(left->IsValid());
- DCHECK(right->IsValid());
- if (!AreEqualEvenIfNaN(left->sx, right->sx))
- return false;
- if (!AreEqualEvenIfNaN(left->sy, right->sy))
- return false;
- return true;
-}
-
-bool SetMatrixOp::AreEqual(const PaintOp* base_left,
- const PaintOp* base_right) {
- auto* left = static_cast<const SetMatrixOp*>(base_left);
- auto* right = static_cast<const SetMatrixOp*>(base_right);
- DCHECK(left->IsValid());
- DCHECK(right->IsValid());
- if (!AreSkM44sEqual(left->matrix, right->matrix))
- return false;
- return true;
-}
-
-bool SetNodeIdOp::AreEqual(const PaintOp* base_left,
- const PaintOp* base_right) {
- auto* left = static_cast<const SetNodeIdOp*>(base_left);
- auto* right = static_cast<const SetNodeIdOp*>(base_right);
-
- DCHECK(left->IsValid());
- DCHECK(right->IsValid());
- return left->node_id == right->node_id;
-}
-
-bool TranslateOp::AreEqual(const PaintOp* base_left,
- const PaintOp* base_right) {
- auto* left = static_cast<const TranslateOp*>(base_left);
- auto* right = static_cast<const TranslateOp*>(base_right);
- DCHECK(left->IsValid());
- DCHECK(right->IsValid());
- if (!AreEqualEvenIfNaN(left->dx, right->dx))
- return false;
- if (!AreEqualEvenIfNaN(left->dy, right->dy))
- return false;
- return true;
-}
-
-bool PaintOp::IsDrawOp() const {
- return g_is_draw_op[type];
-}
-
-bool PaintOp::IsPaintOpWithFlags() const {
- return g_has_paint_flags[type];
-}
-
-bool PaintOp::operator==(const PaintOp& other) const {
- if (GetType() != other.GetType())
- return false;
- return g_equals_operator[type](this, &other);
-}
-
-// static
-bool PaintOp::TypeHasFlags(PaintOpType type) {
- return g_has_paint_flags[static_cast<uint8_t>(type)];
-}
-
-void PaintOp::Raster(SkCanvas* canvas, const PlaybackParams& params) const {
- g_raster_functions[type](this, canvas, params);
-}
-
-size_t PaintOp::Serialize(void* memory,
- size_t size,
- const SerializeOptions& options,
- const PaintFlags* flags_to_serialize,
- const SkM44& current_ctm,
- const SkM44& original_ctm) const {
- // Need at least enough room for a skip/type header.
- if (size < 4)
- return 0u;
-
- DCHECK_EQ(0u,
- reinterpret_cast<uintptr_t>(memory) % PaintOpBuffer::PaintOpAlign);
-
- size_t written = g_serialize_functions[type](this, memory, size, options,
- flags_to_serialize, current_ctm,
- original_ctm);
- DCHECK_LE(written, size);
- if (written < 4)
- return 0u;
-
- size_t aligned_written = ((written + PaintOpBuffer::PaintOpAlign - 1) &
- ~(PaintOpBuffer::PaintOpAlign - 1));
- if (aligned_written >= kMaxSkip)
- return 0u;
- if (aligned_written > size)
- return 0u;
-
- // Update skip and type now that the size is known.
- uint32_t bytes_to_skip = static_cast<uint32_t>(aligned_written);
- static_cast<uint32_t*>(memory)[0] = type | bytes_to_skip << 8;
- return bytes_to_skip;
-}
-
-PaintOp* PaintOp::Deserialize(const volatile void* input,
- size_t input_size,
- void* output,
- size_t output_size,
- size_t* read_bytes,
- const DeserializeOptions& options) {
- DCHECK_GE(output_size, sizeof(LargestPaintOp));
-
- uint8_t type;
- uint32_t skip;
- if (!PaintOpReader::ReadAndValidateOpHeader(input, input_size, &type, &skip))
- return nullptr;
-
- *read_bytes = skip;
- return g_deserialize_functions[type](input, skip, output, output_size,
- options);
-}
-
-// static
-bool PaintOp::GetBounds(const PaintOp& op, SkRect* rect) {
- DCHECK(op.IsDrawOp());
-
- switch (op.GetType()) {
- case PaintOpType::DrawColor:
- return false;
- case PaintOpType::DrawDRRect: {
- const auto& rect_op = static_cast<const DrawDRRectOp&>(op);
- *rect = rect_op.outer.getBounds();
- rect->sort();
- return true;
- }
- case PaintOpType::DrawImage: {
- const auto& image_op = static_cast<const DrawImageOp&>(op);
- *rect = SkRect::MakeXYWH(image_op.left, image_op.top,
- image_op.image.width(), image_op.image.height());
- rect->sort();
- return true;
- }
- case PaintOpType::DrawImageRect: {
- const auto& image_rect_op = static_cast<const DrawImageRectOp&>(op);
- *rect = image_rect_op.dst;
- rect->sort();
- return true;
- }
- case PaintOpType::DrawIRect: {
- const auto& rect_op = static_cast<const DrawIRectOp&>(op);
- *rect = SkRect::Make(rect_op.rect);
- rect->sort();
- return true;
- }
- case PaintOpType::DrawLine: {
- const auto& line_op = static_cast<const DrawLineOp&>(op);
- rect->setLTRB(line_op.x0, line_op.y0, line_op.x1, line_op.y1);
- rect->sort();
- return true;
- }
- case PaintOpType::DrawOval: {
- const auto& oval_op = static_cast<const DrawOvalOp&>(op);
- *rect = oval_op.oval;
- rect->sort();
- return true;
- }
- case PaintOpType::DrawPath: {
- const auto& path_op = static_cast<const DrawPathOp&>(op);
- *rect = path_op.path.getBounds();
- rect->sort();
- return true;
- }
- case PaintOpType::DrawRect: {
- const auto& rect_op = static_cast<const DrawRectOp&>(op);
- *rect = rect_op.rect;
- rect->sort();
- return true;
- }
- case PaintOpType::DrawRRect: {
- const auto& rect_op = static_cast<const DrawRRectOp&>(op);
- *rect = rect_op.rrect.rect();
- rect->sort();
- return true;
- }
- case PaintOpType::DrawRecord:
- return false;
- case PaintOpType::DrawSkottie: {
- const auto& skottie_op = static_cast<const DrawSkottieOp&>(op);
- *rect = skottie_op.dst;
- rect->sort();
- return true;
- }
- case PaintOpType::DrawTextBlob: {
- const auto& text_op = static_cast<const DrawTextBlobOp&>(op);
- *rect = text_op.blob->bounds().makeOffset(text_op.x, text_op.y);
- rect->sort();
- return true;
- }
- default:
- NOTREACHED();
- }
- return false;
-}
-
-// static
-gfx::Rect PaintOp::ComputePaintRect(const PaintOp& op,
- const SkRect& clip_rect,
- const SkMatrix& ctm) {
- gfx::Rect transformed_rect;
- SkRect op_rect;
- if (!op.IsDrawOp() || !PaintOp::GetBounds(op, &op_rect)) {
- // If we can't provide a conservative bounding rect for the op, assume it
- // covers the complete current clip.
- // TODO(khushalsagar): See if we can do something better for non-draw ops.
- transformed_rect = gfx::ToEnclosingRect(gfx::SkRectToRectF(clip_rect));
- } else {
- const PaintFlags* flags =
- op.IsPaintOpWithFlags()
- ? &(static_cast<const PaintOpWithFlags&>(op).flags)
- : nullptr;
- SkRect paint_rect = MapRect(ctm, op_rect);
- if (flags) {
- SkPaint paint = flags->ToSkPaint();
- paint_rect = paint.canComputeFastBounds() && paint_rect.isFinite()
- ? paint.computeFastBounds(paint_rect, &paint_rect)
- : clip_rect;
- }
- // Clamp the image rect by the current clip rect.
- if (!paint_rect.intersect(clip_rect))
- return gfx::Rect();
-
- transformed_rect = gfx::ToEnclosingRect(gfx::SkRectToRectF(paint_rect));
- }
-
- // During raster, we use the device clip bounds on the canvas, which outsets
- // the actual clip by 1 due to the possibility of antialiasing. Account for
- // this here by outsetting the image rect by 1. Note that this only affects
- // queries into the rtree, which will now return images that only touch the
- // bounds of the query rect.
- //
- // Note that it's not sufficient for us to inset the device clip bounds at
- // raster time, since we might be sending a larger-than-one-item display
- // item to skia, which means that skia will internally determine whether to
- // raster the picture (using device clip bounds that are outset).
- transformed_rect.Inset(-1);
- return transformed_rect;
-}
-
-// static
-bool PaintOp::QuickRejectDraw(const PaintOp& op, const SkCanvas* canvas) {
- if (!op.IsDrawOp())
- return false;
-
- SkRect rect;
- if (!PaintOp::GetBounds(op, &rect))
- return false;
- if (!rect.isFinite())
- return true;
-
- if (op.IsPaintOpWithFlags()) {
- 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);
- }
-
- return canvas->quickReject(rect);
-}
-
-// static
-bool PaintOp::OpHasDiscardableImages(const PaintOp& op) {
- if (op.IsPaintOpWithFlags() && static_cast<const PaintOpWithFlags&>(op)
- .HasDiscardableImagesFromFlags()) {
- return true;
- }
-
- if (op.GetType() == PaintOpType::DrawImage &&
- static_cast<const DrawImageOp&>(op).HasDiscardableImages()) {
- return true;
- } else if (op.GetType() == PaintOpType::DrawImageRect &&
- static_cast<const DrawImageRectOp&>(op).HasDiscardableImages()) {
- return true;
- } else if (op.GetType() == PaintOpType::DrawRecord &&
- static_cast<const DrawRecordOp&>(op).HasDiscardableImages()) {
- return true;
- } else if (op.GetType() == PaintOpType::DrawSkottie &&
- static_cast<const DrawSkottieOp&>(op).HasDiscardableImages()) {
- return true;
- }
-
- return false;
-}
-
-void PaintOp::DestroyThis() {
- auto func = g_destructor_functions[type];
- if (func)
- func(this);
-}
-
-bool PaintOpWithFlags::HasDiscardableImagesFromFlags() const {
- return flags.HasDiscardableImages();
-}
-
-void PaintOpWithFlags::RasterWithFlags(SkCanvas* canvas,
- const PaintFlags* raster_flags,
- const PlaybackParams& params) const {
- g_raster_with_flags_functions[type](this, raster_flags, canvas, params);
-}
-
-int ClipPathOp::CountSlowPaths() const {
- return antialias && !path.isConvex() ? 1 : 0;
-}
-
-int DrawLineOp::CountSlowPaths() const {
- if (const SkPathEffect* effect = flags.getPathEffect().get()) {
- SkPathEffect::DashInfo info;
- SkPathEffect::DashType dashType = effect->asADash(&info);
- if (flags.getStrokeCap() != PaintFlags::kRound_Cap &&
- dashType == SkPathEffect::kDash_DashType && info.fCount == 2) {
- // The PaintFlags will count this as 1, so uncount that here as
- // this kind of line is special cased and not slow.
- return -1;
- }
- }
- return 0;
-}
-
-int DrawPathOp::CountSlowPaths() const {
- // This logic is copied from SkPathCounter instead of attempting to expose
- // that from Skia.
- if (!flags.isAntiAlias() || path.isConvex())
- return 0;
-
- PaintFlags::Style paintStyle = flags.getStyle();
- const SkRect& pathBounds = path.getBounds();
- if (paintStyle == PaintFlags::kStroke_Style && flags.getStrokeWidth() == 0) {
- // AA hairline concave path is not slow.
- return 0;
- } else if (paintStyle == PaintFlags::kFill_Style &&
- pathBounds.width() < 64.f && pathBounds.height() < 64.f &&
- !path.isVolatile()) {
- // AADF eligible concave path is not slow.
- return 0;
- } else {
- return 1;
- }
-}
-
-int DrawRecordOp::CountSlowPaths() const {
- return record->num_slow_paths_up_to_min_for_MSAA();
-}
-
-bool DrawRecordOp::HasNonAAPaint() const {
- return record->HasNonAAPaint();
-}
-
-bool DrawRecordOp::HasDrawTextOps() const {
- return record->has_draw_text_ops();
-}
-
-bool DrawRecordOp::HasSaveLayerOps() const {
- return record->has_save_layer_ops();
-}
-
-bool DrawRecordOp::HasSaveLayerAlphaOps() const {
- return record->has_save_layer_alpha_ops();
-}
-
-bool DrawRecordOp::HasEffectsPreventingLCDTextForSaveLayerAlpha() const {
- return record->has_effects_preventing_lcd_text_for_save_layer_alpha();
-}
-
-AnnotateOp::AnnotateOp() : PaintOp(kType) {}
-
-AnnotateOp::AnnotateOp(PaintCanvas::AnnotationType annotation_type,
- const SkRect& rect,
- sk_sp<SkData> data)
- : PaintOp(kType),
- annotation_type(annotation_type),
- rect(rect),
- data(std::move(data)) {}
-
-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) {}
-
-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),
- sampling(sampling) {}
-
-bool DrawImageOp::HasDiscardableImages() const {
- return image && !image.IsTextureBacked();
-}
-
-DrawImageOp::~DrawImageOp() = default;
-
-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),
- 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 {
- return image && !image.IsTextureBacked();
-}
-
-DrawImageRectOp::~DrawImageRectOp() = default;
-
-DrawRecordOp::DrawRecordOp(sk_sp<const PaintRecord> record)
- : PaintOp(kType), record(std::move(record)) {}
-
-DrawRecordOp::~DrawRecordOp() = default;
-
-size_t DrawRecordOp::AdditionalBytesUsed() const {
- return record->bytes_used();
-}
-
-size_t DrawRecordOp::AdditionalOpCount() const {
- return record->total_op_count();
-}
-
-DrawSkottieOp::DrawSkottieOp(scoped_refptr<SkottieWrapper> skottie,
- SkRect dst,
- float t,
- SkottieFrameDataMap images,
- const SkottieColorMap& color_map,
- SkottieTextPropertyValueMap text_map)
- : PaintOp(kType),
- skottie(std::move(skottie)),
- dst(dst),
- t(t),
- images(std::move(images)),
- color_map(color_map),
- text_map(std::move(text_map)) {}
-
-DrawSkottieOp::DrawSkottieOp() : PaintOp(kType) {}
-
-DrawSkottieOp::~DrawSkottieOp() = default;
-
-bool DrawSkottieOp::HasDiscardableImages() const {
- return !images.empty();
-}
-
-bool DrawRecordOp::HasDiscardableImages() const {
- return record->HasDiscardableImages();
-}
-
-DrawTextBlobOp::DrawTextBlobOp() : PaintOpWithFlags(kType) {}
-
-DrawTextBlobOp::DrawTextBlobOp(sk_sp<SkTextBlob> blob,
- SkScalar x,
- SkScalar y,
- const PaintFlags& flags)
- : PaintOpWithFlags(kType, flags), blob(std::move(blob)), x(x), y(y) {}
-
-DrawTextBlobOp::DrawTextBlobOp(sk_sp<SkTextBlob> blob,
- SkScalar x,
- SkScalar y,
- NodeId node_id,
- const PaintFlags& flags)
- : PaintOpWithFlags(kType, flags),
- blob(std::move(blob)),
- x(x),
- y(y),
- node_id(node_id) {}
-
-DrawTextBlobOp::~DrawTextBlobOp() = default;
-
-PaintOpBuffer::CompositeIterator::CompositeIterator(
- const PaintOpBuffer* buffer,
- const std::vector<size_t>* offsets)
- : iter_(offsets == nullptr ? absl::variant<Iterator, OffsetIterator>(
- absl::in_place_type<Iterator>,
- buffer)
- : absl::variant<Iterator, OffsetIterator>(
- absl::in_place_type<OffsetIterator>,
- buffer,
- offsets)) {
- DCHECK(!buffer->are_ops_destroyed());
-}
-
-PaintOpBuffer::CompositeIterator::CompositeIterator(
- const CompositeIterator& other) = default;
-PaintOpBuffer::CompositeIterator::CompositeIterator(CompositeIterator&& other) =
- default;
-
PaintOpBuffer::PaintOpBuffer()
: has_non_aa_paint_(false),
has_discardable_images_(false),
@@ -2913,19 +93,19 @@ PaintOpBuffer::PaintOpBuffer()
has_draw_text_ops_(false),
has_save_layer_ops_(false),
has_save_layer_alpha_ops_(false),
- has_effects_preventing_lcd_text_for_save_layer_alpha_(false),
- are_ops_destroyed_(false) {}
+ has_effects_preventing_lcd_text_for_save_layer_alpha_(false) {}
PaintOpBuffer::PaintOpBuffer(PaintOpBuffer&& other) {
*this = std::move(other);
}
PaintOpBuffer::~PaintOpBuffer() {
- Reset();
+ DestroyOps();
}
PaintOpBuffer& PaintOpBuffer::operator=(PaintOpBuffer&& other) {
data_ = std::move(other.data_);
+ DCHECK(!other.data_);
used_ = other.used_;
reserved_ = other.reserved_;
op_count_ = other.op_count_;
@@ -2940,24 +120,31 @@ PaintOpBuffer& PaintOpBuffer::operator=(PaintOpBuffer&& other) {
has_save_layer_alpha_ops_ = other.has_save_layer_alpha_ops_;
has_effects_preventing_lcd_text_for_save_layer_alpha_ =
other.has_effects_preventing_lcd_text_for_save_layer_alpha_;
- are_ops_destroyed_ = other.are_ops_destroyed_;
- // Make sure the other pob can destruct safely.
- other.used_ = 0;
- other.op_count_ = 0;
+ // Make sure the other pob can destruct safely or is ready for reuse.
other.reserved_ = 0;
+ other.ResetRetainingBuffer();
return *this;
}
-void PaintOpBuffer::Reset() {
- if (!are_ops_destroyed_) {
- for (PaintOp& op : Iterator(this)) {
- op.DestroyThis();
+void PaintOpBuffer::DestroyOps() {
+ if (data_) {
+ for (size_t offset = 0; offset < used_;) {
+ auto* op = reinterpret_cast<PaintOp*>(data_.get() + offset);
+ offset += op->skip;
+ op->DestroyThis();
}
}
+}
- // Leave data_ allocated, reserved_ unchanged. ShrinkToFit will take care of
- // that if called.
+void PaintOpBuffer::Reset() {
+ DestroyOps();
+ // Leave data_ allocated, reserved_ unchanged. ShrinkToFit() will take care
+ // of that if called.
+ ResetRetainingBuffer();
+}
+
+void PaintOpBuffer::ResetRetainingBuffer() {
used_ = 0;
op_count_ = 0;
num_slow_paths_up_to_min_for_MSAA_ = 0;
@@ -2970,32 +157,6 @@ void PaintOpBuffer::Reset() {
has_save_layer_ops_ = false;
has_save_layer_alpha_ops_ = false;
has_effects_preventing_lcd_text_for_save_layer_alpha_ = false;
- are_ops_destroyed_ = false;
-}
-
-// When |op| is a nested PaintOpBuffer, this returns the PaintOp inside
-// that buffer if the buffer contains a single drawing op, otherwise it
-// returns null. This searches recursively if the PaintOpBuffer contains only
-// another PaintOpBuffer.
-static const PaintOp* GetNestedSingleDrawingOp(const PaintOp* op) {
- if (!op->IsDrawOp())
- return nullptr;
- while (op->GetType() == PaintOpType::DrawRecord) {
- auto* draw_record_op = static_cast<const DrawRecordOp*>(op);
- if (draw_record_op->record->size() > 1) {
- // If there's more than one op, then we need to keep the
- // SaveLayer.
- return nullptr;
- }
-
- // Recurse into the single-op DrawRecordOp and make sure it's a
- // drawing op.
- op = &draw_record_op->record->GetFirstOp();
- if (!op->IsDrawOp())
- return nullptr;
- }
-
- return op;
}
void PaintOpBuffer::Playback(SkCanvas* canvas) const {
@@ -3007,87 +168,15 @@ void PaintOpBuffer::Playback(SkCanvas* canvas,
Playback(canvas, params, nullptr);
}
-PaintOpBuffer::PlaybackFoldingIterator::PlaybackFoldingIterator(
- const PaintOpBuffer* buffer,
- const std::vector<size_t>* offsets)
- : iter_(buffer, offsets),
- folded_draw_color_(SkColors::kTransparent, SkBlendMode::kSrcOver) {
- DCHECK(!buffer->are_ops_destroyed());
- FindNextOp();
-}
-
-PaintOpBuffer::PlaybackFoldingIterator::~PlaybackFoldingIterator() = default;
-
-void PaintOpBuffer::PlaybackFoldingIterator::FindNextOp() {
- current_alpha_ = 1.0f;
- for (current_op_ = NextUnfoldedOp(); current_op_;
- current_op_ = NextUnfoldedOp()) {
- if (current_op_->GetType() != PaintOpType::SaveLayerAlpha)
- break;
- const PaintOp* second = NextUnfoldedOp();
- if (!second)
- break;
-
- if (second->GetType() == PaintOpType::Restore) {
- // Drop a SaveLayerAlpha/Restore combo.
- continue;
- }
-
- // Find a nested drawing PaintOp to replace |second| if possible, while
- // holding onto the pointer to |second| in case we can't find a nested
- // drawing op to replace it with.
- const PaintOp* draw_op = GetNestedSingleDrawingOp(second);
-
- const PaintOp* third = nullptr;
- if (draw_op) {
- third = NextUnfoldedOp();
- if (third && third->GetType() == PaintOpType::Restore) {
- auto* save_op = static_cast<const SaveLayerAlphaOp*>(current_op_);
- if (draw_op->IsPaintOpWithFlags() &&
- // SkPaint::drawTextBlob() applies alpha on each glyph so we don't
- // fold SaveLayerAlpha into DrwaTextBlob to ensure correct alpha
- // even if some glyphs overlap.
- draw_op->GetType() != PaintOpType::DrawTextBlob) {
- auto* flags_op = static_cast<const PaintOpWithFlags*>(draw_op);
- if (flags_op->flags.SupportsFoldingAlpha()) {
- current_alpha_ = save_op->alpha;
- current_op_ = draw_op;
- break;
- }
- } else if (draw_op->GetType() == PaintOpType::DrawColor &&
- static_cast<const DrawColorOp*>(draw_op)->mode ==
- SkBlendMode::kSrcOver) {
- auto* draw_color_op = static_cast<const DrawColorOp*>(draw_op);
- SkColor4f color = draw_color_op->color;
- folded_draw_color_.color = {color.fR, color.fG, color.fB,
- save_op->alpha * color.fA};
- current_op_ = &folded_draw_color_;
- break;
- }
- }
- }
-
- // If we get here, then we could not find a foldable sequence after
- // this SaveLayerAlpha, so store any peeked at ops.
- stack_->push_back(second);
- if (third)
- stack_->push_back(third);
- break;
+sk_sp<PaintRecord> PaintOpBuffer::MoveRetainingBufferIfPossible() {
+ const size_t old_reserved = reserved_;
+ sk_sp<PaintRecord> result = sk_make_sp<PaintRecord>(std::move(*this));
+ if (BufferDataPtr old_data = result->ReallocIfNeededToFit()) {
+ // Reuse the original buffer for future recording.
+ data_ = std::move(old_data);
+ reserved_ = old_reserved;
}
-}
-
-const PaintOp* PaintOpBuffer::PlaybackFoldingIterator::NextUnfoldedOp() {
- if (stack_->size()) {
- const PaintOp* op = stack_->front();
- // Shift paintops forward.
- stack_->erase(stack_->begin());
- return op;
- }
- if (!iter_)
- return nullptr;
- const PaintOp& op = *iter_;
- ++iter_;
- return &op;
+ return result;
}
void PaintOpBuffer::Playback(SkCanvas* canvas,
@@ -3119,13 +208,18 @@ void PaintOpBuffer::Playback(SkCanvas* canvas,
// 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->getLocalToDevice(),
- params.custom_callback,
- params.did_draw_op_callback);
+ params.custom_callback, params.did_draw_op_callback,
+ params.convert_op_callback);
new_params.save_layer_alpha_should_preserve_lcd_text =
save_layer_alpha_should_preserve_lcd_text;
new_params.is_analyzing = params.is_analyzing;
for (PlaybackFoldingIterator iter(this, offsets); iter; ++iter) {
- const PaintOp& op = *iter;
+ const PaintOp* op = iter.get();
+ if (params.convert_op_callback) {
+ op = params.convert_op_callback.Run(*op);
+ if (!op)
+ continue;
+ }
// This is an optimization to replicate the behaviour in SkCanvas
// which rejects ops that draw outside the current clip. In the
@@ -3133,13 +227,13 @@ void PaintOpBuffer::Playback(SkCanvas* canvas,
// using an ImageProvider for pre-decoding images, we can save
// performing an expensive decode that will never be rasterized.
const bool skip_op = new_params.image_provider &&
- PaintOp::OpHasDiscardableImages(op) &&
- PaintOp::QuickRejectDraw(op, canvas);
+ PaintOp::OpHasDiscardableImages(*op) &&
+ PaintOp::QuickRejectDraw(*op, canvas);
if (skip_op)
continue;
- if (op.IsPaintOpWithFlags()) {
- const auto& flags_op = static_cast<const PaintOpWithFlags&>(op);
+ if (op->IsPaintOpWithFlags()) {
+ const auto& flags_op = static_cast<const PaintOpWithFlags&>(*op);
auto* context = canvas->recordingContext();
const ScopedRasterFlags scoped_flags(
&flags_op.flags, new_params.image_provider, canvas->getTotalMatrix(),
@@ -3148,7 +242,7 @@ void PaintOpBuffer::Playback(SkCanvas* canvas,
flags_op.RasterWithFlags(canvas, raster_flags, new_params);
} else {
DCHECK_EQ(iter.alpha(), 255);
- op.Raster(canvas, new_params);
+ op->Raster(canvas, new_params);
}
if (!new_params.did_draw_op_callback.is_null())
@@ -3163,28 +257,13 @@ bool PaintOpBuffer::Deserialize(const volatile void* input,
while (total_bytes_read < input_size) {
const volatile void* next_op =
static_cast<const volatile char*>(input) + total_bytes_read;
-
- uint8_t type;
- uint32_t skip;
- if (!PaintOpReader::ReadAndValidateOpHeader(
- next_op, input_size - total_bytes_read, &type, &skip)) {
+ size_t read_bytes = 0;
+ if (!PaintOp::DeserializeIntoPaintOpBuffer(next_op,
+ input_size - total_bytes_read,
+ this, &read_bytes, options)) {
return false;
}
-
- size_t op_skip = ComputeOpSkip(g_type_to_size[type]);
- const auto* op = g_deserialize_functions[type](
- next_op, skip, AllocatePaintOp(op_skip), op_skip, options);
- if (!op) {
- // The last allocated op has already been destroyed if it failed to
- // deserialize. Update the buffer's op tracking to exclude it to avoid
- // access during cleanup at destruction.
- used_ -= op_skip;
- op_count_--;
- return false;
- }
-
- g_analyze_op_functions[type](this, op);
- total_bytes_read += skip;
+ total_bytes_read += read_bytes;
}
DCHECK_GT(size(), 0u);
@@ -3243,21 +322,23 @@ SkRect PaintOpBuffer::GetFixedScaleBounds(const SkMatrix& ctm,
SkScalarCeilToInt(SkScalarAbs(scale.height() * bounds.height())));
}
-void PaintOpBuffer::ReallocBuffer(size_t new_size) {
+PaintOpBuffer::BufferDataPtr PaintOpBuffer::ReallocBuffer(size_t new_size) {
DCHECK_GE(new_size, used_);
std::unique_ptr<char, base::AlignedFreeDeleter> new_data(
- static_cast<char*>(base::AlignedAlloc(new_size, PaintOpAlign)));
+ static_cast<char*>(base::AlignedAlloc(new_size, kPaintOpAlign)));
if (data_)
memcpy(new_data.get(), data_.get(), used_);
+ BufferDataPtr old_data = std::move(data_);
data_ = std::move(new_data);
reserved_ = new_size;
+ return old_data;
}
void* PaintOpBuffer::AllocatePaintOp(size_t skip) {
DCHECK_LT(skip, PaintOp::kMaxSkip);
if (used_ + skip > reserved_) {
// Start reserved_ at kInitialBufferSize and then double.
- // ShrinkToFit can make this smaller afterwards.
+ // ShrinkToFit() can make this smaller afterwards.
size_t new_size = reserved_ ? reserved_ : kInitialBufferSize;
while (used_ + skip > new_size)
new_size *= 2;
@@ -3272,30 +353,36 @@ void* PaintOpBuffer::AllocatePaintOp(size_t skip) {
}
void PaintOpBuffer::ShrinkToFit() {
- if (used_ == reserved_)
- return;
+ ReallocIfNeededToFit();
+}
+
+PaintOpBuffer::BufferDataPtr PaintOpBuffer::ReallocIfNeededToFit() {
+ if (used_ == reserved_) {
+ return nullptr;
+ }
if (!used_) {
reserved_ = 0;
- data_.reset();
- } else {
- ReallocBuffer(used_);
+ return std::move(data_);
}
+ return ReallocBuffer(used_);
}
bool PaintOpBuffer::operator==(const PaintOpBuffer& other) const {
- if (op_count_ != other.op_count_)
- return false;
- if (num_slow_paths_up_to_min_for_MSAA_ !=
- other.num_slow_paths_up_to_min_for_MSAA_)
- return false;
- if (subrecord_bytes_used_ != other.subrecord_bytes_used_)
- return false;
- if (subrecord_op_count_ != other.subrecord_op_count_)
- return false;
- if (has_non_aa_paint_ != other.has_non_aa_paint_)
- return false;
- if (has_discardable_images_ != other.has_discardable_images_)
+ // Check status fields first, which is faster than checking equality of
+ // paint operations. This doesn't need to be complete, and should not check
+ // data buffer capacity related fields because they don't affect equality.
+ if (op_count_ != other.op_count_ || used_ != other.used_ ||
+ num_slow_paths_up_to_min_for_MSAA_ !=
+ other.num_slow_paths_up_to_min_for_MSAA_ ||
+ subrecord_op_count_ != other.subrecord_op_count_ ||
+ has_draw_ops_ != other.has_draw_ops_ ||
+ has_draw_text_ops_ != other.has_draw_text_ops_ ||
+ has_effects_preventing_lcd_text_for_save_layer_alpha_ !=
+ other.has_effects_preventing_lcd_text_for_save_layer_alpha_ ||
+ has_non_aa_paint_ != other.has_non_aa_paint_ ||
+ has_discardable_images_ != other.has_discardable_images_) {
return false;
+ }
Iterator left_iter(this);
Iterator right_iter(&other);
@@ -3324,4 +411,43 @@ bool PaintOpBuffer::NeedsAdditionalInvalidationForLCDText(
old_buffer.has_effects_preventing_lcd_text_for_save_layer_alpha();
}
+void PaintOpBuffer::UpdateSaveLayerBounds(size_t offset, const SkRect& bounds) {
+ CHECK_LT(offset, used_);
+ CHECK_LE(offset + sizeof(PaintOp), used_);
+
+ auto* op = reinterpret_cast<PaintOp*>(data_.get() + offset);
+ switch (op->GetType()) {
+ case SaveLayerOp::kType:
+ CHECK_LE(offset + sizeof(SaveLayerOp), used_);
+ static_cast<SaveLayerOp*>(op)->bounds = bounds;
+ break;
+ case SaveLayerAlphaOp::kType:
+ CHECK_LE(offset + sizeof(SaveLayerAlphaOp), used_);
+ static_cast<SaveLayerAlphaOp*>(op)->bounds = bounds;
+ break;
+ default:
+ NOTREACHED();
+ }
+}
+
+const PaintOp* PaintOpBuffer::GetOpAtForTesting(size_t index,
+ PaintOpType type) const {
+ size_t i = 0;
+ for (const auto& op : *this) {
+ if (i == index) {
+ return op.GetType() == type ? &op : nullptr;
+ }
+ i++;
+ }
+ return nullptr;
+}
+
+PaintOpBuffer::Iterator PaintOpBuffer::begin() const {
+ return Iterator(this);
+}
+
+PaintOpBuffer::Iterator PaintOpBuffer::end() const {
+ return Iterator(this).end();
+}
+
} // namespace cc
diff --git a/chromium/cc/paint/paint_op_buffer.h b/chromium/cc/paint/paint_op_buffer.h
index 48651f9bf0e..6edc1410523 100644
--- a/chromium/cc/paint/paint_op_buffer.h
+++ b/chromium/cc/paint/paint_op_buffer.h
@@ -5,140 +5,63 @@
#ifndef CC_PAINT_PAINT_OP_BUFFER_H_
#define CC_PAINT_PAINT_OP_BUFFER_H_
-#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"
-#include "base/containers/stack_container.h"
#include "base/debug/alias.h"
#include "base/memory/aligned_memory.h"
#include "base/memory/raw_ptr.h"
+#include "base/memory/raw_ptr_exclusion.h"
#include "base/memory/scoped_refptr.h"
#include "base/notreached.h"
#include "cc/base/math_util.h"
-#include "cc/paint/node_id.h"
-#include "cc/paint/paint_canvas.h"
#include "cc/paint/paint_export.h"
-#include "cc/paint/paint_flags.h"
-#include "cc/paint/skottie_color_map.h"
-#include "cc/paint/skottie_frame_data.h"
-#include "cc/paint/skottie_resource_metadata.h"
-#include "cc/paint/skottie_text_property_value.h"
-#include "cc/paint/skottie_wrapper.h"
+#include "gpu/command_buffer/common/mailbox.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/abseil-cpp/absl/types/variant.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "third_party/skia/include/core/SkPath.h"
-#include "third_party/skia/include/core/SkRRect.h"
-#include "third_party/skia/include/core/SkRect.h"
+#include "third_party/skia/include/core/SkM44.h"
#include "third_party/skia/include/core/SkRefCnt.h"
-#include "third_party/skia/include/core/SkScalar.h"
-#include "ui/gfx/geometry/rect.h"
+class SkCanvas;
class SkColorSpace;
class SkImage;
class SkStrikeClient;
class SkStrikeServer;
-class SkTextBlob;
-// PaintOpBuffer is a reimplementation of SkLiteDL.
-// See: third_party/skia/src/core/SkLiteDL.h.
namespace cc {
+
class ClientPaintCache;
class ImageProvider;
+class PaintOp;
class ServicePaintCache;
class SkottieSerializationHistory;
class TransferCacheDeserializeHelper;
class TransferCacheSerializeHelper;
-class CC_PAINT_EXPORT ThreadsafePath : public SkPath {
- public:
- explicit ThreadsafePath(const SkPath& path) : SkPath(path) {
- updateBoundsCache();
- }
- ThreadsafePath() { updateBoundsCache(); }
-};
-
-class CC_PAINT_EXPORT SharedImageProvider {
- public:
- enum class Error {
- kNoError,
- kUnknownMailbox,
- kNoAccess,
- kSkImageCreationFailed,
- };
-
- virtual ~SharedImageProvider() = default;
- virtual sk_sp<SkImage> OpenSharedImageForRead(const gpu::Mailbox& mailbox,
- Error& error) = 0;
-};
-
-// See PaintOp::Serialize/Deserialize for comments. Derived Serialize types
-// don't write the 4 byte type/skip header because they don't know how much
-// data they will need to write. PaintOp::Serialize itself must update it.
-#define HAS_SERIALIZATION_FUNCTIONS() \
- static size_t Serialize( \
- const PaintOp* op, void* memory, size_t size, \
- const SerializeOptions& options, const PaintFlags* flags_to_serialize, \
- const SkM44& current_ctm, const SkM44& original_ctm); \
- static PaintOp* Deserialize(const volatile void* input, size_t input_size, \
- void* output, size_t output_size, \
- const DeserializeOptions& options)
-
-enum class PaintOpType : uint8_t {
- Annotate,
- ClipPath,
- ClipRect,
- ClipRRect,
- Concat,
- CustomData,
- DrawColor,
- DrawDRRect,
- DrawImage,
- DrawImageRect,
- DrawIRect,
- DrawLine,
- DrawOval,
- DrawPath,
- DrawRecord,
- DrawRect,
- DrawRRect,
- DrawSkottie,
- DrawTextBlob,
- Noop,
- Restore,
- Rotate,
- Save,
- SaveLayer,
- SaveLayerAlpha,
- Scale,
- SetMatrix,
- SetNodeId,
- Translate,
- LastPaintOpType = Translate,
-};
-
-CC_PAINT_EXPORT std::string PaintOpTypeToString(PaintOpType type);
-CC_PAINT_EXPORT std::ostream& operator<<(std::ostream&, PaintOpType);
+enum class PaintOpType : uint8_t;
struct CC_PAINT_EXPORT PlaybackParams {
using CustomDataRasterCallback =
base::RepeatingCallback<void(SkCanvas* canvas, uint32_t id)>;
using DidDrawOpCallback = base::RepeatingCallback<void()>;
+ // This callback returns
+ // - &op if no conversion;
+ // - a pointer (owned by the callback) to a new op;
+ // - null if the op should be discarded.
+ using ConvertOpCallback =
+ base::RepeatingCallback<const PaintOp*(const PaintOp& op)>;
explicit PlaybackParams(ImageProvider* image_provider);
PlaybackParams(
ImageProvider* image_provider,
const SkM44& original_ctm,
CustomDataRasterCallback custom_callback = CustomDataRasterCallback(),
- DidDrawOpCallback did_draw_op_callback = DidDrawOpCallback());
+ DidDrawOpCallback did_draw_op_callback = DidDrawOpCallback(),
+ ConvertOpCallback convert_op_callback = ConvertOpCallback());
~PlaybackParams();
PlaybackParams(const PlaybackParams& other);
@@ -151,30 +74,32 @@ struct CC_PAINT_EXPORT PlaybackParams {
SkM44 original_ctm;
CustomDataRasterCallback custom_callback;
DidDrawOpCallback did_draw_op_callback;
+ ConvertOpCallback convert_op_callback;
absl::optional<bool> save_layer_alpha_should_preserve_lcd_text;
bool is_analyzing = false;
};
-class CC_PAINT_EXPORT PaintOp {
+class CC_PAINT_EXPORT SharedImageProvider {
public:
- uint32_t type : 8;
- uint32_t skip : 24;
-
- explicit PaintOp(PaintOpType type) : type(static_cast<uint8_t>(type)) {}
-
- PaintOpType GetType() const { return static_cast<PaintOpType>(type); }
+ enum class Error {
+ kNoError,
+ kUnknownMailbox,
+ kNoAccess,
+ kSkImageCreationFailed,
+ };
- // Subclasses should provide a static Raster() method which is called from
- // here. The Raster method should take a const PaintOp* parameter. It is
- // static with a pointer to the base type so that we can use it as a function
- // pointer.
- void Raster(SkCanvas* canvas, const PlaybackParams& params) const;
- bool IsDrawOp() const;
- bool IsPaintOpWithFlags() const;
+ virtual ~SharedImageProvider() = default;
+ virtual sk_sp<SkImage> OpenSharedImageForRead(const gpu::Mailbox& mailbox,
+ Error& error) = 0;
+};
- bool operator==(const PaintOp& other) const;
- bool operator!=(const PaintOp& other) const { return !(*this == other); }
+// Defined outside of the class as this const is used in multiple files.
+static constexpr int kMinNumberOfSlowPathsForMSAA = 6;
+// PaintOpBuffer is a reimplementation of SkLiteDL.
+// See: third_party/skia/src/core/SkLiteDL.h.
+class CC_PAINT_EXPORT PaintOpBuffer : public SkRefCnt {
+ public:
struct CC_PAINT_EXPORT SerializeOptions {
SerializeOptions();
SerializeOptions(ImageProvider* image_provider,
@@ -217,888 +142,37 @@ class CC_PAINT_EXPORT PaintOp {
std::vector<uint8_t>* scratch_buffer,
bool is_privileged,
SharedImageProvider* shared_image_provider);
- TransferCacheDeserializeHelper* transfer_cache = nullptr;
- ServicePaintCache* paint_cache = nullptr;
- SkStrikeClient* strike_client = nullptr;
+ raw_ptr<TransferCacheDeserializeHelper> transfer_cache = nullptr;
+ raw_ptr<ServicePaintCache> paint_cache = nullptr;
+ raw_ptr<SkStrikeClient> strike_client = nullptr;
// Do a DumpWithoutCrashing when serialization fails.
bool crash_dump_on_failure = false;
// Used to memcpy Skia flattenables into to avoid TOCTOU issues.
- std::vector<uint8_t>* scratch_buffer = nullptr;
+ raw_ptr<std::vector<uint8_t>> scratch_buffer = nullptr;
// True if the deserialization is happening on a privileged gpu channel.
// e.g. in the case of UI.
bool is_privileged = false;
- SharedImageProvider* shared_image_provider = nullptr;
+ raw_ptr<SharedImageProvider> shared_image_provider = nullptr;
};
- // Indicates how PaintImages are serialized.
- enum class SerializedImageType : uint8_t {
- kNoImage,
- kImageData,
- kTransferCacheEntry,
- kMailbox,
- kLastType = kMailbox
- };
-
- // Subclasses should provide a static Serialize() method called from here.
- // If the op can be serialized to |memory| in no more than |size| bytes,
- // then return the number of bytes written. If it won't fit, return 0.
- // If |flags_to_serialize| is non-null, it overrides any flags within the op.
- // |current_ctm| is the transform that will affect the op when rasterized.
- // |original_ctm| is the transform that SetMatrixOps must be made relative to.
- size_t Serialize(void* memory,
- size_t size,
- const SerializeOptions& options,
- const PaintFlags* flags_to_serialize,
- const SkM44& current_ctm,
- const SkM44& original_ctm) const;
-
- // Deserializes a PaintOp of this type from a given buffer |input| of
- // at most |input_size| bytes. Returns null on any errors.
- // The PaintOp is deserialized into the |output| buffer and returned
- // if valid. nullptr is returned if the deserialization fails.
- // |output_size| must be at least LargestPaintOp + serialized->skip,
- // to fit all ops. The caller is responsible for destroying these ops.
- // After reading, it returns the number of bytes read in |read_bytes|.
- static PaintOp* Deserialize(const volatile void* input,
- size_t input_size,
- void* output,
- size_t output_size,
- size_t* read_bytes,
- const DeserializeOptions& options);
-
- // For draw ops, returns true if a conservative bounding rect can be provided
- // for the op.
- static bool GetBounds(const PaintOp& op, SkRect* rect);
-
- // Returns the minimum conservative bounding rect that |op| draws to on a
- // canvas. |clip_rect| and |ctm| are the current clip rect and transform on
- // this canvas.
- static gfx::Rect ComputePaintRect(const PaintOp& op,
- const SkRect& clip_rect,
- const SkMatrix& ctm);
-
- // Returns true if the op lies outside the current clip and should be skipped.
- // Should only be used with draw ops.
- static bool QuickRejectDraw(const PaintOp& op, const SkCanvas* canvas);
-
- // Returns true if executing this op will require decoding of any lazy
- // generated images.
- static bool OpHasDiscardableImages(const PaintOp& op);
-
- // Returns true if the given op type has PaintFlags.
- static bool TypeHasFlags(PaintOpType type);
-
- int CountSlowPaths() const { return 0; }
- int CountSlowPathsFromFlags() const { return 0; }
-
- bool HasNonAAPaint() const { return false; }
- bool HasDrawTextOps() const { return false; }
- bool HasSaveLayerOps() const { return false; }
- bool HasSaveLayerAlphaOps() const { return false; }
- // Returns true if effects are present that would break LCD text or be broken
- // by the flags for SaveLayerAlpha to preserving LCD text.
- bool HasEffectsPreventingLCDTextForSaveLayerAlpha() const { return false; }
-
- bool HasDiscardableImages() const { return false; }
- bool HasDiscardableImagesFromFlags() const { return false; }
-
- // Returns the number of bytes used by this op in referenced sub records
- // and display lists. This doesn't count other objects like paths or blobs.
- size_t AdditionalBytesUsed() const { return 0; }
-
- // Returns the number of ops in referenced sub records and display lists.
- size_t AdditionalOpCount() const { return 0; }
-
- // Run the destructor for the derived op type. Ops are usually contained in
- // memory buffers and so don't have their destructors run automatically.
- void DestroyThis();
-
- // DrawColor is more restrictive on the blend modes that can be used.
- static bool IsValidDrawColorSkBlendMode(SkBlendMode mode) {
- return static_cast<uint32_t>(mode) <=
- static_cast<uint32_t>(SkBlendMode::kLastCoeffMode);
- }
-
- // PaintFlags can have more complex blend modes than DrawColor.
- static bool IsValidPaintFlagsSkBlendMode(SkBlendMode mode) {
- return static_cast<uint32_t>(mode) <=
- static_cast<uint32_t>(SkBlendMode::kLastMode);
- }
-
- static bool IsValidSkClipOp(SkClipOp op) {
- return static_cast<uint32_t>(op) <=
- static_cast<uint32_t>(SkClipOp::kMax_EnumValue);
- }
-
- static bool IsValidPath(const SkPath& path) { return path.isValid(); }
-
- static bool IsUnsetRect(const SkRect& rect) {
- return rect.fLeft == SK_ScalarInfinity;
- }
-
- static bool IsValidOrUnsetRect(const SkRect& rect) {
- return IsUnsetRect(rect) || rect.isFinite();
- }
-
- // PaintOp supports having nans, but some tests want to make sure
- // that operator== is true on two objects. These helpers compare
- // various types in a way where nan == nan is true.
- static bool AreEqualEvenIfNaN(float left, float right) {
- if (std::isnan(left) && std::isnan(right))
- return true;
- return left == right;
- }
- static bool AreSkPointsEqual(const SkPoint& left, const SkPoint& right);
- static bool AreSkPoint3sEqual(const SkPoint3& left, const SkPoint3& right);
- 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;
- static constexpr bool kHasPaintFlags = false;
- // Since skip and type fit in a uint32_t, this is the max size of skip.
- static constexpr size_t kMaxSkip = static_cast<size_t>(1 << 24);
- static const SkRect kUnsetRect;
-};
-
-class CC_PAINT_EXPORT PaintOpWithFlags : public PaintOp {
- public:
- static constexpr bool kHasPaintFlags = true;
- PaintOpWithFlags(PaintOpType type, const PaintFlags& flags)
- : PaintOp(type), flags(flags) {}
-
- int CountSlowPathsFromFlags() const { return flags.getPathEffect() ? 1 : 0; }
- bool HasNonAAPaint() const { return !flags.isAntiAlias(); }
- bool HasDiscardableImagesFromFlags() const;
-
- void RasterWithFlags(SkCanvas* canvas,
- const PaintFlags* flags,
- const PlaybackParams& params) const;
-
- // Subclasses should provide a static RasterWithFlags() method which is called
- // from the Raster() method. The RasterWithFlags() should use the SkPaint
- // passed to it, instead of the |flags| member directly, as some callers may
- // provide a modified PaintFlags. The RasterWithFlags() method is static with
- // a const PaintOpWithFlags* parameter so that it can be used as a function
- // pointer.
- PaintFlags flags;
-
- protected:
- explicit PaintOpWithFlags(PaintOpType type) : PaintOp(type) {}
-};
-
-class CC_PAINT_EXPORT AnnotateOp final : public PaintOp {
- public:
- static constexpr PaintOpType kType = PaintOpType::Annotate;
- AnnotateOp(PaintCanvas::AnnotationType annotation_type,
- const SkRect& rect,
- sk_sp<SkData> data);
- ~AnnotateOp();
- static void Raster(const AnnotateOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params);
- bool IsValid() const { return rect.isFinite(); }
- static bool AreEqual(const PaintOp* left, const PaintOp* right);
- HAS_SERIALIZATION_FUNCTIONS();
-
- PaintCanvas::AnnotationType annotation_type;
- SkRect rect;
- sk_sp<SkData> data;
-
- private:
- AnnotateOp();
-};
-
-class CC_PAINT_EXPORT ClipPathOp final : public PaintOp {
- public:
- static constexpr PaintOpType kType = PaintOpType::ClipPath;
- ClipPathOp(SkPath path,
- SkClipOp op,
- bool antialias,
- UsePaintCache use_paint_cache = UsePaintCache::kEnabled)
- : PaintOp(kType),
- path(path),
- op(op),
- antialias(antialias),
- use_cache(use_paint_cache) {}
- static void Raster(const ClipPathOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params);
- bool IsValid() const { return IsValidSkClipOp(op) && IsValidPath(path); }
- static bool AreEqual(const PaintOp* left, const PaintOp* right);
- int CountSlowPaths() const;
- bool HasNonAAPaint() const { return !antialias; }
- HAS_SERIALIZATION_FUNCTIONS();
-
- ThreadsafePath path;
- SkClipOp op;
- bool antialias;
- UsePaintCache use_cache;
-
- private:
- ClipPathOp() : PaintOp(kType) {}
-};
-
-class CC_PAINT_EXPORT ClipRectOp final : public PaintOp {
- public:
- static constexpr PaintOpType kType = PaintOpType::ClipRect;
- ClipRectOp(const SkRect& rect, SkClipOp op, bool antialias)
- : PaintOp(kType), rect(rect), op(op), antialias(antialias) {}
- static void Raster(const ClipRectOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params);
- bool IsValid() const { return IsValidSkClipOp(op) && rect.isFinite(); }
- static bool AreEqual(const PaintOp* left, const PaintOp* right);
- HAS_SERIALIZATION_FUNCTIONS();
-
- SkRect rect;
- SkClipOp op;
- bool antialias;
-
- private:
- ClipRectOp() : PaintOp(kType) {}
-};
-
-class CC_PAINT_EXPORT ClipRRectOp final : public PaintOp {
- public:
- static constexpr PaintOpType kType = PaintOpType::ClipRRect;
- ClipRRectOp(const SkRRect& rrect, SkClipOp op, bool antialias)
- : PaintOp(kType), rrect(rrect), op(op), antialias(antialias) {}
- static void Raster(const ClipRRectOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params);
- bool IsValid() const { return IsValidSkClipOp(op) && rrect.isValid(); }
- static bool AreEqual(const PaintOp* left, const PaintOp* right);
- bool HasNonAAPaint() const { return !antialias; }
- HAS_SERIALIZATION_FUNCTIONS();
-
- SkRRect rrect;
- SkClipOp op;
- bool antialias;
-
- private:
- ClipRRectOp() : PaintOp(kType) {}
-};
-
-class CC_PAINT_EXPORT ConcatOp final : public PaintOp {
- public:
- static constexpr PaintOpType kType = PaintOpType::Concat;
- explicit ConcatOp(const SkM44& matrix) : PaintOp(kType), matrix(matrix) {}
- static void Raster(const ConcatOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params);
- bool IsValid() const { return true; }
- static bool AreEqual(const PaintOp* left, const PaintOp* right);
- HAS_SERIALIZATION_FUNCTIONS();
-
- SkM44 matrix;
-
- private:
- ConcatOp() : PaintOp(kType) {}
-};
-
-class CC_PAINT_EXPORT CustomDataOp final : public PaintOp {
- public:
- static constexpr PaintOpType kType = PaintOpType::CustomData;
- explicit CustomDataOp(uint32_t id) : PaintOp(kType), id(id) {}
- static void Raster(const CustomDataOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params);
- bool IsValid() const { return true; }
- static bool AreEqual(const PaintOp* left, const PaintOp* right);
- HAS_SERIALIZATION_FUNCTIONS();
-
- // Stores user defined id as a placeholder op.
- uint32_t id;
-
- private:
- CustomDataOp() : PaintOp(kType) {}
-};
-
-class CC_PAINT_EXPORT DrawColorOp final : public PaintOp {
- public:
- static constexpr PaintOpType kType = PaintOpType::DrawColor;
- static constexpr bool kIsDrawOp = true;
- DrawColorOp(SkColor4f color, SkBlendMode mode)
- : PaintOp(kType), color(color), mode(mode) {}
- static void Raster(const DrawColorOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params);
- bool IsValid() const { return IsValidDrawColorSkBlendMode(mode); }
- static bool AreEqual(const PaintOp* left, const PaintOp* right);
- HAS_SERIALIZATION_FUNCTIONS();
-
- SkColor4f color;
- SkBlendMode mode;
-
- private:
- DrawColorOp() : PaintOp(kType) {}
-};
-
-class CC_PAINT_EXPORT DrawDRRectOp final : public PaintOpWithFlags {
- public:
- static constexpr PaintOpType kType = PaintOpType::DrawDRRect;
- static constexpr bool kIsDrawOp = true;
- DrawDRRectOp(const SkRRect& outer,
- const SkRRect& inner,
- const PaintFlags& flags)
- : PaintOpWithFlags(kType, flags), outer(outer), inner(inner) {}
- static void RasterWithFlags(const DrawDRRectOp* op,
- const PaintFlags* flags,
- SkCanvas* canvas,
- const PlaybackParams& params);
- bool IsValid() const {
- return flags.IsValid() && outer.isValid() && inner.isValid();
- }
- static bool AreEqual(const PaintOp* left, const PaintOp* right);
- HAS_SERIALIZATION_FUNCTIONS();
-
- SkRRect outer;
- SkRRect inner;
-
- private:
- DrawDRRectOp() : PaintOpWithFlags(kType) {}
-};
-
-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,
- const PaintFlags* flags,
- SkCanvas* canvas,
- const PlaybackParams& params);
- bool IsValid() const {
- return flags.IsValid() && SkScalarIsFinite(scale_adjustment.width()) &&
- SkScalarIsFinite(scale_adjustment.height());
- }
- static bool AreEqual(const PaintOp* left, const PaintOp* right);
- bool HasDiscardableImages() const;
- bool HasNonAAPaint() const { return false; }
- HAS_SERIALIZATION_FUNCTIONS();
-
- PaintImage image;
- SkScalar left;
- SkScalar top;
- SkSamplingOptions sampling;
-
- private:
- DrawImageOp();
-
- // Scale that has already been applied to the decoded image during
- // serialization. Used with OOP raster.
- SkSize scale_adjustment = SkSize::Make(1.f, 1.f);
-};
-
-class CC_PAINT_EXPORT DrawImageRectOp final : public PaintOpWithFlags {
- public:
- static constexpr PaintOpType kType = PaintOpType::DrawImageRect;
- static constexpr bool kIsDrawOp = true;
- 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();
- static void RasterWithFlags(const DrawImageRectOp* op,
- const PaintFlags* flags,
- SkCanvas* canvas,
- const PlaybackParams& params);
- bool IsValid() const {
- return flags.IsValid() && src.isFinite() && dst.isFinite() &&
- SkScalarIsFinite(scale_adjustment.width()) &&
- SkScalarIsFinite(scale_adjustment.height());
- }
- static bool AreEqual(const PaintOp* left, const PaintOp* right);
- bool HasDiscardableImages() const;
- HAS_SERIALIZATION_FUNCTIONS();
-
- PaintImage image;
- SkRect src;
- SkRect dst;
- SkSamplingOptions sampling;
- SkCanvas::SrcRectConstraint constraint;
-
- private:
- DrawImageRectOp();
-
- // Scale that has already been applied to the decoded image during
- // serialization. Used with OOP raster.
- SkSize scale_adjustment = SkSize::Make(1.f, 1.f);
-};
-
-class CC_PAINT_EXPORT DrawIRectOp final : public PaintOpWithFlags {
- public:
- static constexpr PaintOpType kType = PaintOpType::DrawIRect;
- static constexpr bool kIsDrawOp = true;
- DrawIRectOp(const SkIRect& rect, const PaintFlags& flags)
- : PaintOpWithFlags(kType, flags), rect(rect) {}
- static void RasterWithFlags(const DrawIRectOp* op,
- const PaintFlags* flags,
- SkCanvas* canvas,
- const PlaybackParams& params);
- bool IsValid() const { return flags.IsValid(); }
- static bool AreEqual(const PaintOp* left, const PaintOp* right);
- bool HasNonAAPaint() const { return false; }
- HAS_SERIALIZATION_FUNCTIONS();
-
- SkIRect rect;
-
- private:
- DrawIRectOp() : PaintOpWithFlags(kType) {}
-};
-
-class CC_PAINT_EXPORT DrawLineOp final : public PaintOpWithFlags {
- public:
- static constexpr PaintOpType kType = PaintOpType::DrawLine;
- static constexpr bool kIsDrawOp = true;
- DrawLineOp(SkScalar x0,
- SkScalar y0,
- SkScalar x1,
- SkScalar y1,
- const PaintFlags& flags)
- : PaintOpWithFlags(kType, flags), x0(x0), y0(y0), x1(x1), y1(y1) {}
- static void RasterWithFlags(const DrawLineOp* op,
- const PaintFlags* flags,
- SkCanvas* canvas,
- const PlaybackParams& params);
- bool IsValid() const { return flags.IsValid(); }
- static bool AreEqual(const PaintOp* left, const PaintOp* right);
- HAS_SERIALIZATION_FUNCTIONS();
-
- int CountSlowPaths() const;
-
- SkScalar x0;
- SkScalar y0;
- SkScalar x1;
- SkScalar y1;
-
- private:
- DrawLineOp() : PaintOpWithFlags(kType) {}
-};
-
-class CC_PAINT_EXPORT DrawOvalOp final : public PaintOpWithFlags {
- public:
- static constexpr PaintOpType kType = PaintOpType::DrawOval;
- static constexpr bool kIsDrawOp = true;
- DrawOvalOp(const SkRect& oval, const PaintFlags& flags)
- : PaintOpWithFlags(kType, flags), oval(oval) {}
- static void RasterWithFlags(const DrawOvalOp* op,
- const PaintFlags* flags,
- SkCanvas* canvas,
- const PlaybackParams& params);
- bool IsValid() const {
- // Reproduce SkRRect::isValid without converting.
- return flags.IsValid() && oval.isFinite() && oval.isSorted();
- }
- static bool AreEqual(const PaintOp* left, const PaintOp* right);
- HAS_SERIALIZATION_FUNCTIONS();
-
- SkRect oval;
-
- private:
- DrawOvalOp() : PaintOpWithFlags(kType) {}
-};
-
-class CC_PAINT_EXPORT DrawPathOp final : public PaintOpWithFlags {
- public:
- static constexpr PaintOpType kType = PaintOpType::DrawPath;
- static constexpr bool kIsDrawOp = true;
- DrawPathOp(const SkPath& path,
- const PaintFlags& flags,
- UsePaintCache use_paint_cache = UsePaintCache::kEnabled)
- : PaintOpWithFlags(kType, flags),
- path(path),
- sk_path_fill_type(static_cast<uint8_t>(path.getFillType())),
- use_cache(use_paint_cache) {}
- static void RasterWithFlags(const DrawPathOp* op,
- const PaintFlags* flags,
- SkCanvas* canvas,
- const PlaybackParams& params);
- bool IsValid() const { return flags.IsValid() && IsValidPath(path); }
- static bool AreEqual(const PaintOp* left, const PaintOp* right);
- int CountSlowPaths() const;
- HAS_SERIALIZATION_FUNCTIONS();
-
- 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;
- UsePaintCache use_cache;
-
- private:
- DrawPathOp() : PaintOpWithFlags(kType) {}
-};
-
-class CC_PAINT_EXPORT DrawRecordOp final : public PaintOp {
- public:
- static constexpr PaintOpType kType = PaintOpType::DrawRecord;
- static constexpr bool kIsDrawOp = true;
- explicit DrawRecordOp(sk_sp<const PaintRecord> record);
- ~DrawRecordOp();
- static void Raster(const DrawRecordOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params);
- bool IsValid() const { return true; }
- static bool AreEqual(const PaintOp* left, const PaintOp* right);
- size_t AdditionalBytesUsed() const;
- size_t AdditionalOpCount() const;
- bool HasDiscardableImages() const;
- int CountSlowPaths() const;
- bool HasNonAAPaint() const;
- bool HasDrawTextOps() const;
- bool HasSaveLayerOps() const;
- bool HasSaveLayerAlphaOps() const;
- bool HasEffectsPreventingLCDTextForSaveLayerAlpha() const;
- HAS_SERIALIZATION_FUNCTIONS();
-
- sk_sp<const PaintRecord> record;
-};
-
-class CC_PAINT_EXPORT DrawRectOp final : public PaintOpWithFlags {
- public:
- static constexpr PaintOpType kType = PaintOpType::DrawRect;
- static constexpr bool kIsDrawOp = true;
- DrawRectOp(const SkRect& rect, const PaintFlags& flags)
- : PaintOpWithFlags(kType, flags), rect(rect) {}
- static void RasterWithFlags(const DrawRectOp* op,
- const PaintFlags* flags,
- SkCanvas* canvas,
- const PlaybackParams& params);
- bool IsValid() const { return flags.IsValid() && rect.isFinite(); }
- static bool AreEqual(const PaintOp* left, const PaintOp* right);
- HAS_SERIALIZATION_FUNCTIONS();
-
- SkRect rect;
-
- private:
- DrawRectOp() : PaintOpWithFlags(kType) {}
-};
-
-class CC_PAINT_EXPORT DrawRRectOp final : public PaintOpWithFlags {
- public:
- static constexpr PaintOpType kType = PaintOpType::DrawRRect;
- static constexpr bool kIsDrawOp = true;
- DrawRRectOp(const SkRRect& rrect, const PaintFlags& flags)
- : PaintOpWithFlags(kType, flags), rrect(rrect) {}
- static void RasterWithFlags(const DrawRRectOp* op,
- const PaintFlags* flags,
- SkCanvas* canvas,
- const PlaybackParams& params);
- bool IsValid() const { return flags.IsValid() && rrect.isValid(); }
- static bool AreEqual(const PaintOp* left, const PaintOp* right);
- HAS_SERIALIZATION_FUNCTIONS();
-
- SkRRect rrect;
-
- private:
- DrawRRectOp() : PaintOpWithFlags(kType) {}
-};
-
-class CC_PAINT_EXPORT DrawSkottieOp final : public PaintOp {
- public:
- static constexpr PaintOpType kType = PaintOpType::DrawSkottie;
- static constexpr bool kIsDrawOp = true;
- DrawSkottieOp(scoped_refptr<SkottieWrapper> skottie,
- SkRect dst,
- float t,
- SkottieFrameDataMap images,
- const SkottieColorMap& color_map,
- SkottieTextPropertyValueMap text_map);
- ~DrawSkottieOp();
- static void Raster(const DrawSkottieOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params);
- bool IsValid() const {
- return !!skottie && !dst.isEmpty() && t >= 0 && t <= 1.f;
- }
- static bool AreEqual(const PaintOp* left, const PaintOp* right);
- bool HasDiscardableImages() const;
- HAS_SERIALIZATION_FUNCTIONS();
-
- scoped_refptr<SkottieWrapper> skottie;
- SkRect dst;
- float t;
- // Image to use for each asset in this frame of the animation. If an asset is
- // missing, the most recently used image for that asset (from a previous
- // DrawSkottieOp) gets reused when rendering this frame. Given that image
- // assets generally do not change from frame to frame in most animations, that
- // means in practice, this map is often empty.
- SkottieFrameDataMap images;
- // Node name hashes and corresponding colors to use for dynamic coloration.
- SkottieColorMap color_map;
- SkottieTextPropertyValueMap text_map;
-
- private:
- SkottieWrapper::FrameDataFetchResult GetImageAssetForRaster(
- SkCanvas* canvas,
- const PlaybackParams& params,
- SkottieResourceIdHash asset_id,
- float t_frame,
- sk_sp<SkImage>& image_out,
- SkSamplingOptions& sampling_out) const;
-
- DrawSkottieOp();
-};
-
-// TODO(penghuang): Replace DrawTextBlobOp with DrawSlugOp, when GrSlug can be
-// serialized.
-class CC_PAINT_EXPORT DrawTextBlobOp final : public PaintOpWithFlags {
- public:
- static constexpr PaintOpType kType = PaintOpType::DrawTextBlob;
- static constexpr bool kIsDrawOp = true;
- DrawTextBlobOp(sk_sp<SkTextBlob> blob,
- SkScalar x,
- SkScalar y,
- const PaintFlags& flags);
- DrawTextBlobOp(sk_sp<SkTextBlob> blob,
- SkScalar x,
- SkScalar y,
- NodeId node_id,
- const PaintFlags& flags);
- ~DrawTextBlobOp();
- static void RasterWithFlags(const DrawTextBlobOp* op,
- const PaintFlags* flags,
- SkCanvas* canvas,
- const PlaybackParams& params);
- bool IsValid() const { return flags.IsValid(); }
- bool HasDrawTextOps() const { return true; }
- static bool AreEqual(const PaintOp* left, const PaintOp* right);
- HAS_SERIALIZATION_FUNCTIONS();
-
- sk_sp<SkTextBlob> blob;
- sk_sp<GrSlug> slug;
- std::vector<sk_sp<GrSlug>> extra_slugs;
- SkScalar x;
- SkScalar y;
- // This field isn't serialized.
- NodeId node_id = kInvalidNodeId;
-
- private:
- DrawTextBlobOp();
-};
-
-class CC_PAINT_EXPORT NoopOp final : public PaintOp {
- public:
- static constexpr PaintOpType kType = PaintOpType::Noop;
- NoopOp() : PaintOp(kType) {}
- static void Raster(const NoopOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params) {}
- bool IsValid() const { return true; }
- static bool AreEqual(const PaintOp* left, const PaintOp* right);
- HAS_SERIALIZATION_FUNCTIONS();
-};
-
-class CC_PAINT_EXPORT RestoreOp final : public PaintOp {
- public:
- static constexpr PaintOpType kType = PaintOpType::Restore;
- RestoreOp() : PaintOp(kType) {}
- static void Raster(const RestoreOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params);
- bool IsValid() const { return true; }
- static bool AreEqual(const PaintOp* left, const PaintOp* right);
- HAS_SERIALIZATION_FUNCTIONS();
-};
-
-class CC_PAINT_EXPORT RotateOp final : public PaintOp {
- public:
- static constexpr PaintOpType kType = PaintOpType::Rotate;
- explicit RotateOp(SkScalar degrees) : PaintOp(kType), degrees(degrees) {}
- static void Raster(const RotateOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params);
- bool IsValid() const { return true; }
- static bool AreEqual(const PaintOp* left, const PaintOp* right);
- HAS_SERIALIZATION_FUNCTIONS();
-
- SkScalar degrees;
-
- private:
- RotateOp() : PaintOp(kType) {}
-};
-
-class CC_PAINT_EXPORT SaveOp final : public PaintOp {
- public:
- static constexpr PaintOpType kType = PaintOpType::Save;
- SaveOp() : PaintOp(kType) {}
- static void Raster(const SaveOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params);
- bool IsValid() const { return true; }
- static bool AreEqual(const PaintOp* left, const PaintOp* right);
- HAS_SERIALIZATION_FUNCTIONS();
-};
-
-class CC_PAINT_EXPORT SaveLayerOp final : public PaintOpWithFlags {
- public:
- static constexpr PaintOpType kType = PaintOpType::SaveLayer;
- SaveLayerOp(const SkRect* bounds, const PaintFlags* flags)
- : PaintOpWithFlags(kType, flags ? *flags : PaintFlags()),
- bounds(bounds ? *bounds : kUnsetRect) {}
- static void RasterWithFlags(const SaveLayerOp* op,
- const PaintFlags* flags,
- SkCanvas* canvas,
- const PlaybackParams& params);
- bool IsValid() const { return flags.IsValid() && IsValidOrUnsetRect(bounds); }
- static bool AreEqual(const PaintOp* left, const PaintOp* right);
- bool HasNonAAPaint() const { return false; }
- // We simply assume any effects (or even no effects -- just starting an empty
- // transparent layer) would break LCD text or be broken by the flags for
- // SaveLayerAlpha to preserve LCD text.
- bool HasEffectsPreventingLCDTextForSaveLayerAlpha() const { return true; }
- bool HasSaveLayerOps() const { return true; }
- HAS_SERIALIZATION_FUNCTIONS();
-
- SkRect bounds;
-
- private:
- SaveLayerOp() : PaintOpWithFlags(kType) {}
-};
-
-class CC_PAINT_EXPORT SaveLayerAlphaOp final : public PaintOp {
- public:
- static constexpr PaintOpType kType = PaintOpType::SaveLayerAlpha;
- template <class F, class = std::enable_if_t<std::is_same_v<F, float>>>
- SaveLayerAlphaOp(const SkRect* bounds, F alpha)
- : PaintOp(kType), bounds(bounds ? *bounds : kUnsetRect), alpha(alpha) {}
- static void Raster(const SaveLayerAlphaOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params);
- bool IsValid() const { return IsValidOrUnsetRect(bounds); }
- static bool AreEqual(const PaintOp* left, const PaintOp* right);
- bool HasSaveLayerOps() const { return true; }
- bool HasSaveLayerAlphaOps() const { return true; }
- HAS_SERIALIZATION_FUNCTIONS();
-
- SkRect bounds;
- float alpha;
-
- private:
- SaveLayerAlphaOp() : PaintOp(kType) {}
-};
-
-class CC_PAINT_EXPORT ScaleOp final : public PaintOp {
- public:
- static constexpr PaintOpType kType = PaintOpType::Scale;
- ScaleOp(SkScalar sx, SkScalar sy) : PaintOp(kType), sx(sx), sy(sy) {}
- static void Raster(const ScaleOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params);
- bool IsValid() const { return true; }
- static bool AreEqual(const PaintOp* left, const PaintOp* right);
- HAS_SERIALIZATION_FUNCTIONS();
-
- SkScalar sx;
- SkScalar sy;
-
- private:
- ScaleOp() : PaintOp(kType) {}
-};
-
-class CC_PAINT_EXPORT SetMatrixOp final : public PaintOp {
- public:
- static constexpr PaintOpType kType = PaintOpType::SetMatrix;
- 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).
- //
- // TODO(enne): Find some cleaner way to do this, possibly by making
- // all SetMatrix calls Concat??
- static void Raster(const SetMatrixOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params);
- bool IsValid() const { return true; }
- static bool AreEqual(const PaintOp* left, const PaintOp* right);
- HAS_SERIALIZATION_FUNCTIONS();
-
- SkM44 matrix;
-
- private:
- SetMatrixOp() : PaintOp(kType) {}
-};
-
-class CC_PAINT_EXPORT SetNodeIdOp final : public PaintOp {
- public:
- static constexpr PaintOpType kType = PaintOpType::SetNodeId;
- explicit SetNodeIdOp(int node_id) : PaintOp(kType), node_id(node_id) {}
- static void Raster(const SetNodeIdOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params);
- bool IsValid() const { return true; }
- static bool AreEqual(const PaintOp* left, const PaintOp* right);
- HAS_SERIALIZATION_FUNCTIONS();
-
- int node_id;
-
- private:
- SetNodeIdOp() : PaintOp(kType) {}
-};
-
-class CC_PAINT_EXPORT TranslateOp final : public PaintOp {
- public:
- static constexpr PaintOpType kType = PaintOpType::Translate;
- TranslateOp(SkScalar dx, SkScalar dy) : PaintOp(kType), dx(dx), dy(dy) {}
- static void Raster(const TranslateOp* op,
- SkCanvas* canvas,
- const PlaybackParams& params);
- bool IsValid() const { return true; }
- static bool AreEqual(const PaintOp* left, const PaintOp* right);
- HAS_SERIALIZATION_FUNCTIONS();
-
- SkScalar dx;
- SkScalar dy;
-
- private:
- TranslateOp() : PaintOp(kType) {}
-};
-
-#undef HAS_SERIALIZATION_FUNCTIONS
-
-// TODO(vmpstr): Revisit this when sizes of DrawImageRectOp change.
-using LargestPaintOp =
- typename std::conditional<(sizeof(DrawImageRectOp) > sizeof(DrawDRRectOp)),
- DrawImageRectOp,
- DrawDRRectOp>::type;
-
-// Defined outside of the class as this const is used in multiple files.
-static constexpr int kMinNumberOfSlowPathsForMSAA = 6;
-
-class CC_PAINT_EXPORT PaintOpBuffer : public SkRefCnt {
- public:
enum { kInitialBufferSize = 4096 };
- static constexpr size_t PaintOpAlign = 8;
+ static constexpr size_t kPaintOpAlign = 8;
static inline size_t ComputeOpSkip(size_t sizeof_op) {
- return MathUtil::UncheckedRoundUp(sizeof_op, PaintOpBuffer::PaintOpAlign);
+ return MathUtil::UncheckedRoundUp(sizeof_op, kPaintOpAlign);
}
PaintOpBuffer();
PaintOpBuffer(const PaintOpBuffer&) = delete;
+ // `other` will be reset to the initial state.
PaintOpBuffer(PaintOpBuffer&& other);
~PaintOpBuffer() override;
PaintOpBuffer& operator=(const PaintOpBuffer&) = delete;
+ // `other` will be reset in the initial state.
PaintOpBuffer& operator=(PaintOpBuffer&& other);
+ // Resets the PaintOpBuffer to the initial state, except that the current
+ // data buffer is retained.
void Reset();
// Replays the paint op buffer into the canvas.
@@ -1109,12 +183,11 @@ class CC_PAINT_EXPORT PaintOpBuffer : public SkRefCnt {
// overwritten.
bool Deserialize(const volatile void* input,
size_t input_size,
- const PaintOp::DeserializeOptions& options);
+ const DeserializeOptions& options);
- static sk_sp<PaintOpBuffer> MakeFromMemory(
- const volatile void* input,
- size_t input_size,
- const PaintOp::DeserializeOptions& options);
+ static sk_sp<PaintOpBuffer> MakeFromMemory(const volatile void* input,
+ size_t input_size,
+ const DeserializeOptions& options);
// Given the |bounds| of a PaintOpBuffer that would be transformed by |ctm|
// when rendered, compute the bounds needed to raster the buffer at a fixed
@@ -1151,28 +224,30 @@ class CC_PAINT_EXPORT PaintOpBuffer : public SkRefCnt {
bool has_effects_preventing_lcd_text_for_save_layer_alpha() const {
return has_effects_preventing_lcd_text_for_save_layer_alpha_;
}
- bool are_ops_destroyed() const { return are_ops_destroyed_; }
- void MarkOpsDestroyed() { are_ops_destroyed_ = true; }
-
bool NeedsAdditionalInvalidationForLCDText(
const PaintOpBuffer& old_buffer) const;
+ // Resize the PaintOpBuffer to exactly fit the current amount of used space.
+ void ShrinkToFit();
+
+ // Takes the contents of this. The result is shrunk to fit. If the
+ // shrinking-to-fit allocates a new data buffer, this PaintOpBuffer retains
+ // the original data buffer for future use.
+ sk_sp<PaintOpBuffer> MoveRetainingBufferIfPossible();
+
bool operator==(const PaintOpBuffer& other) const;
bool operator!=(const PaintOpBuffer& other) const {
return !(*this == other);
}
- // Resize the PaintOpBuffer to exactly fit the current amount of used space.
- void ShrinkToFit();
-
const PaintOp& GetFirstOp() const {
return reinterpret_cast<const PaintOp&>(*data_);
}
template <typename T, typename... Args>
const T& push(Args&&... args) {
- static_assert(std::is_convertible<T, PaintOp>::value, "T not a PaintOp.");
- static_assert(alignof(T) <= PaintOpAlign, "");
+ static_assert(std::is_base_of<PaintOp, T>::value, "T not a PaintOp.");
+ static_assert(alignof(T) <= kPaintOpAlign, "");
static_assert(sizeof(T) < std::numeric_limits<uint16_t>::max(),
"Cannot fit op code in skip");
uint16_t skip = static_cast<uint16_t>(ComputeOpSkip(sizeof(T)));
@@ -1185,24 +260,7 @@ class CC_PAINT_EXPORT PaintOpBuffer : public SkRefCnt {
return *op;
}
- void UpdateSaveLayerBounds(size_t offset, const SkRect& bounds) {
- CHECK_LT(offset, used_);
- CHECK_LE(offset + sizeof(PaintOp), used_);
-
- auto* op = reinterpret_cast<PaintOp*>(data_.get() + offset);
- switch (op->GetType()) {
- case SaveLayerOp::kType:
- CHECK_LE(offset + sizeof(SaveLayerOp), used_);
- static_cast<SaveLayerOp*>(op)->bounds = bounds;
- break;
- case SaveLayerAlphaOp::kType:
- CHECK_LE(offset + sizeof(SaveLayerAlphaOp), used_);
- static_cast<SaveLayerAlphaOp*>(op)->bounds = bounds;
- break;
- default:
- NOTREACHED();
- }
- }
+ void UpdateSaveLayerBounds(size_t offset, const SkRect& bounds);
template <typename T>
void AnalyzeAddedOp(const T* op) {
@@ -1232,13 +290,9 @@ class CC_PAINT_EXPORT PaintOpBuffer : public SkRefCnt {
template <typename T>
const T* GetOpAtForTesting(size_t index) const {
- size_t i = 0;
- for (PaintOpBuffer::Iterator it(this); it && i <= index; ++it, ++i) {
- if (i == index && it->GetType() == T::kType)
- return static_cast<const T*>(it.get());
- }
- return nullptr;
+ return static_cast<const T*>(GetOpAtForTesting(index, T::kType));
}
+ const PaintOp* GetOpAtForTesting(size_t index, PaintOpType type) const;
size_t GetOpOffsetForTracing(const PaintOp& op) const {
DCHECK_GE(reinterpret_cast<const char*>(&op), data_.get());
@@ -1248,215 +302,25 @@ class CC_PAINT_EXPORT PaintOpBuffer : public SkRefCnt {
return result;
}
- class CC_PAINT_EXPORT Iterator {
- public:
- using value_type = PaintOp;
- explicit Iterator(const PaintOpBuffer* buffer)
- : Iterator(buffer, buffer->data_.get(), 0u) {}
-
- PaintOp* get() const { return reinterpret_cast<PaintOp*>(ptr_); }
- PaintOp* operator->() const { return get(); }
- PaintOp& operator*() const { return *get(); }
- Iterator begin() const { return Iterator(buffer_); }
- Iterator end() const {
- return Iterator(buffer_, buffer_->data_.get() + buffer_->used_,
- buffer_->used_);
- }
- bool operator==(const Iterator& other) const {
- // Not valid to compare iterators on different buffers.
- DCHECK_EQ(other.buffer_, buffer_);
- return other.op_offset_ == op_offset_;
- }
- bool operator!=(const Iterator& other) const { return !(*this == other); }
- Iterator& operator++() {
- DCHECK(*this);
- const PaintOp& op = **this;
- ptr_ += op.skip;
- op_offset_ += op.skip;
-
- CHECK_LE(op_offset_, buffer_->used_);
- return *this;
- }
- explicit operator bool() const { return op_offset_ < buffer_->used_; }
-
- private:
- Iterator(const PaintOpBuffer* buffer, char* ptr, size_t op_offset)
- : buffer_(buffer), ptr_(ptr), op_offset_(op_offset) {
- DCHECK(!buffer->are_ops_destroyed());
- }
-
- // `buffer_` and `ptr_` are not a raw_ptr<...> for performance reasons
- // (based on analysis of sampling profiler data and tab_search:top100:2020).
- RAW_PTR_EXCLUSION const PaintOpBuffer* buffer_ = nullptr;
- RAW_PTR_EXCLUSION char* ptr_ = nullptr;
-
- size_t op_offset_ = 0;
- };
+ class Iterator;
+ class OffsetIterator;
+ class CompositeIterator;
+ class PlaybackFoldingIterator;
- class CC_PAINT_EXPORT OffsetIterator {
- public:
- using value_type = PaintOp;
- // Offsets and paint op buffer must come from the same DisplayItemList.
- OffsetIterator(const PaintOpBuffer* buffer,
- const std::vector<size_t>* offsets)
- : buffer_(buffer), ptr_(buffer_->data_.get()), offsets_(offsets) {
- DCHECK(!buffer->are_ops_destroyed());
- if (!offsets || offsets->empty()) {
- *this = end();
- return;
- }
- op_offset_ = (*offsets)[0];
- ptr_ += op_offset_;
- }
-
- PaintOp* get() const { return reinterpret_cast<PaintOp*>(ptr_); }
- PaintOp* operator->() const { return get(); }
- PaintOp& operator*() const { return *get(); }
- OffsetIterator begin() const { return OffsetIterator(buffer_, offsets_); }
- OffsetIterator end() const {
- return OffsetIterator(buffer_, buffer_->data_.get() + buffer_->used_,
- buffer_->used_, offsets_);
- }
- bool operator==(const OffsetIterator& other) const {
- // Not valid to compare iterators on different buffers.
- DCHECK_EQ(other.buffer_, buffer_);
- return other.op_offset_ == op_offset_;
- }
- bool operator!=(const OffsetIterator& other) const {
- return !(*this == other);
- }
- OffsetIterator& operator++() {
- if (++offsets_index_ >= offsets_->size()) {
- *this = end();
- return *this;
- }
-
- size_t target_offset = (*offsets_)[offsets_index_];
- // Sanity checks.
- CHECK_GE(target_offset, op_offset_);
- // Debugging crbug.com/738182.
- base::debug::Alias(&target_offset);
- CHECK_LT(target_offset, buffer_->used_);
-
- // Advance the iterator to the target offset.
- ptr_ += (target_offset - op_offset_);
- op_offset_ = target_offset;
-
- DCHECK(!*this || (*this)->type <=
- static_cast<uint32_t>(PaintOpType::LastPaintOpType));
- return *this;
- }
-
- explicit operator bool() const { return op_offset_ < buffer_->used_; }
-
- private:
- OffsetIterator(const PaintOpBuffer* buffer,
- char* ptr,
- size_t op_offset,
- const std::vector<size_t>* offsets)
- : buffer_(buffer), ptr_(ptr), offsets_(offsets), op_offset_(op_offset) {
- DCHECK(!buffer->are_ops_destroyed());
- }
-
- // `buffer_`, `ptr_`, and `offsets_` are not a raw_ptr<...> for performance
- // reasons (based on analysis of sampling profiler data and
- // tab_search:top100:2020).
- RAW_PTR_EXCLUSION const PaintOpBuffer* buffer_ = nullptr;
- RAW_PTR_EXCLUSION char* ptr_ = nullptr;
- RAW_PTR_EXCLUSION const std::vector<size_t>* offsets_;
-
- size_t op_offset_ = 0;
- size_t offsets_index_ = 0;
- };
-
- class CC_PAINT_EXPORT CompositeIterator {
- public:
- using value_type = PaintOp;
- // Offsets and paint op buffer must come from the same DisplayItemList.
- CompositeIterator(const PaintOpBuffer* buffer,
- const std::vector<size_t>* offsets);
- CompositeIterator(const CompositeIterator& other);
- CompositeIterator(CompositeIterator&& other);
-
- PaintOp* get() const {
- return absl::visit([](const auto& iter) { return iter.get(); }, iter_);
- }
- PaintOp* operator->() const { return get(); }
- PaintOp& operator*() const { return *get(); }
- CompositeIterator begin() const {
- return absl::holds_alternative<Iterator>(iter_)
- ? CompositeIterator(absl::get<Iterator>(iter_).begin())
- : CompositeIterator(absl::get<OffsetIterator>(iter_).begin());
- }
- CompositeIterator end() const {
- return absl::holds_alternative<Iterator>(iter_)
- ? CompositeIterator(absl::get<Iterator>(iter_).end())
- : CompositeIterator(absl::get<OffsetIterator>(iter_).end());
- }
- bool operator==(const CompositeIterator& other) const {
- return iter_ == other.iter_;
- }
- bool operator!=(const CompositeIterator& other) const {
- return !(*this == other);
- }
- CompositeIterator& operator++() {
- absl::visit([](auto& iter) { ++iter; }, iter_);
- return *this;
- }
- explicit operator bool() const {
- return absl::visit([](const auto& iter) { return !!iter; }, iter_);
- }
-
- private:
- explicit CompositeIterator(OffsetIterator iter) : iter_(std::move(iter)) {}
- explicit CompositeIterator(Iterator iter) : iter_(std::move(iter)) {}
-
- absl::variant<Iterator, OffsetIterator> iter_;
- };
-
- class CC_PAINT_EXPORT PlaybackFoldingIterator {
- public:
- PlaybackFoldingIterator(const PaintOpBuffer* buffer,
- const std::vector<size_t>* offsets);
- ~PlaybackFoldingIterator();
-
- const PaintOp* get() const { return current_op_; }
- const PaintOp* operator->() const { return current_op_; }
- const PaintOp& operator*() const { return *current_op_; }
-
- PlaybackFoldingIterator& operator++() {
- FindNextOp();
- return *this;
- }
-
- explicit operator bool() const { return !!current_op_; }
-
- // Guaranteed to be 255 for all ops without flags.
- uint8_t alpha() const {
- return static_cast<uint8_t>(current_alpha_ * 255.0f);
- }
-
- private:
- void FindNextOp();
- const PaintOp* NextUnfoldedOp();
-
- PaintOpBuffer::CompositeIterator iter_;
-
- // FIFO queue of paint ops that have been peeked at.
- base::StackVector<const PaintOp*, 3> stack_;
- DrawColorOp folded_draw_color_;
-
- // `current_op_` is not a raw_ptr<...> for performance reasons (based on
- // analysis of sampling profiler data and tab_search:top100:2020).
- RAW_PTR_EXCLUSION const PaintOp* current_op_ = nullptr;
-
- float current_alpha_ = 1.0f;
- };
+ // STL-like container support:
+ using value_type = PaintOp;
+ using const_iterator = Iterator;
+ Iterator begin() const;
+ Iterator end() const;
private:
friend class DisplayItemList;
+ friend class PaintOp;
friend class PaintOpBufferOffsetsTest;
friend class SolidColorAnalyzer;
+ using BufferDataPtr = std::unique_ptr<char, base::AlignedFreeDeleter>;
+
+ void DestroyOps();
// Replays the paint op buffer into the canvas. If |indices| is specified, it
// contains indices in an increasing order and only the indices specified in
@@ -1465,11 +329,20 @@ class CC_PAINT_EXPORT PaintOpBuffer : public SkRefCnt {
const PlaybackParams& params,
const std::vector<size_t>* indices) const;
- void ReallocBuffer(size_t new_size);
+ // Creates a new buffer sized to `new_size`, copying the old to the new (if
+ // the old exists). Returns the old buffer.
+ BufferDataPtr ReallocBuffer(size_t new_size);
+
+ // Shrinks the buffer to fit `used_`. Returns the old buffer if this
+ // allocated a new buffer, or nullptr.
+ BufferDataPtr ReallocIfNeededToFit();
+
// Returns the allocated op.
void* AllocatePaintOp(size_t skip);
- std::unique_ptr<char, base::AlignedFreeDeleter> data_;
+ void ResetRetainingBuffer();
+
+ BufferDataPtr data_;
size_t used_ = 0;
size_t reserved_ = 0;
size_t op_count_ = 0;
@@ -1490,7 +363,6 @@ class CC_PAINT_EXPORT PaintOpBuffer : public SkRefCnt {
bool has_save_layer_ops_ : 1;
bool has_save_layer_alpha_ops_ : 1;
bool has_effects_preventing_lcd_text_for_save_layer_alpha_ : 1;
- bool are_ops_destroyed_ : 1;
};
} // namespace cc
diff --git a/chromium/cc/paint/paint_op_buffer_fuzzer.cc b/chromium/cc/paint/paint_op_buffer_fuzzer.cc
index 05c01c8ff3d..cb54c7718c1 100644
--- a/chromium/cc/paint/paint_op_buffer_fuzzer.cc
+++ b/chromium/cc/paint/paint_op_buffer_fuzzer.cc
@@ -75,7 +75,7 @@ void Raster(scoped_refptr<viz::TestContextProvider> context_provider,
SkImageInfo image_info = SkImageInfo::MakeN32(
kRasterDimension, kRasterDimension, kOpaque_SkAlphaType);
- context_provider->BindToCurrentThread();
+ context_provider->BindToCurrentSequence();
sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(
context_provider->GrContext(), SkBudgeted::kYes, image_info);
SkCanvas* canvas = surface->getCanvas();
@@ -95,7 +95,7 @@ void Raster(scoped_refptr<viz::TestContextProvider> context_provider,
std::unique_ptr<char, base::AlignedFreeDeleter> deserialized(
static_cast<char*>(base::AlignedAlloc(
- sizeof(cc::LargestPaintOp), cc::PaintOpBuffer::PaintOpAlign)));
+ sizeof(cc::LargestPaintOp), cc::PaintOpBuffer::kPaintOpAlign)));
size_t bytes_read = 0;
cc::PaintOp* deserialized_op = cc::PaintOp::Deserialize(
data, size, deserialized.get(), sizeof(cc::LargestPaintOp), &bytes_read,
@@ -148,14 +148,14 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
}
auto context_provider_no_support = viz::TestContextProvider::Create();
- context_provider_no_support->BindToCurrentThread();
+ context_provider_no_support->BindToCurrentSequence();
CHECK(!context_provider_no_support->GrContext()->supportsDistanceFieldText());
Raster(context_provider_no_support, font_manager->strike_client(),
&paint_cache, data, size);
auto context_provider_with_support = viz::TestContextProvider::Create(
std::string("GL_OES_standard_derivatives"));
- context_provider_with_support->BindToCurrentThread();
+ context_provider_with_support->BindToCurrentSequence();
CHECK(
context_provider_with_support->GrContext()->supportsDistanceFieldText());
Raster(context_provider_with_support, font_manager->strike_client(),
diff --git a/chromium/cc/paint/paint_op_buffer_iterator.cc b/chromium/cc/paint/paint_op_buffer_iterator.cc
new file mode 100644
index 00000000000..b3e46ac2b44
--- /dev/null
+++ b/chromium/cc/paint/paint_op_buffer_iterator.cc
@@ -0,0 +1,136 @@
+// Copyright 2017 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/paint/paint_op_buffer_iterator.h"
+
+namespace cc {
+
+namespace {
+
+// When |op| is a nested PaintOpBuffer, this returns the PaintOp inside
+// that buffer if the buffer contains a single drawing op, otherwise it
+// returns null. This searches recursively if the PaintOpBuffer contains only
+// another PaintOpBuffer.
+static const PaintOp* GetNestedSingleDrawingOp(const PaintOp* op) {
+ if (!op->IsDrawOp())
+ return nullptr;
+ while (op->GetType() == PaintOpType::DrawRecord) {
+ auto* draw_record_op = static_cast<const DrawRecordOp*>(op);
+ if (draw_record_op->record->size() > 1) {
+ // If there's more than one op, then we need to keep the
+ // SaveLayer.
+ return nullptr;
+ }
+
+ // Recurse into the single-op DrawRecordOp and make sure it's a
+ // drawing op.
+ op = &draw_record_op->record->GetFirstOp();
+ if (!op->IsDrawOp())
+ return nullptr;
+ }
+
+ return op;
+}
+
+} // anonymous namespace
+
+PaintOpBuffer::CompositeIterator::CompositeIterator(
+ const PaintOpBuffer* buffer,
+ const std::vector<size_t>* offsets)
+ : iter_(offsets == nullptr ? absl::variant<Iterator, OffsetIterator>(
+ absl::in_place_type<Iterator>,
+ buffer)
+ : absl::variant<Iterator, OffsetIterator>(
+ absl::in_place_type<OffsetIterator>,
+ buffer,
+ offsets)) {}
+
+PaintOpBuffer::CompositeIterator::CompositeIterator(
+ const CompositeIterator& other) = default;
+PaintOpBuffer::CompositeIterator::CompositeIterator(CompositeIterator&& other) =
+ default;
+
+PaintOpBuffer::PlaybackFoldingIterator::PlaybackFoldingIterator(
+ const PaintOpBuffer* buffer,
+ const std::vector<size_t>* offsets)
+ : iter_(buffer, offsets),
+ folded_draw_color_(SkColors::kTransparent, SkBlendMode::kSrcOver) {
+ FindNextOp();
+}
+
+PaintOpBuffer::PlaybackFoldingIterator::~PlaybackFoldingIterator() = default;
+
+void PaintOpBuffer::PlaybackFoldingIterator::FindNextOp() {
+ current_alpha_ = 1.0f;
+ for (current_op_ = NextUnfoldedOp(); current_op_;
+ current_op_ = NextUnfoldedOp()) {
+ if (current_op_->GetType() != PaintOpType::SaveLayerAlpha)
+ break;
+ const PaintOp* second = NextUnfoldedOp();
+ if (!second)
+ break;
+
+ if (second->GetType() == PaintOpType::Restore) {
+ // Drop a SaveLayerAlpha/Restore combo.
+ continue;
+ }
+
+ // Find a nested drawing PaintOp to replace |second| if possible, while
+ // holding onto the pointer to |second| in case we can't find a nested
+ // drawing op to replace it with.
+ const PaintOp* draw_op = GetNestedSingleDrawingOp(second);
+
+ const PaintOp* third = nullptr;
+ if (draw_op) {
+ third = NextUnfoldedOp();
+ if (third && third->GetType() == PaintOpType::Restore) {
+ auto* save_op = static_cast<const SaveLayerAlphaOp*>(current_op_);
+ if (draw_op->IsPaintOpWithFlags() &&
+ // SkPaint::drawTextBlob() applies alpha on each glyph so we don't
+ // fold SaveLayerAlpha into DrwaTextBlob to ensure correct alpha
+ // even if some glyphs overlap.
+ draw_op->GetType() != PaintOpType::DrawTextBlob) {
+ auto* flags_op = static_cast<const PaintOpWithFlags*>(draw_op);
+ if (flags_op->flags.SupportsFoldingAlpha()) {
+ current_alpha_ = save_op->alpha;
+ current_op_ = draw_op;
+ break;
+ }
+ } else if (draw_op->GetType() == PaintOpType::DrawColor &&
+ static_cast<const DrawColorOp*>(draw_op)->mode ==
+ SkBlendMode::kSrcOver) {
+ auto* draw_color_op = static_cast<const DrawColorOp*>(draw_op);
+ SkColor4f color = draw_color_op->color;
+ folded_draw_color_.color = {color.fR, color.fG, color.fB,
+ save_op->alpha * color.fA};
+ current_op_ = &folded_draw_color_;
+ break;
+ }
+ }
+ }
+
+ // If we get here, then we could not find a foldable sequence after
+ // this SaveLayerAlpha, so store any peeked at ops.
+ stack_->push_back(second);
+ if (third)
+ stack_->push_back(third);
+ break;
+ }
+}
+
+const PaintOp* PaintOpBuffer::PlaybackFoldingIterator::NextUnfoldedOp() {
+ if (stack_->size()) {
+ const PaintOp* op = stack_->front();
+ // Shift paintops forward.
+ stack_->erase(stack_->begin());
+ return op;
+ }
+ if (!iter_)
+ return nullptr;
+ const PaintOp& op = *iter_;
+ ++iter_;
+ return &op;
+}
+
+} // namespace cc
diff --git a/chromium/cc/paint/paint_op_buffer_iterator.h b/chromium/cc/paint/paint_op_buffer_iterator.h
new file mode 100644
index 00000000000..c9386be6731
--- /dev/null
+++ b/chromium/cc/paint/paint_op_buffer_iterator.h
@@ -0,0 +1,218 @@
+// Copyright 2017 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_PAINT_PAINT_OP_BUFFER_ITERATOR_H_
+#define CC_PAINT_PAINT_OP_BUFFER_ITERATOR_H_
+
+#include <utility>
+#include <vector>
+
+#include "cc/paint/paint_op.h"
+#include "cc/paint/paint_op_buffer.h"
+
+namespace cc {
+
+class CC_PAINT_EXPORT PaintOpBuffer::Iterator {
+ public:
+ using value_type = PaintOp;
+ explicit Iterator(const PaintOpBuffer* buffer)
+ : Iterator(buffer, buffer->data_.get(), 0u) {}
+
+ const PaintOp* get() const { return reinterpret_cast<const PaintOp*>(ptr_); }
+ const PaintOp* operator->() const { return get(); }
+ const PaintOp& operator*() const { return *get(); }
+ Iterator begin() const { return Iterator(buffer_); }
+ Iterator end() const {
+ return Iterator(buffer_, buffer_->data_.get() + buffer_->used_,
+ buffer_->used_);
+ }
+ bool operator==(const Iterator& other) const {
+ // Not valid to compare iterators on different buffers.
+ DCHECK_EQ(other.buffer_, buffer_);
+ return other.op_offset_ == op_offset_;
+ }
+ bool operator!=(const Iterator& other) const { return !(*this == other); }
+ Iterator& operator++() {
+ DCHECK(*this);
+ const PaintOp& op = **this;
+ ptr_ += op.skip;
+ op_offset_ += op.skip;
+
+ CHECK_LE(op_offset_, buffer_->used_);
+ return *this;
+ }
+ explicit operator bool() const { return op_offset_ < buffer_->used_; }
+
+ private:
+ Iterator(const PaintOpBuffer* buffer, const char* ptr, size_t op_offset)
+ : buffer_(buffer), ptr_(ptr), op_offset_(op_offset) {}
+
+ // `buffer_` and `ptr_` are not a raw_ptr<...> for performance reasons
+ // (based on analysis of sampling profiler data and tab_search:top100:2020).
+ RAW_PTR_EXCLUSION const PaintOpBuffer* buffer_ = nullptr;
+ RAW_PTR_EXCLUSION const char* ptr_ = nullptr;
+
+ size_t op_offset_ = 0;
+};
+
+class CC_PAINT_EXPORT PaintOpBuffer::OffsetIterator {
+ public:
+ using value_type = PaintOp;
+ // Offsets and paint op buffer must come from the same DisplayItemList.
+ OffsetIterator(const PaintOpBuffer* buffer,
+ const std::vector<size_t>* offsets)
+ : buffer_(buffer), ptr_(buffer_->data_.get()), offsets_(offsets) {
+ if (!offsets || offsets->empty()) {
+ *this = end();
+ return;
+ }
+ op_offset_ = (*offsets)[0];
+ ptr_ += op_offset_;
+ }
+
+ const PaintOp* get() const { return reinterpret_cast<const PaintOp*>(ptr_); }
+ const PaintOp* operator->() const { return get(); }
+ const PaintOp& operator*() const { return *get(); }
+ OffsetIterator begin() const { return OffsetIterator(buffer_, offsets_); }
+ OffsetIterator end() const {
+ return OffsetIterator(buffer_, buffer_->data_.get() + buffer_->used_,
+ buffer_->used_, offsets_);
+ }
+ bool operator==(const OffsetIterator& other) const {
+ // Not valid to compare iterators on different buffers.
+ DCHECK_EQ(other.buffer_, buffer_);
+ return other.op_offset_ == op_offset_;
+ }
+ bool operator!=(const OffsetIterator& other) const {
+ return !(*this == other);
+ }
+ OffsetIterator& operator++() {
+ if (++offsets_index_ >= offsets_->size()) {
+ *this = end();
+ return *this;
+ }
+
+ size_t target_offset = (*offsets_)[offsets_index_];
+ // Sanity checks.
+ CHECK_GE(target_offset, op_offset_);
+ // Debugging crbug.com/738182.
+ base::debug::Alias(&target_offset);
+ CHECK_LT(target_offset, buffer_->used_);
+
+ // Advance the iterator to the target offset.
+ ptr_ += (target_offset - op_offset_);
+ op_offset_ = target_offset;
+
+ DCHECK(!*this || (*this)->type <=
+ static_cast<uint32_t>(PaintOpType::LastPaintOpType));
+ return *this;
+ }
+
+ explicit operator bool() const { return op_offset_ < buffer_->used_; }
+
+ private:
+ OffsetIterator(const PaintOpBuffer* buffer,
+ const char* ptr,
+ size_t op_offset,
+ const std::vector<size_t>* offsets)
+ : buffer_(buffer), ptr_(ptr), offsets_(offsets), op_offset_(op_offset) {}
+
+ // `buffer_`, `ptr_`, and `offsets_` are not a raw_ptr<...> for performance
+ // reasons (based on analysis of sampling profiler data and
+ // tab_search:top100:2020).
+ RAW_PTR_EXCLUSION const PaintOpBuffer* buffer_ = nullptr;
+ RAW_PTR_EXCLUSION const char* ptr_ = nullptr;
+ RAW_PTR_EXCLUSION const std::vector<size_t>* offsets_;
+
+ size_t op_offset_ = 0;
+ size_t offsets_index_ = 0;
+};
+
+class CC_PAINT_EXPORT PaintOpBuffer::CompositeIterator {
+ public:
+ using value_type = PaintOp;
+ // Offsets and paint op buffer must come from the same DisplayItemList.
+ CompositeIterator(const PaintOpBuffer* buffer,
+ const std::vector<size_t>* offsets);
+ CompositeIterator(const CompositeIterator& other);
+ CompositeIterator(CompositeIterator&& other);
+
+ const PaintOp* get() const {
+ return absl::visit([](const auto& iter) { return iter.get(); }, iter_);
+ }
+ const PaintOp* operator->() const { return get(); }
+ const PaintOp& operator*() const { return *get(); }
+ CompositeIterator begin() const {
+ return absl::holds_alternative<Iterator>(iter_)
+ ? CompositeIterator(absl::get<Iterator>(iter_).begin())
+ : CompositeIterator(absl::get<OffsetIterator>(iter_).begin());
+ }
+ CompositeIterator end() const {
+ return absl::holds_alternative<Iterator>(iter_)
+ ? CompositeIterator(absl::get<Iterator>(iter_).end())
+ : CompositeIterator(absl::get<OffsetIterator>(iter_).end());
+ }
+ bool operator==(const CompositeIterator& other) const {
+ return iter_ == other.iter_;
+ }
+ bool operator!=(const CompositeIterator& other) const {
+ return !(*this == other);
+ }
+ CompositeIterator& operator++() {
+ absl::visit([](auto& iter) { ++iter; }, iter_);
+ return *this;
+ }
+ explicit operator bool() const {
+ return absl::visit([](const auto& iter) { return !!iter; }, iter_);
+ }
+
+ private:
+ explicit CompositeIterator(OffsetIterator iter) : iter_(std::move(iter)) {}
+ explicit CompositeIterator(Iterator iter) : iter_(std::move(iter)) {}
+
+ absl::variant<Iterator, OffsetIterator> iter_;
+};
+
+class CC_PAINT_EXPORT PaintOpBuffer::PlaybackFoldingIterator {
+ public:
+ PlaybackFoldingIterator(const PaintOpBuffer* buffer,
+ const std::vector<size_t>* offsets);
+ ~PlaybackFoldingIterator();
+
+ const PaintOp* get() const { return current_op_; }
+ const PaintOp* operator->() const { return current_op_; }
+ const PaintOp& operator*() const { return *current_op_; }
+
+ PlaybackFoldingIterator& operator++() {
+ FindNextOp();
+ return *this;
+ }
+
+ explicit operator bool() const { return !!current_op_; }
+
+ // Guaranteed to be 255 for all ops without flags.
+ uint8_t alpha() const {
+ return static_cast<uint8_t>(current_alpha_ * 255.0f);
+ }
+
+ private:
+ void FindNextOp();
+ const PaintOp* NextUnfoldedOp();
+
+ PaintOpBuffer::CompositeIterator iter_;
+
+ // FIFO queue of paint ops that have been peeked at.
+ base::StackVector<const PaintOp*, 3> stack_;
+ DrawColorOp folded_draw_color_;
+
+ // `current_op_` is not a raw_ptr<...> for performance reasons (based on
+ // analysis of sampling profiler data and tab_search:top100:2020).
+ RAW_PTR_EXCLUSION const PaintOp* current_op_ = nullptr;
+
+ float current_alpha_ = 1.0f;
+};
+
+} // namespace cc
+
+#endif // CC_PAINT_PAINT_OP_BUFFER_ITERATOR_H_
diff --git a/chromium/cc/paint/paint_op_buffer_serializer.cc b/chromium/cc/paint/paint_op_buffer_serializer.cc
index ad9498a817d..b63a7f17d1a 100644
--- a/chromium/cc/paint/paint_op_buffer_serializer.cc
+++ b/chromium/cc/paint/paint_op_buffer_serializer.cc
@@ -12,6 +12,7 @@
#include "base/bind.h"
#include "base/trace_event/trace_event.h"
#include "cc/paint/clear_for_opaque_raster.h"
+#include "cc/paint/paint_op_buffer_iterator.h"
#include "cc/paint/scoped_raster_flags.h"
#include "skia/ext/legacy_display_globals.h"
#include "third_party/skia/include/core/SkColorSpace.h"
@@ -73,25 +74,6 @@ void PaintOpBufferSerializer::Serialize(const PaintOpBuffer* buffer,
RestoreToCount(canvas.get(), saveCount, params);
}
-void PaintOpBufferSerializer::SerializeAndDestroy(
- PaintOpBuffer* buffer,
- const std::vector<size_t>* offsets,
- const Preamble& preamble) {
- std::unique_ptr<SkCanvas> canvas = MakeAnalysisCanvas(options_);
-
- // These PlaybackParams use the initial (identity) canvas matrix, as they are
- // only used for serializing the preamble and the initial save / final restore
- // SerializeBuffer will create its own PlaybackParams based on the
- // post-preamble canvas.
- PlaybackParams params = MakeParams(canvas.get());
-
- int saveCount = canvas->getSaveCount();
- Save(canvas.get(), params);
- SerializePreamble(canvas.get(), preamble, params);
- SerializeBufferAndDestroy(canvas.get(), buffer, offsets);
- RestoreToCount(canvas.get(), saveCount, params);
-}
-
void PaintOpBufferSerializer::Serialize(const PaintOpBuffer* buffer) {
std::unique_ptr<SkCanvas> canvas = MakeAnalysisCanvas(options_);
SerializeBuffer(canvas.get(), buffer, nullptr);
@@ -203,7 +185,7 @@ void PaintOpBufferSerializer::SerializePreamble(SkCanvas* canvas,
bool PaintOpBufferSerializer::WillSerializeNextOp(const PaintOp& op,
SkCanvas* canvas,
- PlaybackParams params,
+ const PlaybackParams& params,
uint8_t alpha) {
// Skip ops outside the current clip if they have images. This saves
// performing an unnecessary expensive decode.
@@ -288,31 +270,6 @@ void PaintOpBufferSerializer::SerializeBuffer(
}
}
-void PaintOpBufferSerializer::SerializeBufferAndDestroy(
- SkCanvas* canvas,
- PaintOpBuffer* buffer,
- const std::vector<size_t>* offsets) {
- DCHECK(buffer);
- // This updates the original_ctm to reflect the canvas transformation at
- // start of this call to SerializeBuffer.
- PlaybackParams params = MakeParams(canvas);
- bool destroy_op_only = false;
-
- for (PaintOpBuffer::PlaybackFoldingIterator iter(buffer, offsets); iter;
- ++iter) {
- PaintOp& op = const_cast<PaintOp&>(*iter);
- if (!destroy_op_only) {
- // If serialization failed, destroy PaintOps in |buffer|.
- destroy_op_only = !WillSerializeNextOp(op, canvas, params, iter.alpha());
- }
- op.DestroyThis();
- }
-
- // Each PaintOp in |buffer| is destroyed. Update the flag |ops_destroyed| to
- // true, so it skip calling destruction in PaintOpsBuffer::Reset().
- const_cast<PaintOpBuffer*>(buffer)->MarkOpsDestroyed();
-}
-
bool PaintOpBufferSerializer::SerializeOpWithFlags(
SkCanvas* canvas,
const PaintOpWithFlags& flags_op,
@@ -353,7 +310,7 @@ bool PaintOpBufferSerializer::SerializeOp(SkCanvas* canvas,
}
DCHECK_GE(bytes, 4u);
- DCHECK_EQ(bytes % PaintOpBuffer::PaintOpAlign, 0u);
+ DCHECK_EQ(bytes % PaintOpBuffer::kPaintOpAlign, 0u);
return true;
}
diff --git a/chromium/cc/paint/paint_op_buffer_serializer.h b/chromium/cc/paint/paint_op_buffer_serializer.h
index 25861c85320..2a14de4d028 100644
--- a/chromium/cc/paint/paint_op_buffer_serializer.h
+++ b/chromium/cc/paint/paint_op_buffer_serializer.h
@@ -9,8 +9,8 @@
#include <vector>
#include "base/memory/raw_ptr.h"
+#include "cc/paint/paint_op.h"
#include "cc/paint/paint_op_buffer.h"
-
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/private/chromium/SkChromeRemoteGlyphCache.h"
#include "ui/gfx/geometry/rect_f.h"
@@ -58,11 +58,6 @@ class CC_PAINT_EXPORT PaintOpBufferSerializer {
void Serialize(const PaintOpBuffer* buffer,
const std::vector<size_t>* offsets,
const Preamble& preamble);
- // Sereialize the buffer as |Serialize| with a preamble. This function also
- // destroys the PaintOps in |buffer| after serialization.
- void SerializeAndDestroy(PaintOpBuffer* buffer,
- const std::vector<size_t>* offsets,
- const Preamble& preamble);
// Serialize the buffer without a preamble. This function serializes the whole
// buffer without any extra ops added. No clearing is done. This should
// generally be used for internal PaintOpBuffers that want to be sent as-is.
@@ -86,14 +81,11 @@ class CC_PAINT_EXPORT PaintOpBufferSerializer {
void SerializeBuffer(SkCanvas* canvas,
const PaintOpBuffer* buffer,
const std::vector<size_t>* offsets);
- void SerializeBufferAndDestroy(SkCanvas* canvas,
- PaintOpBuffer* buffer,
- const std::vector<size_t>* offsets);
// Returns whether searilization of |op| succeeded and we need to serialize
// the next PaintOp in the PaintOpBuffer.
bool WillSerializeNextOp(const PaintOp& op,
SkCanvas* canvas,
- PlaybackParams params,
+ const PlaybackParams& params,
uint8_t alpha);
bool SerializeOpWithFlags(SkCanvas* canvas,
const PaintOpWithFlags& flags_op,
diff --git a/chromium/cc/paint/paint_op_buffer_unittest.cc b/chromium/cc/paint/paint_op_buffer_unittest.cc
index d303ed7918e..ecb25946845 100644
--- a/chromium/cc/paint/paint_op_buffer_unittest.cc
+++ b/chromium/cc/paint/paint_op_buffer_unittest.cc
@@ -5,6 +5,7 @@
#include "cc/paint/paint_op_buffer.h"
#include <algorithm>
+#include <string>
#include "base/bind.h"
#include "base/memory/raw_ptr.h"
@@ -17,6 +18,7 @@
#include "cc/paint/image_transfer_cache_entry.h"
#include "cc/paint/paint_flags.h"
#include "cc/paint/paint_image_builder.h"
+#include "cc/paint/paint_op_buffer_iterator.h"
#include "cc/paint/paint_op_buffer_serializer.h"
#include "cc/paint/paint_op_reader.h"
#include "cc/paint/paint_op_writer.h"
@@ -26,7 +28,7 @@
#include "cc/paint/skottie_wrapper.h"
#include "cc/paint/transfer_cache_entry.h"
#include "cc/test/lottie_test_data.h"
-#include "cc/test/paint_op_helper.h"
+#include "cc/test/paint_op_matchers.h"
#include "cc/test/skia_common.h"
#include "cc/test/test_options_provider.h"
#include "cc/test/test_paint_worklet_input.h"
@@ -42,28 +44,30 @@
#include "third_party/skia/include/private/chromium/SkChromeRemoteGlyphCache.h"
#include "ui/gfx/geometry/test/geometry_util.h"
+namespace cc {
+namespace {
+
using ::testing::_;
+using ::testing::AllOf;
using ::testing::AtLeast;
using ::testing::Contains;
+using ::testing::Each;
using ::testing::ElementsAre;
+using ::testing::Eq;
using ::testing::Key;
+using ::testing::Le;
+using ::testing::Matcher;
using ::testing::Mock;
using ::testing::NiceMock;
using ::testing::NotNull;
+using ::testing::Pointee;
+using ::testing::ResultOf;
-namespace cc {
-namespace {
// An arbitrary size guaranteed to fit the size of any serialized op in this
// unit test. This can also be used for deserialized op size safely in this
// unit test suite as generally deserialized ops are smaller.
static constexpr size_t kBufferBytesPerOp = 1000 + sizeof(LargestPaintOp);
-template <typename T>
-void ValidateOps(PaintOpBuffer* buffer) {
- // Make sure all test data is valid before serializing it.
- for (const PaintOp& op : PaintOpBuffer::Iterator(buffer))
- EXPECT_TRUE(static_cast<const T&>(op).IsValid());
-}
} // namespace
class PaintOpSerializationTestUtils {
@@ -133,28 +137,22 @@ class PaintOpAppendTest : public ::testing::Test {
}
void VerifyOps(PaintOpBuffer* buffer) {
- EXPECT_EQ(buffer->size(), 4u);
-
- PaintOpBuffer::Iterator iter(buffer);
- ASSERT_EQ(iter->GetType(), PaintOpType::SaveLayer);
- const SaveLayerOp& save_op = static_cast<const SaveLayerOp&>(*iter);
- EXPECT_EQ(save_op.bounds, rect_);
- EXPECT_EQ(save_op.flags, flags_);
- ++iter;
-
- ASSERT_EQ(iter->GetType(), PaintOpType::Save);
- ++iter;
-
- ASSERT_EQ(iter->GetType(), PaintOpType::DrawColor);
- const DrawColorOp& op = static_cast<const DrawColorOp&>(*iter);
- EXPECT_EQ(op.color, draw_color_);
- EXPECT_EQ(op.mode, blend_);
- ++iter;
-
- ASSERT_EQ(iter->GetType(), PaintOpType::Restore);
- ++iter;
+ EXPECT_THAT(*buffer,
+ PaintOpsAreEq(SaveLayerOp(&rect_, &flags_), SaveOp(),
+ DrawColorOp(draw_color_, blend_), RestoreOp()));
+ }
- EXPECT_FALSE(iter);
+ void CheckInitialState(PaintOpBuffer* buffer, bool expect_empty_buffer) {
+ EXPECT_FALSE(buffer->has_draw_ops());
+ EXPECT_FALSE(buffer->has_save_layer_ops());
+ EXPECT_EQ(0u, buffer->size());
+ EXPECT_EQ(0u, buffer->total_op_count());
+ EXPECT_EQ(0u, buffer->next_op_offset());
+ EXPECT_FALSE(PaintOpBuffer::Iterator(buffer));
+ if (expect_empty_buffer) {
+ EXPECT_EQ(0u, buffer->paint_ops_size());
+ EXPECT_EQ(sizeof(PaintOpBuffer), buffer->bytes_used());
+ }
}
private:
@@ -170,6 +168,7 @@ TEST_F(PaintOpAppendTest, SimpleAppend) {
VerifyOps(&buffer);
buffer.Reset();
+ CheckInitialState(&buffer, false);
PushOps(&buffer);
VerifyOps(&buffer);
}
@@ -183,8 +182,7 @@ TEST_F(PaintOpAppendTest, MoveThenDestruct) {
VerifyOps(&destination);
// Original should be empty, and safe to destruct.
- EXPECT_EQ(original.size(), 0u);
- EXPECT_EQ(original.bytes_used(), sizeof(PaintOpBuffer));
+ CheckInitialState(&original, true);
}
TEST_F(PaintOpAppendTest, MoveThenDestructOperatorEq) {
@@ -197,9 +195,7 @@ TEST_F(PaintOpAppendTest, MoveThenDestructOperatorEq) {
VerifyOps(&destination);
// Original should be empty, and safe to destruct.
- EXPECT_EQ(original.size(), 0u);
- EXPECT_EQ(original.bytes_used(), sizeof(PaintOpBuffer));
- EXPECT_FALSE(PaintOpBuffer::Iterator(&original));
+ CheckInitialState(&original, true);
}
TEST_F(PaintOpAppendTest, MoveThenReappend) {
@@ -1260,7 +1256,7 @@ class SimpleSerializer {
bytes_written_[i] = 0;
size_t op_idx = 0;
- for (const PaintOp& op : PaintOpBuffer::Iterator(&buffer)) {
+ for (const PaintOp& op : buffer) {
size_t bytes_written = op.Serialize(current_, remaining_,
options_provider_.serialize_options(),
nullptr, SkM44(), SkM44());
@@ -1278,8 +1274,9 @@ class SimpleSerializer {
// Number of bytes bytes_written must be a multiple of PaintOpAlign
// unless the buffer is filled entirely.
- if (remaining_ != 0u)
- DCHECK_EQ(0u, bytes_written % PaintOpBuffer::PaintOpAlign);
+ if (remaining_ != 0u) {
+ DCHECK_EQ(0u, bytes_written % PaintOpBuffer::kPaintOpAlign);
+ }
}
}
@@ -1353,7 +1350,7 @@ class DeserializerIterator {
remaining_(remaining),
options_(options) {
data_.reset(static_cast<char*>(base::AlignedAlloc(
- sizeof(LargestPaintOp), PaintOpBuffer::PaintOpAlign)));
+ sizeof(LargestPaintOp), PaintOpBuffer::kPaintOpAlign)));
DeserializeCurrentOp();
}
@@ -1392,7 +1389,7 @@ void PushAnnotateOps(PaintOpBuffer* buffer) {
test_rects[1], nullptr);
buffer->push<AnnotateOp>(PaintCanvas::AnnotationType::NAMED_DESTINATION,
test_rects[2], SkData::MakeEmpty());
- ValidateOps<AnnotateOp>(buffer);
+ EXPECT_THAT(*buffer, Each(PaintOpIs<AnnotateOp>()));
}
void PushClipPathOps(PaintOpBuffer* buffer) {
@@ -1401,7 +1398,7 @@ void PushClipPathOps(PaintOpBuffer* buffer) {
buffer->push<ClipPathOp>(test_paths[i], op, /*antialias=*/!!(i % 2),
UsePaintCache::kDisabled);
}
- ValidateOps<ClipPathOp>(buffer);
+ EXPECT_THAT(*buffer, Each(PaintOpIs<ClipPathOp>()));
}
void PushClipRectOps(PaintOpBuffer* buffer) {
@@ -1410,7 +1407,7 @@ void PushClipRectOps(PaintOpBuffer* buffer) {
bool antialias = !!(i % 3);
buffer->push<ClipRectOp>(test_rects[i], op, antialias);
}
- ValidateOps<ClipRectOp>(buffer);
+ EXPECT_THAT(*buffer, Each(PaintOpIs<ClipRectOp>()));
}
void PushClipRRectOps(PaintOpBuffer* buffer) {
@@ -1419,26 +1416,26 @@ void PushClipRRectOps(PaintOpBuffer* buffer) {
bool antialias = !!(i % 3);
buffer->push<ClipRRectOp>(test_rrects[i], op, antialias);
}
- ValidateOps<ClipRRectOp>(buffer);
+ EXPECT_THAT(*buffer, Each(PaintOpIs<ClipRRectOp>()));
}
void PushConcatOps(PaintOpBuffer* buffer) {
for (auto& test_matrix : test_matrices)
buffer->push<ConcatOp>(test_matrix);
- ValidateOps<ConcatOp>(buffer);
+ EXPECT_THAT(*buffer, Each(PaintOpIs<ConcatOp>()));
}
void PushCustomDataOps(PaintOpBuffer* buffer) {
for (uint32_t test_id : test_ids)
buffer->push<CustomDataOp>(test_id);
- ValidateOps<CustomDataOp>(buffer);
+ EXPECT_THAT(*buffer, Each(PaintOpIs<CustomDataOp>()));
}
void PushDrawColorOps(PaintOpBuffer* buffer) {
for (size_t i = 0; i < test_colors.size(); ++i) {
buffer->push<DrawColorOp>(test_colors[i], static_cast<SkBlendMode>(i));
}
- ValidateOps<DrawColorOp>(buffer);
+ EXPECT_THAT(*buffer, Each(PaintOpIs<DrawColorOp>()));
}
void PushDrawDRRectOps(PaintOpBuffer* buffer) {
@@ -1447,7 +1444,7 @@ void PushDrawDRRectOps(PaintOpBuffer* buffer) {
buffer->push<DrawDRRectOp>(test_rrects[i], test_rrects[i + 1],
test_flags[i]);
}
- ValidateOps<DrawDRRectOp>(buffer);
+ EXPECT_THAT(*buffer, Each(PaintOpIs<DrawDRRectOp>()));
}
void PushDrawImageOps(PaintOpBuffer* buffer) {
@@ -1464,7 +1461,7 @@ void PushDrawImageOps(PaintOpBuffer* buffer) {
// 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]);
- ValidateOps<DrawImageOp>(buffer);
+ EXPECT_THAT(*buffer, Each(PaintOpIs<DrawImageOp>()));
}
void PushDrawImageRectOps(PaintOpBuffer* buffer) {
@@ -1484,14 +1481,14 @@ void PushDrawImageRectOps(PaintOpBuffer* buffer) {
// Test optional flags.
buffer->push<DrawImageRectOp>(test_images[0], test_rects[0], test_rects[1],
SkCanvas::kStrict_SrcRectConstraint);
- ValidateOps<DrawImageRectOp>(buffer);
+ EXPECT_THAT(*buffer, Each(PaintOpIs<DrawImageRectOp>()));
}
void PushDrawIRectOps(PaintOpBuffer* buffer) {
size_t len = std::min(test_irects.size(), test_flags.size());
for (size_t i = 0; i < len; ++i)
buffer->push<DrawIRectOp>(test_irects[i], test_flags[i]);
- ValidateOps<DrawIRectOp>(buffer);
+ EXPECT_THAT(*buffer, Each(PaintOpIs<DrawIRectOp>()));
}
void PushDrawLineOps(PaintOpBuffer* buffer) {
@@ -1501,14 +1498,14 @@ void PushDrawLineOps(PaintOpBuffer* buffer) {
test_floats[i + 2], test_floats[i + 3],
test_flags[i]);
}
- ValidateOps<DrawLineOp>(buffer);
+ EXPECT_THAT(*buffer, Each(PaintOpIs<DrawLineOp>()));
}
void PushDrawOvalOps(PaintOpBuffer* buffer) {
size_t len = std::min(test_paths.size(), test_flags.size());
for (size_t i = 0; i < len; ++i)
buffer->push<DrawOvalOp>(test_rects[i], test_flags[i]);
- ValidateOps<DrawOvalOp>(buffer);
+ EXPECT_THAT(*buffer, Each(PaintOpIs<DrawOvalOp>()));
}
void PushDrawPathOps(PaintOpBuffer* buffer) {
@@ -1516,21 +1513,21 @@ void PushDrawPathOps(PaintOpBuffer* buffer) {
for (size_t i = 0; i < len; ++i)
buffer->push<DrawPathOp>(test_paths[i], test_flags[i],
UsePaintCache::kDisabled);
- ValidateOps<DrawPathOp>(buffer);
+ EXPECT_THAT(*buffer, Each(PaintOpIs<DrawPathOp>()));
}
void PushDrawRectOps(PaintOpBuffer* buffer) {
size_t len = std::min(test_rects.size(), test_flags.size());
for (size_t i = 0; i < len; ++i)
buffer->push<DrawRectOp>(test_rects[i], test_flags[i]);
- ValidateOps<DrawRectOp>(buffer);
+ EXPECT_THAT(*buffer, Each(PaintOpIs<DrawRectOp>()));
}
void PushDrawRRectOps(PaintOpBuffer* buffer) {
size_t len = std::min(test_rrects.size(), test_flags.size());
for (size_t i = 0; i < len; ++i)
buffer->push<DrawRRectOp>(test_rrects[i], test_flags[i]);
- ValidateOps<DrawRRectOp>(buffer);
+ EXPECT_THAT(*buffer, Each(PaintOpIs<DrawRRectOp>()));
}
SkottieFrameDataMap GetTestImagesForSkottie(SkottieWrapper& skottie,
@@ -1627,7 +1624,7 @@ void PushDrawSkottieOps(PaintOpBuffer* buffer) {
test_skottie_color_maps[i],
test_skottie_text_maps[i]);
}
- ValidateOps<DrawSkottieOp>(buffer);
+ EXPECT_THAT(*buffer, Each(PaintOpIs<DrawSkottieOp>()));
}
void PushDrawTextBlobOps(PaintOpBuffer* buffer) {
@@ -1685,7 +1682,7 @@ void PushDrawTextBlobOps(PaintOpBuffer* buffer) {
buffer->push<DrawTextBlobOp>(test_paint_blobs[i], test_floats[i],
test_floats[i + 1], test_flags[i]);
}
- ValidateOps<DrawTextBlobOp>(buffer);
+ EXPECT_THAT(*buffer, Each(PaintOpIs<DrawTextBlobOp>()));
}
void PushNoopOps(PaintOpBuffer* buffer) {
@@ -1693,7 +1690,7 @@ void PushNoopOps(PaintOpBuffer* buffer) {
buffer->push<NoopOp>();
buffer->push<NoopOp>();
buffer->push<NoopOp>();
- ValidateOps<NoopOp>(buffer);
+ EXPECT_THAT(*buffer, Each(PaintOpIs<NoopOp>()));
}
void PushRestoreOps(PaintOpBuffer* buffer) {
@@ -1701,13 +1698,13 @@ void PushRestoreOps(PaintOpBuffer* buffer) {
buffer->push<RestoreOp>();
buffer->push<RestoreOp>();
buffer->push<RestoreOp>();
- ValidateOps<RestoreOp>(buffer);
+ EXPECT_THAT(*buffer, Each(PaintOpIs<RestoreOp>()));
}
void PushRotateOps(PaintOpBuffer* buffer) {
for (float test_float : test_floats)
buffer->push<RotateOp>(test_float);
- ValidateOps<RotateOp>(buffer);
+ EXPECT_THAT(*buffer, Each(PaintOpIs<RotateOp>()));
}
void PushSaveOps(PaintOpBuffer* buffer) {
@@ -1715,7 +1712,7 @@ void PushSaveOps(PaintOpBuffer* buffer) {
buffer->push<SaveOp>();
buffer->push<SaveOp>();
buffer->push<SaveOp>();
- ValidateOps<SaveOp>(buffer);
+ EXPECT_THAT(*buffer, Each(PaintOpIs<SaveOp>()));
}
void PushSaveLayerOps(PaintOpBuffer* buffer) {
@@ -1727,7 +1724,7 @@ void PushSaveLayerOps(PaintOpBuffer* buffer) {
buffer->push<SaveLayerOp>(nullptr, &test_flags[0]);
buffer->push<SaveLayerOp>(&test_rects[0], nullptr);
buffer->push<SaveLayerOp>(nullptr, nullptr);
- ValidateOps<SaveLayerOp>(buffer);
+ EXPECT_THAT(*buffer, Each(PaintOpIs<SaveLayerOp>()));
}
void PushSaveLayerAlphaOps(PaintOpBuffer* buffer) {
@@ -1737,31 +1734,31 @@ void PushSaveLayerAlphaOps(PaintOpBuffer* buffer) {
// Test optional args.
buffer->push<SaveLayerAlphaOp>(nullptr, test_floats[0]);
- ValidateOps<SaveLayerAlphaOp>(buffer);
+ EXPECT_THAT(*buffer, Each(PaintOpIs<SaveLayerAlphaOp>()));
}
void PushScaleOps(PaintOpBuffer* buffer) {
for (size_t i = 0; i < test_floats.size() - 1; i += 2)
buffer->push<ScaleOp>(test_floats[i], test_floats[i + 1]);
- ValidateOps<ScaleOp>(buffer);
+ EXPECT_THAT(*buffer, Each(PaintOpIs<ScaleOp>()));
}
void PushSetMatrixOps(PaintOpBuffer* buffer) {
for (auto& test_matrix : test_matrices)
buffer->push<SetMatrixOp>(test_matrix);
- ValidateOps<SetMatrixOp>(buffer);
+ EXPECT_THAT(*buffer, Each(PaintOpIs<SetMatrixOp>()));
}
void PushTranslateOps(PaintOpBuffer* buffer) {
for (size_t i = 0; i < test_floats.size() - 1; i += 2)
buffer->push<TranslateOp>(test_floats[i], test_floats[i + 1]);
- ValidateOps<TranslateOp>(buffer);
+ EXPECT_THAT(*buffer, Each(PaintOpIs<TranslateOp>()));
}
void PushSetNodeIdOps(PaintOpBuffer* buffer) {
for (uint32_t test_id : test_ids)
buffer->push<SetNodeIdOp>(static_cast<int>(test_id));
- ValidateOps<SetNodeIdOp>(buffer);
+ EXPECT_THAT(*buffer, Each(PaintOpIs<SetNodeIdOp>()));
}
class PaintOpSerializationTest : public ::testing::TestWithParam<uint8_t> {
@@ -1868,7 +1865,7 @@ class PaintOpSerializationTest : public ::testing::TestWithParam<uint8_t> {
// in the buffer_.
output_size_ = kBufferBytesPerOp * buffer_.size();
output_.reset(static_cast<char*>(
- base::AlignedAlloc(output_size_, PaintOpBuffer::PaintOpAlign)));
+ base::AlignedAlloc(output_size_, PaintOpBuffer::kPaintOpAlign)));
}
bool IsTypeSupported() {
@@ -1962,7 +1959,7 @@ TEST_P(PaintOpSerializationTest, SerializationFailures) {
TestOptionsProvider options_provider;
size_t op_idx = 0;
- for (PaintOpBuffer::Iterator iter(&buffer_); iter; ++iter, ++op_idx) {
+ for (const PaintOp& op : buffer_) {
SCOPED_TRACE(base::StringPrintf(
"%s #%zu", PaintOpTypeToString(GetParamType()).c_str(), op_idx));
size_t expected_bytes = bytes_written[op_idx];
@@ -1975,15 +1972,16 @@ TEST_P(PaintOpSerializationTest, SerializationFailures) {
for (size_t i = 0; i < bytes_written[op_idx] + 2; ++i) {
options_provider.ClearPaintCache();
options_provider.ForcePurgeSkottieSerializationHistory();
- size_t written_bytes = iter->Serialize(
- output_.get(), i, options_provider.serialize_options(), nullptr,
- SkM44(), SkM44());
+ size_t written_bytes =
+ op.Serialize(output_.get(), i, options_provider.serialize_options(),
+ nullptr, SkM44(), SkM44());
if (i >= expected_bytes) {
EXPECT_EQ(expected_bytes, written_bytes) << "i: " << i;
} else {
EXPECT_EQ(0u, written_bytes) << "i: " << i;
}
}
+ ++op_idx;
}
}
@@ -2004,14 +2002,13 @@ TEST_P(PaintOpSerializationTest, DeserializationFailures) {
char* first = static_cast<char*>(output_.get());
char* current = first;
- static constexpr size_t kAlign = PaintOpBuffer::PaintOpAlign;
+ static constexpr size_t kAlign = PaintOpBuffer::kPaintOpAlign;
static constexpr size_t kOutputOpSize = kBufferBytesPerOp;
std::unique_ptr<char, base::AlignedFreeDeleter> deserialize_buffer_(
static_cast<char*>(base::AlignedAlloc(kOutputOpSize, kAlign)));
- size_t op_idx = 0;
size_t total_read = 0;
- for (PaintOpBuffer::Iterator iter(&buffer_); iter; ++iter, ++op_idx) {
+ for (size_t op_idx = 0; op_idx < buffer_.size(); ++op_idx) {
PaintOp* serialized = reinterpret_cast<PaintOp*>(current);
uint32_t skip = serialized->skip;
@@ -2099,8 +2096,8 @@ TEST_P(PaintOpSerializationTest, UsesOverridenFlags) {
size_t deserialized_size = sizeof(LargestPaintOp) + PaintOp::kMaxSkip;
std::unique_ptr<char, base::AlignedFreeDeleter> deserialized(
static_cast<char*>(
- base::AlignedAlloc(deserialized_size, PaintOpBuffer::PaintOpAlign)));
- for (const PaintOp& op : PaintOpBuffer::Iterator(&buffer_)) {
+ base::AlignedAlloc(deserialized_size, PaintOpBuffer::kPaintOpAlign)));
+ for (const PaintOp& op : buffer_) {
size_t bytes_written = op.Serialize(output_.get(), output_size_,
options_provider.serialize_options(),
nullptr, SkM44(), SkM44());
@@ -2132,7 +2129,7 @@ TEST_P(PaintOpSerializationTest, UsesOverridenFlags) {
TEST(PaintOpSerializationTest, CompleteBufferSerialization) {
PaintOpBuffer buffer;
- PushDrawIRectOps(&buffer);
+ buffer.push<DrawColorOp>(SkColors::kBlue, SkBlendMode::kSrc);
PaintOpBufferSerializer::Preamble preamble;
preamble.content_size = gfx::Size(1000, 1000);
@@ -2142,7 +2139,7 @@ TEST(PaintOpSerializationTest, CompleteBufferSerialization) {
std::unique_ptr<char, base::AlignedFreeDeleter> memory(
static_cast<char*>(base::AlignedAlloc(PaintOpBuffer::kInitialBufferSize,
- PaintOpBuffer::PaintOpAlign)));
+ PaintOpBuffer::kPaintOpAlign)));
TestOptionsProvider options_provider;
SimpleBufferSerializer serializer(memory.get(),
PaintOpBuffer::kInitialBufferSize,
@@ -2150,79 +2147,20 @@ TEST(PaintOpSerializationTest, CompleteBufferSerialization) {
serializer.Serialize(&buffer, nullptr, preamble);
ASSERT_NE(serializer.written(), 0u);
- auto deserialized_buffer =
+ sk_sp<PaintOpBuffer> deserialized_buffer =
PaintOpBuffer::MakeFromMemory(memory.get(), serializer.written(),
options_provider.deserialize_options());
- ASSERT_TRUE(deserialized_buffer);
-
// The deserialized buffer has an extra pair of save/restores and a clear, for
// the preamble and root buffer.
- ASSERT_EQ(deserialized_buffer->size(), buffer.size() + 4u);
-
- size_t i = 0;
- auto serialized_iter = PaintOpBuffer::Iterator(&buffer);
- for (const PaintOp& op : PaintOpBuffer::Iterator(deserialized_buffer.get())) {
- SCOPED_TRACE(i);
- i++;
-
- if (i == 1) {
- // Save.
- ASSERT_EQ(op.GetType(), PaintOpType::Save)
- << PaintOpTypeToString(op.GetType());
- continue;
- }
-
- if (i == 2) {
- // Preamble partial raster clear.
- ASSERT_EQ(op.GetType(), PaintOpType::DrawColor)
- << PaintOpTypeToString(op.GetType());
- continue;
- }
- if (i == 3) {
- // Preamble playback rect clip.
- ASSERT_EQ(op.GetType(), PaintOpType::ClipRect)
- << PaintOpTypeToString(op.GetType());
- EXPECT_EQ(static_cast<const ClipRectOp&>(op).rect,
- gfx::RectToSkRect(preamble.playback_rect));
- continue;
- }
-
- if (serialized_iter) {
- // Root buffer.
- ASSERT_EQ(op.GetType(), (*serialized_iter).GetType())
- << PaintOpTypeToString(op.GetType());
- EXPECT_EQ(op, *serialized_iter);
- ++serialized_iter;
- continue;
- }
-
- // End restore.
- ASSERT_EQ(op.GetType(), PaintOpType::Restore)
- << PaintOpTypeToString(op.GetType());
- }
-}
-
-TEST(PaintOpSerializationTest, DoNotPreservePaintOps) {
- PaintOpBuffer buffer;
- PushDrawIRectOps(&buffer);
-
- PaintOpBufferSerializer::Preamble preamble;
- preamble.content_size = gfx::Size(1000, 1000);
- preamble.playback_rect = gfx::Rect(preamble.content_size);
- preamble.full_raster_rect = preamble.playback_rect;
- preamble.requires_clear = true;
-
- std::unique_ptr<char, base::AlignedFreeDeleter> memory(
- static_cast<char*>(base::AlignedAlloc(PaintOpBuffer::kInitialBufferSize,
- PaintOpBuffer::PaintOpAlign)));
- TestOptionsProvider options_provider;
- SimpleBufferSerializer serializer(memory.get(),
- PaintOpBuffer::kInitialBufferSize,
- options_provider.serialize_options());
- serializer.SerializeAndDestroy(&buffer, nullptr, preamble);
- ASSERT_NE(serializer.written(), 0u);
-
- EXPECT_TRUE(buffer.are_ops_destroyed());
+ EXPECT_THAT(deserialized_buffer,
+ Pointee(ElementsAre(
+ // Preamble:
+ PaintOpEq(SaveOp()), PaintOpIs<DrawColorOp>(),
+ PaintOpIs<ClipRectOp>(),
+ // Serialized buffer:
+ PaintOpEq(DrawColorOp(SkColors::kBlue, SkBlendMode::kSrc)),
+ // End restore:
+ PaintOpEq(RestoreOp()))));
}
TEST(PaintOpSerializationTest, Preamble) {
@@ -2239,92 +2177,33 @@ TEST(PaintOpSerializationTest, Preamble) {
std::unique_ptr<char, base::AlignedFreeDeleter> memory(
static_cast<char*>(base::AlignedAlloc(PaintOpBuffer::kInitialBufferSize,
- PaintOpBuffer::PaintOpAlign)));
+ PaintOpBuffer::kPaintOpAlign)));
TestOptionsProvider options_provider;
SimpleBufferSerializer serializer(memory.get(),
PaintOpBuffer::kInitialBufferSize,
options_provider.serialize_options());
- serializer.SerializeAndDestroy(&buffer, nullptr, preamble);
+ serializer.Serialize(&buffer, nullptr, preamble);
ASSERT_NE(serializer.written(), 0u);
- auto deserialized_buffer =
+ sk_sp<PaintOpBuffer> deserialized_buffer =
PaintOpBuffer::MakeFromMemory(memory.get(), serializer.written(),
options_provider.deserialize_options());
- ASSERT_TRUE(deserialized_buffer);
- // 5 ops for the preamble and 2 for save/restore.
- ASSERT_EQ(deserialized_buffer->size(), buffer.size() + 7u);
-
- size_t i = 0;
- for (const PaintOp& op : PaintOpBuffer::Iterator(deserialized_buffer.get())) {
- i++;
-
- if (i == 1) {
- // Save.
- ASSERT_EQ(op.GetType(), PaintOpType::Save)
- << PaintOpTypeToString(op.GetType());
- continue;
- }
-
- if (i == 2) {
- // Translate.
- ASSERT_EQ(op.GetType(), PaintOpType::Translate)
- << PaintOpTypeToString(op.GetType());
- const auto& translate_op = static_cast<const TranslateOp&>(op);
- EXPECT_EQ(translate_op.dx, -preamble.full_raster_rect.x());
- EXPECT_EQ(translate_op.dy, -preamble.full_raster_rect.y());
- continue;
- }
-
- if (i == 3) {
- // Clip.
- ASSERT_EQ(op.GetType(), PaintOpType::ClipRect)
- << PaintOpTypeToString(op.GetType());
- const auto& clip_op = static_cast<const ClipRectOp&>(op);
- EXPECT_RECTF_EQ(gfx::SkRectToRectF(clip_op.rect),
- gfx::RectF(preamble.playback_rect));
- continue;
- }
-
- if (i == 4) {
- // Post translate.
- ASSERT_EQ(op.GetType(), PaintOpType::Translate)
- << PaintOpTypeToString(op.GetType());
- const auto& translate_op = static_cast<const TranslateOp&>(op);
- EXPECT_EQ(translate_op.dx, preamble.post_translation.x());
- EXPECT_EQ(translate_op.dy, preamble.post_translation.y());
- continue;
- }
-
- if (i == 5) {
- // Scale.
- ASSERT_EQ(op.GetType(), PaintOpType::Scale)
- << PaintOpTypeToString(op.GetType());
- const auto& scale_op = static_cast<const ScaleOp&>(op);
- EXPECT_EQ(scale_op.sx, preamble.post_scale.x());
- EXPECT_EQ(scale_op.sy, preamble.post_scale.y());
- continue;
- }
-
- if (i == 6) {
- // Partial raster clear goes last.
- ASSERT_EQ(op.GetType(), PaintOpType::DrawColor)
- << PaintOpTypeToString(op.GetType());
- const auto& draw_color_op = static_cast<const DrawColorOp&>(op);
- EXPECT_EQ(draw_color_op.color, SkColors::kTransparent);
- EXPECT_EQ(draw_color_op.mode, SkBlendMode::kSrc);
- continue;
- }
-
- if (i == 7) {
- // Buffer.
- EXPECT_EQ(op, buffer.GetFirstOp());
- continue;
- }
-
- // End restore.
- ASSERT_EQ(op.GetType(), PaintOpType::Restore)
- << PaintOpTypeToString(op.GetType());
- }
+ EXPECT_THAT(deserialized_buffer,
+ Pointee(PaintOpsAreEq(
+ // Preamble:
+ SaveOp(),
+ TranslateOp(-preamble.full_raster_rect.x(),
+ -preamble.full_raster_rect.y()),
+ ClipRectOp(RectToSkRect(preamble.playback_rect),
+ SkClipOp::kIntersect, /*antialias=*/false),
+ TranslateOp(preamble.post_translation.x(),
+ preamble.post_translation.y()),
+ ScaleOp(preamble.post_scale.x(), preamble.post_scale.y()),
+ DrawColorOp(SkColors::kTransparent, SkBlendMode::kSrc),
+ // From the serialized buffer:
+ DrawColorOp(SkColors::kBlue, SkBlendMode::kSrc),
+ // End restore:
+ RestoreOp())));
}
TEST(PaintOpSerializationTest, SerializesNestedRecords) {
@@ -2336,7 +2215,7 @@ TEST(PaintOpSerializationTest, SerializesNestedRecords) {
std::unique_ptr<char, base::AlignedFreeDeleter> memory(
static_cast<char*>(base::AlignedAlloc(PaintOpBuffer::kInitialBufferSize,
- PaintOpBuffer::PaintOpAlign)));
+ PaintOpBuffer::kPaintOpAlign)));
TestOptionsProvider options_provider;
SimpleBufferSerializer serializer(memory.get(),
PaintOpBuffer::kInitialBufferSize,
@@ -2345,42 +2224,20 @@ TEST(PaintOpSerializationTest, SerializesNestedRecords) {
serializer.Serialize(&buffer, nullptr, preamble);
ASSERT_NE(serializer.written(), 0u);
- auto deserialized_buffer =
+ sk_sp<PaintOpBuffer> deserialized_buffer =
PaintOpBuffer::MakeFromMemory(memory.get(), serializer.written(),
options_provider.deserialize_options());
- ASSERT_TRUE(deserialized_buffer);
- ASSERT_EQ(deserialized_buffer->size(), record->size() + 5u);
-
- size_t i = 0;
- auto serialized_iter = PaintOpBuffer::Iterator(record.get());
- for (const PaintOp& op : PaintOpBuffer::Iterator(deserialized_buffer.get())) {
- i++;
- if (i == 1 || i == 3) {
- // First 2 saves.
- ASSERT_EQ(op.GetType(), PaintOpType::Save)
- << PaintOpTypeToString(op.GetType());
- continue;
- }
- // Clear.
- if (i == 2) {
- ASSERT_EQ(op.GetType(), PaintOpType::DrawColor)
- << PaintOpTypeToString(op.GetType());
- continue;
- }
-
- if (serialized_iter) {
- // Nested buffer.
- ASSERT_EQ(op.GetType(), serialized_iter->GetType())
- << PaintOpTypeToString(op.GetType());
- EXPECT_EQ(op, *serialized_iter);
- ++serialized_iter;
- continue;
- }
-
- // End restores.
- ASSERT_EQ(op.GetType(), PaintOpType::Restore)
- << PaintOpTypeToString(op.GetType());
- }
+ EXPECT_THAT(
+ deserialized_buffer,
+ Pointee(PaintOpsAreEq(
+ // Preamble:
+ SaveOp(), DrawColorOp(SkColors::kTransparent, SkBlendMode::kSrc),
+ SaveOp(),
+ // From the serialized buffer:
+ ScaleOp(0.5f, 0.75f),
+ DrawRectOp(SkRect::MakeWH(10.f, 20.f), PaintFlags()),
+ // End restore:
+ RestoreOp(), RestoreOp())));
}
TEST(PaintOpBufferTest, ClipsImagesDuringSerialization) {
@@ -2407,7 +2264,7 @@ TEST(PaintOpBufferTest, ClipsImagesDuringSerialization) {
std::unique_ptr<char, base::AlignedFreeDeleter> memory(
static_cast<char*>(base::AlignedAlloc(PaintOpBuffer::kInitialBufferSize,
- PaintOpBuffer::PaintOpAlign)));
+ PaintOpBuffer::kPaintOpAlign)));
TestOptionsProvider options_provider;
SimpleBufferSerializer serializer(memory.get(),
PaintOpBuffer::kInitialBufferSize,
@@ -2419,30 +2276,21 @@ TEST(PaintOpBufferTest, ClipsImagesDuringSerialization) {
// Avoid clearing.
preamble.content_size = gfx::Size(1000, 1000);
preamble.requires_clear = false;
- serializer.SerializeAndDestroy(&buffer, nullptr, preamble);
+ serializer.Serialize(&buffer, nullptr, preamble);
ASSERT_NE(serializer.written(), 0u);
- auto deserialized_buffer =
+ sk_sp<PaintOpBuffer> deserialized_buffer =
PaintOpBuffer::MakeFromMemory(memory.get(), serializer.written(),
options_provider.deserialize_options());
- ASSERT_TRUE(deserialized_buffer);
-
- auto deserialized_iter = PaintOpBuffer::Iterator(deserialized_buffer.get());
- ASSERT_EQ(deserialized_iter->GetType(), PaintOpType::Save)
- << PaintOpTypeToString(deserialized_iter->GetType());
- ++deserialized_iter;
- ASSERT_EQ(deserialized_iter->GetType(), PaintOpType::ClipRect)
- << PaintOpTypeToString(deserialized_iter->GetType());
- ++deserialized_iter;
+
+ std::vector<Matcher<PaintOp>> matchers;
+ matchers.push_back(PaintOpIs<SaveOp>());
+ matchers.push_back(PaintOpIs<ClipRectOp>());
if (test_case.should_draw) {
- ASSERT_EQ(deserialized_iter->GetType(), PaintOpType::DrawImage)
- << PaintOpTypeToString(deserialized_iter->GetType());
- ++deserialized_iter;
+ matchers.push_back(PaintOpIs<DrawImageOp>());
}
- ASSERT_EQ(deserialized_iter->GetType(), PaintOpType::Restore)
- << PaintOpTypeToString(deserialized_iter->GetType());
- ++deserialized_iter;
- ASSERT_EQ(deserialized_iter.end(), deserialized_iter);
+ matchers.push_back(PaintOpIs<RestoreOp>());
+ EXPECT_THAT(deserialized_buffer, Pointee(ElementsAreArray(matchers)));
}
}
@@ -2467,53 +2315,41 @@ TEST(PaintOpBufferSerializationTest, AlphaFoldingDuringSerialization) {
std::unique_ptr<char, base::AlignedFreeDeleter> memory(
static_cast<char*>(base::AlignedAlloc(PaintOpBuffer::kInitialBufferSize,
- PaintOpBuffer::PaintOpAlign)));
+ PaintOpBuffer::kPaintOpAlign)));
TestOptionsProvider options_provider;
SimpleBufferSerializer serializer(memory.get(),
PaintOpBuffer::kInitialBufferSize,
options_provider.serialize_options());
- serializer.SerializeAndDestroy(&buffer, nullptr, preamble);
+ serializer.Serialize(&buffer, nullptr, preamble);
ASSERT_NE(serializer.written(), 0u);
- auto deserialized_buffer =
+ sk_sp<PaintOpBuffer> deserialized_buffer =
PaintOpBuffer::MakeFromMemory(memory.get(), serializer.written(),
options_provider.deserialize_options());
- ASSERT_TRUE(deserialized_buffer);
-
- // 4 additional ops for save, clip, clear, and restore.
- ASSERT_EQ(deserialized_buffer->size(), 4u);
- size_t i = 0;
- for (const PaintOp& op : PaintOpBuffer::Iterator(deserialized_buffer.get())) {
- ++i;
- if (i == 1) {
- EXPECT_EQ(op.GetType(), PaintOpType::Save);
- continue;
- }
-
- if (i == 2) {
- EXPECT_EQ(op.GetType(), PaintOpType::ClipRect);
- continue;
- }
- if (i == 4) {
- EXPECT_EQ(op.GetType(), PaintOpType::Restore);
- continue;
- }
-
- ASSERT_EQ(op.GetType(), PaintOpType::DrawRect);
- // Expect the alpha from the draw and the save layer to be folded together.
- // Since alpha is stored in a uint8_t and gets rounded, so use tolerance.
- float expected_alpha = alpha * 50;
- EXPECT_LE(std::abs(expected_alpha -
- static_cast<const DrawRectOp&>(op).flags.getAlpha()),
- 1.f);
- }
+ EXPECT_THAT(
+ deserialized_buffer,
+ Pointee(ElementsAre(
+ PaintOpIs<SaveOp>(), PaintOpIs<ClipRectOp>(),
+ AllOf(PaintOpIs<DrawRectOp>(),
+ // Expect the alpha from the draw and the save layer to be
+ // folded together. Since alpha is stored in a uint8_t and
+ // gets rounded, so use tolerance.
+ ResultOf(
+ [alpha](const PaintOp& op) {
+ float expected_alpha = alpha * 50;
+ return std::abs(
+ expected_alpha -
+ static_cast<const DrawRectOp&>(op).flags.getAlpha());
+ },
+ Le(1.f))),
+ PaintOpIs<RestoreOp>())));
}
// Test generic PaintOp deserializing failure cases.
TEST(PaintOpBufferTest, PaintOpDeserialize) {
static constexpr size_t kSize = sizeof(LargestPaintOp) + 100;
- static constexpr size_t kAlign = PaintOpBuffer::PaintOpAlign;
+ static constexpr size_t kAlign = PaintOpBuffer::kPaintOpAlign;
std::unique_ptr<char, base::AlignedFreeDeleter> input_(
static_cast<char*>(base::AlignedAlloc(kSize, kAlign)));
std::unique_ptr<char, base::AlignedFreeDeleter> output_(
@@ -2523,7 +2359,7 @@ TEST(PaintOpBufferTest, PaintOpDeserialize) {
buffer.push<DrawColorOp>(SkColors::kMagenta, SkBlendMode::kSrc);
PaintOpBuffer::Iterator iter(&buffer);
- PaintOp* op = iter.get();
+ const PaintOp* op = iter.get();
ASSERT_TRUE(op);
TestOptionsProvider options_provider;
@@ -2570,10 +2406,10 @@ TEST(PaintOpBufferTest, PaintOpDeserialize) {
TEST(PaintOpBufferTest, ValidateSkClip) {
size_t buffer_size = kBufferBytesPerOp;
std::unique_ptr<char, base::AlignedFreeDeleter> serialized(static_cast<char*>(
- base::AlignedAlloc(buffer_size, PaintOpBuffer::PaintOpAlign)));
+ base::AlignedAlloc(buffer_size, PaintOpBuffer::kPaintOpAlign)));
std::unique_ptr<char, base::AlignedFreeDeleter> deserialized(
static_cast<char*>(
- base::AlignedAlloc(buffer_size, PaintOpBuffer::PaintOpAlign)));
+ base::AlignedAlloc(buffer_size, PaintOpBuffer::kPaintOpAlign)));
PaintOpBuffer buffer;
@@ -2600,8 +2436,7 @@ TEST(PaintOpBufferTest, ValidateSkClip) {
TestOptionsProvider options_provider;
int op_idx = 0;
- for (PaintOpBuffer::Iterator iter(&buffer); iter; ++iter) {
- const PaintOp& op = *iter;
+ for (const PaintOp& op : buffer) {
size_t bytes_written = op.Serialize(serialized.get(), buffer_size,
options_provider.serialize_options(),
nullptr, SkM44(), SkM44());
@@ -2628,10 +2463,10 @@ TEST(PaintOpBufferTest, ValidateSkClip) {
TEST(PaintOpBufferTest, ValidateSkBlendMode) {
size_t buffer_size = kBufferBytesPerOp;
std::unique_ptr<char, base::AlignedFreeDeleter> serialized(static_cast<char*>(
- base::AlignedAlloc(buffer_size, PaintOpBuffer::PaintOpAlign)));
+ base::AlignedAlloc(buffer_size, PaintOpBuffer::kPaintOpAlign)));
std::unique_ptr<char, base::AlignedFreeDeleter> deserialized(
static_cast<char*>(
- base::AlignedAlloc(buffer_size, PaintOpBuffer::PaintOpAlign)));
+ base::AlignedAlloc(buffer_size, PaintOpBuffer::kPaintOpAlign)));
PaintOpBuffer buffer;
@@ -2681,8 +2516,7 @@ TEST(PaintOpBufferTest, ValidateSkBlendMode) {
TestOptionsProvider options_provider;
int op_idx = 0;
- for (PaintOpBuffer::Iterator iter(&buffer); iter; ++iter) {
- const PaintOp& op = *iter;
+ for (const PaintOp& op : buffer) {
size_t bytes_written = op.Serialize(serialized.get(), buffer_size,
options_provider.serialize_options(),
nullptr, SkM44(), SkM44());
@@ -2709,10 +2543,10 @@ TEST(PaintOpBufferTest, ValidateSkBlendMode) {
TEST(PaintOpBufferTest, ValidateRects) {
size_t buffer_size = kBufferBytesPerOp;
std::unique_ptr<char, base::AlignedFreeDeleter> serialized(static_cast<char*>(
- base::AlignedAlloc(buffer_size, PaintOpBuffer::PaintOpAlign)));
+ base::AlignedAlloc(buffer_size, PaintOpBuffer::kPaintOpAlign)));
std::unique_ptr<char, base::AlignedFreeDeleter> deserialized(
static_cast<char*>(
- base::AlignedAlloc(buffer_size, PaintOpBuffer::PaintOpAlign)));
+ base::AlignedAlloc(buffer_size, PaintOpBuffer::kPaintOpAlign)));
// Used for QuickRejectDraw
SkCanvas device(256, 256);
@@ -2742,8 +2576,7 @@ TEST(PaintOpBufferTest, ValidateRects) {
// Every op should serialize but fail to deserialize due to the bad rect.
int op_idx = 0;
- for (PaintOpBuffer::Iterator iter(&buffer); iter; ++iter) {
- const PaintOp& op = *iter;
+ for (const PaintOp& op : buffer) {
size_t bytes_written = op.Serialize(serialized.get(), buffer_size,
options_provider.serialize_options(),
nullptr, SkM44(), SkM44());
@@ -2770,7 +2603,7 @@ TEST(PaintOpBufferTest, BoundingRect_DrawImageOp) {
PushDrawImageOps(&buffer);
SkRect rect;
- for (const PaintOp& base_op : PaintOpBuffer::Iterator(&buffer)) {
+ for (const PaintOp& base_op : buffer) {
const auto& op = static_cast<const DrawImageOp&>(base_op);
SkRect image_rect =
@@ -2785,7 +2618,7 @@ TEST(PaintOpBufferTest, BoundingRect_DrawImageRectOp) {
PushDrawImageRectOps(&buffer);
SkRect rect;
- for (const PaintOp& base_op : PaintOpBuffer::Iterator(&buffer)) {
+ for (const PaintOp& base_op : buffer) {
const auto& op = static_cast<const DrawImageRectOp&>(base_op);
ASSERT_TRUE(PaintOp::GetBounds(op, &rect));
@@ -2798,7 +2631,7 @@ TEST(PaintOpBufferTest, BoundingRect_DrawIRectOp) {
PushDrawIRectOps(&buffer);
SkRect rect;
- for (const PaintOp& base_op : PaintOpBuffer::Iterator(&buffer)) {
+ for (const PaintOp& base_op : buffer) {
const auto& op = static_cast<const DrawIRectOp&>(base_op);
ASSERT_TRUE(PaintOp::GetBounds(op, &rect));
@@ -2811,7 +2644,7 @@ TEST(PaintOpBufferTest, BoundingRect_DrawOvalOp) {
PushDrawOvalOps(&buffer);
SkRect rect;
- for (const PaintOp& base_op : PaintOpBuffer::Iterator(&buffer)) {
+ for (const PaintOp& base_op : buffer) {
const auto& op = static_cast<const DrawOvalOp&>(base_op);
ASSERT_TRUE(PaintOp::GetBounds(op, &rect));
@@ -2824,7 +2657,7 @@ TEST(PaintOpBufferTest, BoundingRect_DrawPathOp) {
PushDrawPathOps(&buffer);
SkRect rect;
- for (const PaintOp& base_op : PaintOpBuffer::Iterator(&buffer)) {
+ for (const PaintOp& base_op : buffer) {
const auto& op = static_cast<const DrawPathOp&>(base_op);
ASSERT_TRUE(PaintOp::GetBounds(op, &rect));
@@ -2837,7 +2670,7 @@ TEST(PaintOpBufferTest, BoundingRect_DrawRectOp) {
PushDrawRectOps(&buffer);
SkRect rect;
- for (const PaintOp& base_op : PaintOpBuffer::Iterator(&buffer)) {
+ for (const PaintOp& base_op : buffer) {
const auto& op = static_cast<const DrawRectOp&>(base_op);
ASSERT_TRUE(PaintOp::GetBounds(op, &rect));
@@ -2850,7 +2683,7 @@ TEST(PaintOpBufferTest, BoundingRect_DrawRRectOp) {
PushDrawRRectOps(&buffer);
SkRect rect;
- for (const PaintOp& base_op : PaintOpBuffer::Iterator(&buffer)) {
+ for (const PaintOp& base_op : buffer) {
const auto& op = static_cast<const DrawRRectOp&>(base_op);
ASSERT_TRUE(PaintOp::GetBounds(op, &rect));
@@ -2863,7 +2696,7 @@ TEST(PaintOpBufferTest, BoundingRect_DrawLineOp) {
PushDrawLineOps(&buffer);
SkRect rect;
- for (const PaintOp& base_op : PaintOpBuffer::Iterator(&buffer)) {
+ for (const PaintOp& base_op : buffer) {
const auto& op = static_cast<const DrawLineOp&>(base_op);
SkRect line_rect;
@@ -2881,7 +2714,7 @@ TEST(PaintOpBufferTest, BoundingRect_DrawDRRectOp) {
PushDrawDRRectOps(&buffer);
SkRect rect;
- for (const PaintOp& base_op : PaintOpBuffer::Iterator(&buffer)) {
+ for (const PaintOp& base_op : buffer) {
const auto& op = static_cast<const DrawDRRectOp&>(base_op);
ASSERT_TRUE(PaintOp::GetBounds(op, &rect));
@@ -2894,7 +2727,7 @@ TEST(PaintOpBufferTest, BoundingRect_DrawTextBlobOp) {
PushDrawTextBlobOps(&buffer);
SkRect rect;
- for (const PaintOp& base_op : PaintOpBuffer::Iterator(&buffer)) {
+ for (const PaintOp& base_op : buffer) {
const auto& op = static_cast<const DrawTextBlobOp&>(base_op);
ASSERT_TRUE(PaintOp::GetBounds(op, &rect));
@@ -3339,7 +3172,7 @@ TEST(PaintOpBufferTest, ReplacesImagesFromProviderOOP) {
std::unique_ptr<char, base::AlignedFreeDeleter> memory(
static_cast<char*>(base::AlignedAlloc(PaintOpBuffer::kInitialBufferSize,
- PaintOpBuffer::PaintOpAlign)));
+ PaintOpBuffer::kPaintOpAlign)));
TestOptionsProvider options_provider;
SimpleBufferSerializer serializer(memory.get(),
PaintOpBuffer::kInitialBufferSize,
@@ -3347,12 +3180,12 @@ TEST(PaintOpBufferTest, ReplacesImagesFromProviderOOP) {
serializer.Serialize(&buffer);
ASSERT_NE(serializer.written(), 0u);
- auto deserialized_buffer =
+ sk_sp<PaintOpBuffer> deserialized_buffer =
PaintOpBuffer::MakeFromMemory(memory.get(), serializer.written(),
options_provider.deserialize_options());
ASSERT_TRUE(deserialized_buffer);
- for (const PaintOp& op : PaintOpBuffer::Iterator(deserialized_buffer.get())) {
+ for (const PaintOp& op : *deserialized_buffer) {
testing::NiceMock<MockCanvas> canvas;
PlaybackParams params(nullptr);
testing::Sequence s;
@@ -3493,10 +3326,8 @@ TEST_P(PaintFilterSerializationTest, Basic) {
// ScaleOp containing the extracted scale factors (if there's no
// security constraints that disable record serialization)
if (!GetParam()) {
- const ScaleOp* scale = actual.record()->GetOpAtForTesting<ScaleOp>(0);
- ASSERT_TRUE(scale);
- EXPECT_EQ(scale->sx, scale_x);
- EXPECT_EQ(scale->sy, scale_y);
+ EXPECT_THAT(actual.record(),
+ Pointee(PaintOpsAreEq(ScaleOp(scale_x, scale_y))));
}
} else {
EXPECT_TRUE(*filter == *deserialized_filter);
@@ -3507,7 +3338,7 @@ TEST_P(PaintFilterSerializationTest, Basic) {
TEST(PaintOpBufferTest, PaintRecordShaderSerialization) {
std::unique_ptr<char, base::AlignedFreeDeleter> memory(
static_cast<char*>(base::AlignedAlloc(PaintOpBuffer::kInitialBufferSize,
- PaintOpBuffer::PaintOpAlign)));
+ PaintOpBuffer::kPaintOpAlign)));
sk_sp<PaintOpBuffer> record_buffer(new PaintOpBuffer);
record_buffer->push<DrawRectOp>(SkRect::MakeXYWH(0, 0, 1, 1), PaintFlags());
@@ -3526,18 +3357,12 @@ TEST(PaintOpBufferTest, PaintRecordShaderSerialization) {
ASSERT_TRUE(serializer.valid());
ASSERT_GT(serializer.written(), 0u);
- auto deserialized_buffer =
+ sk_sp<PaintOpBuffer> deserialized_buffer =
PaintOpBuffer::MakeFromMemory(memory.get(), serializer.written(),
options_provider.deserialize_options());
- ASSERT_TRUE(deserialized_buffer);
- PaintOpBuffer::Iterator it(deserialized_buffer.get());
- ASSERT_TRUE(it);
- const PaintOp& op = *it;
- ASSERT_TRUE(op.GetType() == PaintOpType::DrawRect);
- const auto& rect_op = static_cast<const DrawRectOp&>(op);
- EXPECT_SKRECT_EQ(rect_op.rect, SkRect::MakeXYWH(1, 2, 3, 4));
- EXPECT_TRUE(rect_op.flags == flags);
- EXPECT_TRUE(*rect_op.flags.getShader() == *flags.getShader());
+ EXPECT_THAT(
+ deserialized_buffer,
+ Pointee(PaintOpsAreEq(DrawRectOp(SkRect::MakeXYWH(1, 2, 3, 4), flags))));
}
#if BUILDFLAG(SKIA_SUPPORT_SKOTTIE)
@@ -3546,7 +3371,7 @@ TEST(PaintOpBufferTest, BoundingRect_DrawSkottieOp) {
PushDrawSkottieOps(&buffer);
SkRect rect;
- for (const PaintOp& base_op : PaintOpBuffer::Iterator(&buffer)) {
+ for (const PaintOp& base_op : buffer) {
const auto& op = static_cast<const DrawSkottieOp&>(base_op);
ASSERT_TRUE(PaintOp::GetBounds(op, &rect));
@@ -3559,7 +3384,7 @@ TEST(PaintOpBufferTest,
DrawSkottieOpSerializationFailureFromUnPrivilegedProcess) {
std::unique_ptr<char, base::AlignedFreeDeleter> memory(
static_cast<char*>(base::AlignedAlloc(PaintOpBuffer::kInitialBufferSize,
- PaintOpBuffer::PaintOpAlign)));
+ PaintOpBuffer::kPaintOpAlign)));
scoped_refptr<SkottieWrapper> skottie =
CreateSkottie(gfx::Size(100, 100), /*duration_secs=*/1);
@@ -3761,15 +3586,9 @@ TEST(PaintOpBufferTest, CustomData) {
buffer.push<SaveOp>();
buffer.push<CustomDataOp>(0xFFFFFFFF);
buffer.push<RestoreOp>();
- EXPECT_EQ(buffer.size(), 3u);
- PaintOpBuffer::Iterator iter(&buffer);
- ASSERT_EQ(iter->GetType(), PaintOpType::Save);
- ++iter;
- ASSERT_EQ(iter->GetType(), PaintOpType::CustomData);
- ++iter;
- ASSERT_EQ(iter->GetType(), PaintOpType::Restore);
- ++iter;
+ EXPECT_THAT(buffer,
+ PaintOpsAreEq(SaveOp(), CustomDataOp(0xFFFFFFFF), RestoreOp()));
}
// Playback.
@@ -3794,7 +3613,7 @@ TEST(PaintOpBufferTest, SecurityConstrainedImageSerialization) {
std::unique_ptr<char, base::AlignedFreeDeleter> memory(
static_cast<char*>(base::AlignedAlloc(PaintOpBuffer::kInitialBufferSize,
- PaintOpBuffer::PaintOpAlign)));
+ PaintOpBuffer::kPaintOpAlign)));
TestOptionsProvider options_provider;
PaintOpWriter writer(memory.get(), PaintOpBuffer::kInitialBufferSize,
options_provider.serialize_options(),
@@ -3828,7 +3647,7 @@ TEST(PaintOpBufferTest, DrawImageRectSerializeScaledImages) {
src, dst, SkCanvas::kStrict_SrcRectConstraint);
std::unique_ptr<char, base::AlignedFreeDeleter> memory(
static_cast<char*>(base::AlignedAlloc(PaintOpBuffer::kInitialBufferSize,
- PaintOpBuffer::PaintOpAlign)));
+ PaintOpBuffer::kPaintOpAlign)));
TestOptionsProvider options_provider;
SimpleBufferSerializer serializer(memory.get(),
PaintOpBuffer::kInitialBufferSize,
@@ -3858,7 +3677,7 @@ TEST(PaintOpBufferTest, RecordShadersSerializeScaledImages) {
std::unique_ptr<char, base::AlignedFreeDeleter> memory(
static_cast<char*>(base::AlignedAlloc(PaintOpBuffer::kInitialBufferSize,
- PaintOpBuffer::PaintOpAlign)));
+ PaintOpBuffer::kPaintOpAlign)));
TestOptionsProvider options_provider;
SimpleBufferSerializer serializer(memory.get(),
PaintOpBuffer::kInitialBufferSize,
@@ -3886,7 +3705,7 @@ TEST(PaintOpBufferTest, RecordShadersCached) {
// Generate serialized |memory|.
std::unique_ptr<char, base::AlignedFreeDeleter> memory(
static_cast<char*>(base::AlignedAlloc(PaintOpBuffer::kInitialBufferSize,
- PaintOpBuffer::PaintOpAlign)));
+ PaintOpBuffer::kPaintOpAlign)));
size_t memory_written = 0;
{
auto buffer = sk_make_sp<PaintOpBuffer>();
@@ -3905,7 +3724,7 @@ TEST(PaintOpBufferTest, RecordShadersCached) {
// a scale factor.
std::unique_ptr<char, base::AlignedFreeDeleter> memory_scaled(
static_cast<char*>(base::AlignedAlloc(PaintOpBuffer::kInitialBufferSize,
- PaintOpBuffer::PaintOpAlign)));
+ PaintOpBuffer::kPaintOpAlign)));
size_t memory_scaled_written = 0;
{
auto buffer = sk_make_sp<PaintOpBuffer>();
@@ -3952,7 +3771,7 @@ TEST(PaintOpBufferTest, RecordShadersCached) {
else
EXPECT_EQ(records[i]->size(), 2u);
- for (const PaintOp& base_op : PaintOpBuffer::Iterator(records[i].get())) {
+ for (const PaintOp& base_op : *records[i]) {
if (base_op.GetType() != PaintOpType::DrawRect)
continue;
const auto& op = static_cast<const DrawRectOp&>(base_op);
@@ -3996,7 +3815,7 @@ TEST(PaintOpBufferTest, RecordShadersCachedSize) {
// Generate serialized |memory|.
std::unique_ptr<char, base::AlignedFreeDeleter> memory(
static_cast<char*>(base::AlignedAlloc(PaintOpBuffer::kInitialBufferSize,
- PaintOpBuffer::PaintOpAlign)));
+ PaintOpBuffer::kPaintOpAlign)));
auto buffer = sk_make_sp<PaintOpBuffer>();
PaintFlags flags;
flags.setShader(shader);
@@ -4040,7 +3859,7 @@ TEST(PaintOpBufferTest, RecordFilterSerializeScaledImages) {
std::unique_ptr<char, base::AlignedFreeDeleter> memory(
static_cast<char*>(base::AlignedAlloc(PaintOpBuffer::kInitialBufferSize,
- PaintOpBuffer::PaintOpAlign)));
+ PaintOpBuffer::kPaintOpAlign)));
TestOptionsProvider options_provider;
SimpleBufferSerializer serializer(memory.get(),
PaintOpBuffer::kInitialBufferSize,
@@ -4075,7 +3894,7 @@ TEST(PaintOpBufferTest, NullImages) {
std::unique_ptr<char, base::AlignedFreeDeleter> memory(
static_cast<char*>(base::AlignedAlloc(PaintOpBuffer::kInitialBufferSize,
- PaintOpBuffer::PaintOpAlign)));
+ PaintOpBuffer::kPaintOpAlign)));
TestOptionsProvider options_provider;
SimpleBufferSerializer serializer(memory.get(),
PaintOpBuffer::kInitialBufferSize,
@@ -4084,13 +3903,11 @@ TEST(PaintOpBufferTest, NullImages) {
ASSERT_TRUE(serializer.valid());
ASSERT_GT(serializer.written(), 0u);
- auto deserialized_buffer =
+ sk_sp<PaintOpBuffer> deserialized_buffer =
PaintOpBuffer::MakeFromMemory(memory.get(), serializer.written(),
options_provider.deserialize_options());
- ASSERT_TRUE(deserialized_buffer);
- ASSERT_EQ(deserialized_buffer->size(), 1u);
- ASSERT_EQ(deserialized_buffer->GetFirstOp().GetType(),
- PaintOpType::DrawImage);
+ EXPECT_THAT(deserialized_buffer,
+ Pointee(PaintOpsAreEq(DrawImageOp(PaintImage(), 0.f, 0.f))));
}
TEST(PaintOpBufferTest, HasDrawOpsAndHasDrawTextOps) {
@@ -4228,7 +4045,7 @@ TEST(PaintOpBufferTest, PathCaching) {
std::unique_ptr<char, base::AlignedFreeDeleter> memory(
static_cast<char*>(base::AlignedAlloc(PaintOpBuffer::kInitialBufferSize,
- PaintOpBuffer::PaintOpAlign)));
+ PaintOpBuffer::kPaintOpAlign)));
auto buffer = sk_make_sp<PaintOpBuffer>();
buffer->push<DrawPathOp>(path, flags, UsePaintCache::kEnabled);
SimpleBufferSerializer serializer(memory.get(),
@@ -4239,55 +4056,125 @@ TEST(PaintOpBufferTest, PathCaching) {
EXPECT_TRUE(options_provider.client_paint_cache()->Get(
PaintCacheDataType::kPath, path.getGenerationID()));
- auto deserialized_buffer =
+ sk_sp<PaintOpBuffer> deserialized_buffer =
PaintOpBuffer::MakeFromMemory(memory.get(), serializer.written(),
options_provider.deserialize_options());
- ASSERT_TRUE(deserialized_buffer);
- ASSERT_EQ(deserialized_buffer->size(), 1u);
- ASSERT_EQ(deserialized_buffer->GetFirstOp().GetType(), PaintOpType::DrawPath);
+ EXPECT_THAT(deserialized_buffer,
+ Pointee(ElementsAre(PaintOpIs<DrawPathOp>())));
SkPath cached_path;
EXPECT_TRUE(options_provider.service_paint_cache()->GetPath(
path.getGenerationID(), &cached_path));
}
+TEST(PaintOpBufferTest, ShrinkToFit) {
+ PaintOpBuffer buffer;
+ EXPECT_EQ(sizeof(PaintOpBuffer), buffer.bytes_used());
+ EXPECT_FALSE(&buffer.GetFirstOp());
+ buffer.ShrinkToFit();
+ EXPECT_EQ(sizeof(PaintOpBuffer), buffer.bytes_used());
+ EXPECT_FALSE(&buffer.GetFirstOp());
+
+ buffer.push<DrawColorOp>(SkColors::kRed, SkBlendMode::kSrc);
+ EXPECT_GT(buffer.bytes_used(), sizeof(PaintOpBuffer) + sizeof(DrawColorOp));
+ const PaintOp* first_op = &buffer.GetFirstOp();
+ ASSERT_TRUE(first_op);
+ buffer.ShrinkToFit();
+ EXPECT_EQ(sizeof(PaintOpBuffer) + sizeof(DrawColorOp), buffer.bytes_used());
+ EXPECT_NE(first_op, &buffer.GetFirstOp());
+
+ first_op = &buffer.GetFirstOp();
+ buffer.ShrinkToFit();
+ EXPECT_EQ(sizeof(PaintOpBuffer) + sizeof(DrawColorOp), buffer.bytes_used());
+ EXPECT_EQ(first_op, &buffer.GetFirstOp());
+}
+
+TEST(PaintOpBufferTest, MoveRetainingBufferIfPossible) {
+ PaintOpBuffer buffer;
+ sk_sp<PaintOpBuffer> move_to = buffer.MoveRetainingBufferIfPossible();
+ EXPECT_EQ(sizeof(PaintOpBuffer), move_to->bytes_used());
+ EXPECT_FALSE(&move_to->GetFirstOp());
+ EXPECT_EQ(sizeof(PaintOpBuffer), buffer.bytes_used());
+ EXPECT_FALSE(&buffer.GetFirstOp());
+
+ // `buffer` has more reserved than used.
+ buffer.push<DrawColorOp>(SkColors::kRed, SkBlendMode::kSrc);
+ size_t old_bytes_used = buffer.bytes_used();
+ EXPECT_GT(old_bytes_used, sizeof(PaintOpBuffer) + sizeof(DrawColorOp));
+ const PaintOp* first_op = &buffer.GetFirstOp();
+ ASSERT_TRUE(first_op);
+ EXPECT_EQ(1u, buffer.size());
+
+ // `move_to` should allocate a new data buffer that fits, and `buffer` should
+ // retain the old data buffer.
+ move_to = buffer.MoveRetainingBufferIfPossible();
+ EXPECT_EQ(1u, move_to->size());
+ EXPECT_EQ(sizeof(PaintOpBuffer) + sizeof(DrawColorOp), move_to->bytes_used());
+ EXPECT_NE(first_op, &move_to->GetFirstOp());
+ EXPECT_EQ(first_op, &buffer.GetFirstOp());
+ EXPECT_EQ(old_bytes_used, buffer.bytes_used());
+
+ // `buffer` now fits.
+ buffer = std::move(*move_to);
+ old_bytes_used = buffer.bytes_used();
+ EXPECT_EQ(old_bytes_used, sizeof(PaintOpBuffer) + sizeof(DrawColorOp));
+ first_op = &buffer.GetFirstOp();
+ ASSERT_TRUE(first_op);
+
+ // `move_to` takes the data buffer of `buffer`.
+ move_to = buffer.MoveRetainingBufferIfPossible();
+ EXPECT_EQ(1u, move_to->size());
+ EXPECT_EQ(sizeof(PaintOpBuffer) + sizeof(DrawColorOp), move_to->bytes_used());
+ EXPECT_EQ(first_op, &move_to->GetFirstOp());
+ EXPECT_FALSE(&buffer.GetFirstOp());
+ EXPECT_EQ(sizeof(PaintOpBuffer), buffer.bytes_used());
+}
+
+TEST(IteratorTest, StlContainerLikeIterationTest) {
+ PaintOpBuffer buffer;
+ buffer.push<SaveOp>();
+ buffer.push<SetMatrixOp>(SkM44::Scale(1, 2));
+ EXPECT_THAT(buffer, PaintOpsAreEq(SaveOp(), SetMatrixOp(SkM44::Scale(1, 2))));
+}
+
TEST(IteratorTest, IterationTest) {
PaintOpBuffer buffer;
buffer.push<SaveOp>();
- buffer.push<RestoreOp>();
+ buffer.push<SetMatrixOp>(SkM44::Scale(1, 2));
EXPECT_THAT(PaintOpBuffer::Iterator(&buffer),
- ElementsAre(SaveOp(), RestoreOp()));
+ PaintOpsAreEq(SaveOp(), SetMatrixOp(SkM44::Scale(1, 2))));
}
TEST(IteratorTest, OffsetIterationTest) {
PaintOpBuffer buffer;
const PaintOp& op1 = buffer.push<SaveOp>();
const PaintOp& op2 = buffer.push<RestoreOp>();
- const PaintOp& op3 = buffer.push<NoopOp>();
+ buffer.push<SetMatrixOp>(SkM44::Scale(1, 2));
std::vector<size_t> offsets = {0, static_cast<size_t>(op1.skip + op2.skip)};
EXPECT_THAT(PaintOpBuffer::OffsetIterator(&buffer, &offsets),
- ElementsAre(op1, op3));
+ PaintOpsAreEq(SaveOp(), SetMatrixOp(SkM44::Scale(1, 2))));
}
TEST(IteratorTest, CompositeIterationTest) {
PaintOpBuffer buffer;
const PaintOp& op1 = buffer.push<SaveOp>();
const PaintOp& op2 = buffer.push<RestoreOp>();
- const PaintOp& op3 = buffer.push<NoopOp>();
+ buffer.push<SetMatrixOp>(SkM44::Scale(1, 2));
std::vector<size_t> offsets = {0, static_cast<size_t>(op1.skip + op2.skip)};
- EXPECT_THAT(PaintOpBuffer::CompositeIterator(&buffer, /*offsets=*/nullptr),
- ElementsAre(op1, op2, op3));
+ EXPECT_THAT(
+ PaintOpBuffer::CompositeIterator(&buffer, /*offsets=*/nullptr),
+ PaintOpsAreEq(SaveOp(), RestoreOp(), SetMatrixOp(SkM44::Scale(1, 2))));
EXPECT_THAT(PaintOpBuffer::CompositeIterator(&buffer, &offsets),
- ElementsAre(op1, op3));
+ PaintOpsAreEq(SaveOp(), SetMatrixOp(SkM44::Scale(1, 2))));
}
TEST(IteratorTest, EqualityTest) {
PaintOpBuffer buffer;
buffer.push<SaveOp>();
- buffer.push<RestoreOp>();
+ buffer.push<SetMatrixOp>(SkM44::Scale(1, 2));
PaintOpBuffer::Iterator iter1(&buffer);
PaintOpBuffer::Iterator iter2(&buffer);
EXPECT_TRUE(iter1 == iter2);
@@ -4298,7 +4185,7 @@ TEST(IteratorTest, OffsetEqualityTest) {
PaintOpBuffer buffer;
size_t offset = 0;
offset += buffer.push<SaveOp>().skip;
- offset += buffer.push<RestoreOp>().skip;
+ offset += buffer.push<SetMatrixOp>(SkM44::Scale(1, 2)).skip;
buffer.push<NoopOp>();
std::vector<size_t> offsets = {0, offset};
@@ -4312,7 +4199,7 @@ TEST(IteratorTest, OffsetEqualityTest) {
TEST(IteratorTest, CompositeEqualityTest) {
PaintOpBuffer buffer;
buffer.push<SaveOp>();
- buffer.push<RestoreOp>();
+ buffer.push<SetMatrixOp>(SkM44::Scale(1, 2));
PaintOpBuffer::CompositeIterator iter1(&buffer, /*offsets=*/nullptr);
PaintOpBuffer::CompositeIterator iter2(&buffer, /*offsets=*/nullptr);
@@ -4324,7 +4211,7 @@ TEST(IteratorTest, CompositeOffsetEqualityTest) {
PaintOpBuffer buffer;
size_t offset = 0;
offset += buffer.push<SaveOp>().skip;
- offset += buffer.push<RestoreOp>().skip;
+ offset += buffer.push<SetMatrixOp>(SkM44::Scale(1, 2)).skip;
buffer.push<NoopOp>();
std::vector<size_t> offsets = {0, offset};
@@ -4350,7 +4237,7 @@ TEST(IteratorTest, CompositeOffsetBoolCheck) {
PaintOpBuffer buffer;
size_t offset = 0;
offset += buffer.push<SaveOp>().skip;
- offset += buffer.push<RestoreOp>().skip;
+ offset += buffer.push<SetMatrixOp>(SkM44::Scale(1, 2)).skip;
buffer.push<NoopOp>();
PaintOpBuffer::CompositeIterator iter(&buffer, /*offsets=*/nullptr);
diff --git a/chromium/cc/paint/paint_op_perftest.cc b/chromium/cc/paint/paint_op_perftest.cc
index 08fd4130221..d38a6db6993 100644
--- a/chromium/cc/paint/paint_op_perftest.cc
+++ b/chromium/cc/paint/paint_op_perftest.cc
@@ -34,10 +34,10 @@ class PaintOpPerfTest : public testing::Test {
kTimeCheckInterval),
serialized_data_(static_cast<char*>(
base::AlignedAlloc(kMaxSerializedBufferBytes,
- PaintOpBuffer::PaintOpAlign))),
+ PaintOpBuffer::kPaintOpAlign))),
deserialized_data_(static_cast<char*>(
base::AlignedAlloc(sizeof(LargestPaintOp),
- PaintOpBuffer::PaintOpAlign))) {}
+ PaintOpBuffer::kPaintOpAlign))) {}
void RunTest(const std::string& name, const PaintOpBuffer& buffer) {
TestOptionsProvider test_options_provider;
diff --git a/chromium/cc/paint/paint_op_reader.cc b/chromium/cc/paint/paint_op_reader.cc
index ba4d35b4d76..df423a50e1e 100644
--- a/chromium/cc/paint/paint_op_reader.cc
+++ b/chromium/cc/paint/paint_op_reader.cc
@@ -77,7 +77,7 @@ bool PaintOpReader::ReadAndValidateOpHeader(const volatile void* input,
if (input_size < *skip)
return false;
- if (*skip % PaintOpBuffer::PaintOpAlign != 0)
+ if (*skip % PaintOpBuffer::kPaintOpAlign != 0)
return false;
if (*type > static_cast<uint8_t>(PaintOpType::LastPaintOpType))
return false;
@@ -112,11 +112,11 @@ void PaintOpReader::ReadSimple(T* val) {
uint8_t* PaintOpReader::CopyScratchSpace(size_t bytes) {
DCHECK(SkIsAlign4(reinterpret_cast<uintptr_t>(memory_)));
- if (options_.scratch_buffer->size() < bytes)
- options_.scratch_buffer->resize(bytes);
- memcpy(options_.scratch_buffer->data(), const_cast<const char*>(memory_),
+ if (options_->scratch_buffer->size() < bytes)
+ options_->scratch_buffer->resize(bytes);
+ memcpy(options_->scratch_buffer->data(), const_cast<const char*>(memory_),
bytes);
- return options_.scratch_buffer->data();
+ return options_->scratch_buffer->data();
}
template <typename T>
@@ -223,7 +223,7 @@ void PaintOpReader::Read(SkPath* path) {
case PaintCacheEntryState::kEmpty:
return;
case PaintCacheEntryState::kCached:
- if (!options_.paint_cache->GetPath(path_id, path))
+ if (!options_->paint_cache->GetPath(path_id, path))
SetInvalid(DeserializationError::kMissingPaintCachePathEntry);
return;
case PaintCacheEntryState::kInlined:
@@ -245,7 +245,7 @@ void PaintOpReader::Read(SkPath* path) {
return;
}
if (entry_state == PaintCacheEntryState::kInlined) {
- options_.paint_cache->PutPath(path_id, *path);
+ options_->paint_cache->PutPath(path_id, *path);
} else {
// If we know that this path will only be drawn once, which is
// implied by kInlinedDoNotCache, we signal to skia that it should not
@@ -352,7 +352,7 @@ void PaintOpReader::Read(PaintImage* image) {
}
if (serialized_type == PaintOp::SerializedImageType::kMailbox) {
- if (!options_.shared_image_provider) {
+ if (!options_->shared_image_provider) {
SetInvalid(DeserializationError::kMissingSharedImageProvider);
return;
}
@@ -366,7 +366,7 @@ void PaintOpReader::Read(PaintImage* image) {
SharedImageProvider::Error error;
sk_sp<SkImage> sk_image =
- options_.shared_image_provider->OpenSharedImageForRead(mailbox, error);
+ options_->shared_image_provider->OpenSharedImageForRead(mailbox, error);
if (error != SharedImageProvider::Error::kNoError) {
switch (error) {
case SharedImageProvider::Error::kNoAccess:
@@ -418,7 +418,7 @@ void PaintOpReader::Read(PaintImage* image) {
// The transfer cache entry for an image may not exist if the upload fails.
if (auto* entry =
- options_.transfer_cache->GetEntryAs<ServiceImageTransferCacheEntry>(
+ options_->transfer_cache->GetEntryAs<ServiceImageTransferCacheEntry>(
transfer_cache_entry_id)) {
if (needs_mips)
entry->EnsureMips();
@@ -485,7 +485,7 @@ void PaintOpReader::Read(sk_sp<GrSlug>* slug) {
}
*slug = GrSlug::Deserialize(const_cast<const char*>(memory_), data_bytes,
- options_.strike_client);
+ options_->strike_client);
DidRead(data_bytes);
if (!*slug) {
@@ -532,6 +532,7 @@ void PaintOpReader::Read(sk_sp<PaintShader>* shader) {
ReadSimple(&ref.end_point_);
ReadSimple(&ref.start_degrees_);
ReadSimple(&ref.end_degrees_);
+ ReadSimple(&ref.gradient_interpolation_);
Read(&ref.image_);
bool has_record = false;
ReadSimple(&has_record);
@@ -550,9 +551,9 @@ void PaintOpReader::Read(sk_sp<PaintShader>* shader) {
// Track dependent transfer cache entries to make cached shader size
// more realistic.
- size_t pre_size = options_.transfer_cache->GetTotalEntrySizes();
+ size_t pre_size = options_->transfer_cache->GetTotalEntrySizes();
size_t record_size = Read(&ref.record_);
- size_t post_size = options_.transfer_cache->GetTotalEntrySizes();
+ size_t post_size = options_->transfer_cache->GetTotalEntrySizes();
shader_size = post_size - pre_size + record_size;
ref.id_ = shader_id;
@@ -612,7 +613,7 @@ void PaintOpReader::Read(sk_sp<PaintShader>* shader) {
// transfer cache entries from needing to depend on other transfer cache
// entries.
auto* entry =
- options_.transfer_cache->GetEntryAs<ServiceShaderTransferCacheEntry>(
+ options_->transfer_cache->GetEntryAs<ServiceShaderTransferCacheEntry>(
shader_id);
// Only consider entries that use the same scale. This limits the service
// side transfer cache to only having one entry per shader but this will hit
@@ -623,7 +624,7 @@ void PaintOpReader::Read(sk_sp<PaintShader>* shader) {
} else {
ref.ResolveSkObjects();
DCHECK(ref.sk_cached_picture_);
- options_.transfer_cache->CreateLocalEntry(
+ options_->transfer_cache->CreateLocalEntry(
shader_id, std::make_unique<ServiceShaderTransferCacheEntry>(
*shader, shader_size));
}
@@ -699,7 +700,7 @@ void PaintOpReader::Read(gpu::Mailbox* mailbox) {
}
void PaintOpReader::Read(scoped_refptr<SkottieWrapper>* skottie) {
- if (!options_.is_privileged) {
+ if (!options_->is_privileged) {
valid_ = false;
return;
}
@@ -709,7 +710,7 @@ void PaintOpReader::Read(scoped_refptr<SkottieWrapper>* skottie) {
if (!valid_)
return;
auto* entry =
- options_.transfer_cache->GetEntryAs<ServiceSkottieTransferCacheEntry>(
+ options_->transfer_cache->GetEntryAs<ServiceSkottieTransferCacheEntry>(
transfer_cache_entry_id);
if (entry) {
*skottie = entry->skottie();
@@ -743,7 +744,7 @@ NOINLINE void PaintOpReader::SetInvalid(DeserializationError error) {
"PaintOpReader deserialization error");
base::UmaHistogramEnumeration("GPU.PaintOpReader.DeserializationError",
error);
- if (valid_ && options_.crash_dump_on_failure && base::RandInt(1, 10) == 1) {
+ if (valid_ && options_->crash_dump_on_failure && base::RandInt(1, 10) == 1) {
crash_reporter::ScopedCrashKeyString crash_key_scope(
&deserialization_error_crash_key,
base::NumberToString(static_cast<int>(error)));
@@ -857,9 +858,6 @@ void PaintOpReader::Read(sk_sp<PaintFilter>* filter) {
case PaintFilter::Type::kLightingSpot:
ReadLightingSpotPaintFilter(filter, crop_rect);
break;
- case PaintFilter::Type::kStretch:
- ReadStretchPaintFilter(filter, crop_rect);
- break;
}
}
@@ -1364,32 +1362,10 @@ void PaintOpReader::ReadLightingSpotPaintFilter(
std::move(input), base::OptionalToPtr(crop_rect)));
}
-void PaintOpReader::ReadStretchPaintFilter(
- sk_sp<PaintFilter>* filter,
- const absl::optional<PaintFilter::CropRect>& crop_rect) {
- SkScalar stretch_x = 0.f;
- SkScalar stretch_y = 0.f;
- SkScalar width = 0.f;
- SkScalar height = 0.f;
- sk_sp<PaintFilter> input;
-
- Read(&stretch_x);
- Read(&stretch_y);
- Read(&width);
- Read(&height);
- Read(&input);
-
- if (!valid_)
- return;
- filter->reset(new StretchPaintFilter(stretch_x, stretch_y, width, height,
- std::move(input),
- base::OptionalToPtr(crop_rect)));
-}
-
size_t PaintOpReader::Read(sk_sp<PaintRecord>* record) {
size_t size_bytes = 0;
ReadSize(&size_bytes);
- AlignMemory(PaintOpBuffer::PaintOpAlign);
+ AlignMemory(PaintOpBuffer::kPaintOpAlign);
if (enable_security_constraints_) {
// Validate that the record was not serialized if security constraints are
// enabled.
@@ -1407,7 +1383,7 @@ size_t PaintOpReader::Read(sk_sp<PaintRecord>* record) {
if (!valid_)
return 0;
- *record = PaintOpBuffer::MakeFromMemory(memory_, size_bytes, options_);
+ *record = PaintOpBuffer::MakeFromMemory(memory_, size_bytes, *options_);
if (!*record) {
SetInvalid(DeserializationError::kPaintOpBufferMakeFromMemoryFailure);
return 0;
diff --git a/chromium/cc/paint/paint_op_reader.h b/chromium/cc/paint/paint_op_reader.h
index 3ef81c8ea5c..5ca5cefbb29 100644
--- a/chromium/cc/paint/paint_op_reader.h
+++ b/chromium/cc/paint/paint_op_reader.h
@@ -5,6 +5,7 @@
#ifndef CC_PAINT_PAINT_OP_READER_H_
#define CC_PAINT_PAINT_OP_READER_H_
+#include "base/memory/raw_ref.h"
#include "base/memory/scoped_refptr.h"
#include "cc/paint/paint_export.h"
#include "cc/paint/paint_filter.h"
@@ -297,9 +298,6 @@ class CC_PAINT_EXPORT PaintOpReader {
void ReadLightingSpotPaintFilter(
sk_sp<PaintFilter>* filter,
const absl::optional<PaintFilter::CropRect>& crop_rect);
- void ReadStretchPaintFilter(
- sk_sp<PaintFilter>* filter,
- const absl::optional<PaintFilter::CropRect>& crop_rect);
// Returns the size of the read record, 0 if error.
size_t Read(sk_sp<PaintRecord>* record);
@@ -311,7 +309,7 @@ class CC_PAINT_EXPORT PaintOpReader {
const volatile char* memory_ = nullptr;
size_t remaining_bytes_ = 0u;
bool valid_ = true;
- const PaintOp::DeserializeOptions& options_;
+ const raw_ref<const PaintOp::DeserializeOptions> options_;
// Indicates that the data was serialized with the following constraints:
// 1) PaintRecords and SkDrawLoopers are ignored.
diff --git a/chromium/cc/paint/paint_op_writer.cc b/chromium/cc/paint/paint_op_writer.cc
index 2b5a028dfa3..758702afa1e 100644
--- a/chromium/cc/paint/paint_op_writer.cc
+++ b/chromium/cc/paint/paint_op_writer.cc
@@ -190,13 +190,13 @@ void PaintOpWriter::Write(const SkColor4f& color) {
void PaintOpWriter::Write(const SkPath& path, UsePaintCache use_paint_cache) {
auto id = path.getGenerationID();
- if (!options_.for_identifiability_study)
+ if (!options_->for_identifiability_study)
Write(id);
DCHECK(use_paint_cache == UsePaintCache::kEnabled ||
- !options_.paint_cache->Get(PaintCacheDataType::kPath, id));
+ !options_->paint_cache->Get(PaintCacheDataType::kPath, id));
if (use_paint_cache == UsePaintCache::kEnabled &&
- options_.paint_cache->Get(PaintCacheDataType::kPath, id)) {
+ options_->paint_cache->Get(PaintCacheDataType::kPath, id)) {
Write(static_cast<uint32_t>(PaintCacheEntryState::kCached));
return;
}
@@ -224,7 +224,7 @@ void PaintOpWriter::Write(const SkPath& path, UsePaintCache use_paint_cache) {
size_t bytes_written = path.writeToMemory(memory_);
DCHECK_EQ(bytes_written, bytes_required);
if (use_paint_cache == UsePaintCache::kEnabled) {
- options_.paint_cache->Put(PaintCacheDataType::kPath, id, bytes_written);
+ options_->paint_cache->Put(PaintCacheDataType::kPath, id, bytes_written);
}
*bytes_to_skip = bytes_written;
DidWrite(bytes_written);
@@ -284,7 +284,7 @@ void PaintOpWriter::Write(const DrawImage& draw_image,
}
// Default mode uses the transfer cache.
- auto decoded_image = options_.image_provider->GetRasterContent(draw_image);
+ auto decoded_image = options_->image_provider->GetRasterContent(draw_image);
DCHECK(!decoded_image.decoded_image().image())
<< "Use transfer cache for image serialization";
const DecodedDrawImage& decoded_draw_image = decoded_image.decoded_image();
@@ -305,14 +305,15 @@ void PaintOpWriter::Write(scoped_refptr<SkottieWrapper> skottie) {
return;
bool locked =
- options_.transfer_cache->LockEntry(TransferCacheEntryType::kSkottie, id);
+ options_->transfer_cache->LockEntry(TransferCacheEntryType::kSkottie, id);
// Add a cache entry for the skottie animation.
uint64_t bytes_written = 0u;
if (!locked) {
- bytes_written = options_.transfer_cache->CreateEntry(
+ bytes_written = options_->transfer_cache->CreateEntry(
ClientSkottieTransferCacheEntry(skottie), memory_);
- options_.transfer_cache->AssertLocked(TransferCacheEntryType::kSkottie, id);
+ options_->transfer_cache->AssertLocked(TransferCacheEntryType::kSkottie,
+ id);
}
DCHECK_LE(bytes_written, remaining_bytes_);
@@ -438,21 +439,21 @@ sk_sp<PaintShader> PaintOpWriter::TransformShaderIfNecessary(
if (type == PaintShader::Type::kImage) {
if (!original->paint_image().IsPaintWorklet()) {
- return original->CreateDecodedImage(ctm, quality, options_.image_provider,
- paint_image_transfer_cache_entry_id,
- &quality, paint_image_needs_mips,
- mailbox_out);
+ return original->CreateDecodedImage(
+ ctm, quality, options_->image_provider,
+ paint_image_transfer_cache_entry_id, &quality, paint_image_needs_mips,
+ mailbox_out);
}
sk_sp<PaintShader> record_shader =
- original->CreatePaintWorkletRecord(options_.image_provider);
+ original->CreatePaintWorkletRecord(options_->image_provider);
if (!record_shader)
return nullptr;
return record_shader->CreateScaledPaintRecord(
- ctm, options_.max_texture_size, paint_record_post_scale);
+ ctm, options_->max_texture_size, paint_record_post_scale);
}
if (type == PaintShader::Type::kPaintRecord) {
- return original->CreateScaledPaintRecord(ctm, options_.max_texture_size,
+ return original->CreateScaledPaintRecord(ctm, options_->max_texture_size,
paint_record_post_scale);
}
@@ -514,6 +515,7 @@ void PaintOpWriter::Write(const PaintShader* shader,
WriteSimple(shader->end_point_);
WriteSimple(shader->start_degrees_);
WriteSimple(shader->end_degrees_);
+ WriteSimple(shader->gradient_interpolation_);
if (enable_security_constraints_) {
DrawImage draw_image(shader->image_, false, MakeSrcRect(shader->image_),
@@ -532,7 +534,7 @@ void PaintOpWriter::Write(const PaintShader* shader,
if (shader->record_) {
Write(true);
DCHECK_NE(shader->id_, PaintShader::kInvalidRecordShaderId);
- if (!options_.for_identifiability_study)
+ if (!options_->for_identifiability_study)
Write(shader->id_);
const gfx::Rect playback_rect(
gfx::ToEnclosingRect(gfx::SkRectToRectF(shader->tile())));
@@ -691,9 +693,6 @@ void PaintOpWriter::Write(const PaintFilter* filter, const SkM44& current_ctm) {
case PaintFilter::Type::kLightingSpot:
Write(static_cast<const LightingSpotPaintFilter&>(*filter), current_ctm);
break;
- case PaintFilter::Type::kStretch:
- Write(static_cast<const StretchPaintFilter&>(*filter), current_ctm);
- break;
}
}
@@ -809,7 +808,7 @@ void PaintOpWriter::Write(const RecordPaintFilter& filter,
// analysis (e.g. this ensures any contained text blobs will not be missing
// from the cache).
auto scaled_filter = filter.CreateScaledPaintRecord(
- current_ctm.asM33(), options_.max_texture_size);
+ current_ctm.asM33(), options_->max_texture_size);
if (!scaled_filter) {
WriteSimple(false);
return;
@@ -917,19 +916,10 @@ void PaintOpWriter::Write(const LightingSpotPaintFilter& filter,
Write(filter.input().get(), current_ctm);
}
-void PaintOpWriter::Write(const StretchPaintFilter& filter,
- const SkM44& current_ctm) {
- WriteSimple(filter.stretch_x());
- WriteSimple(filter.stretch_y());
- WriteSimple(filter.width());
- WriteSimple(filter.height());
- Write(filter.input().get(), current_ctm);
-}
-
void PaintOpWriter::Write(const PaintRecord* record,
const gfx::Rect& playback_rect,
const gfx::SizeF& post_scale) {
- AlignMemory(PaintOpBuffer::PaintOpAlign);
+ AlignMemory(PaintOpBuffer::kPaintOpAlign);
// We need to record how many bytes we will serialize, but we don't know this
// information until we do the serialization. So, skip the amount needed
@@ -952,7 +942,7 @@ void PaintOpWriter::Write(const PaintRecord* record,
// converted to a fixed scale mode (hence |post_scale|), which means they are
// first rendered offscreen via SkImage::MakeFromPicture. This inherently does
// not support lcd text, so reflect that in the serialization options.
- PaintOp::SerializeOptions lcd_disabled_options = options_;
+ PaintOp::SerializeOptions lcd_disabled_options = *options_;
lcd_disabled_options.can_use_lcd_text = false;
SimpleBufferSerializer serializer(memory_, remaining_bytes_,
lcd_disabled_options);
diff --git a/chromium/cc/paint/paint_op_writer.h b/chromium/cc/paint/paint_op_writer.h
index 0a461b8f8ef..c1b92df686b 100644
--- a/chromium/cc/paint/paint_op_writer.h
+++ b/chromium/cc/paint/paint_op_writer.h
@@ -6,6 +6,7 @@
#define CC_PAINT_PAINT_OP_WRITER_H_
#include "base/memory/raw_ptr.h"
+#include "base/memory/raw_ref.h"
#include "cc/paint/paint_canvas.h"
#include "cc/paint/paint_export.h"
#include "cc/paint/paint_filter.h"
@@ -169,7 +170,6 @@ class CC_PAINT_EXPORT PaintOpWriter {
const SkM44& current_ctm);
void Write(const LightingPointPaintFilter& filter, const SkM44& current_ctm);
void Write(const LightingSpotPaintFilter& filter, const SkM44& current_ctm);
- void Write(const StretchPaintFilter& filter, const SkM44& current_ctm);
void Write(const PaintRecord* record,
const gfx::Rect& playback_rect,
@@ -192,7 +192,7 @@ class CC_PAINT_EXPORT PaintOpWriter {
raw_ptr<char> memory_ = nullptr;
size_t size_ = 0u;
size_t remaining_bytes_ = 0u;
- const PaintOp::SerializeOptions& options_;
+ const raw_ref<const PaintOp::SerializeOptions> options_;
bool valid_ = true;
// Indicates that the following security constraints must be applied during
diff --git a/chromium/cc/paint/paint_record.cc b/chromium/cc/paint/paint_record.cc
index f8c17777b1d..8f98f340c4e 100644
--- a/chromium/cc/paint/paint_record.cc
+++ b/chromium/cc/paint/paint_record.cc
@@ -4,33 +4,23 @@
#include "cc/paint/paint_record.h"
-#include "cc/paint/paint_op_buffer.h"
+#include <utility>
+
#include "third_party/skia/include/core/SkPictureRecorder.h"
namespace cc {
sk_sp<SkPicture> ToSkPicture(
- sk_sp<PaintRecord> record,
- const SkRect& bounds,
- ImageProvider* image_provider,
- PlaybackParams::CustomDataRasterCallback callback) {
- SkPictureRecorder recorder;
- SkCanvas* canvas = recorder.beginRecording(bounds);
- PlaybackParams params(image_provider);
- params.custom_callback = callback;
- record->Playback(canvas, params);
- return recorder.finishRecordingAsPicture();
-}
-
-sk_sp<const SkPicture> ToSkPicture(
sk_sp<const PaintRecord> record,
const SkRect& bounds,
ImageProvider* image_provider,
- PlaybackParams::CustomDataRasterCallback callback) {
+ PlaybackParams::CustomDataRasterCallback custom_callback,
+ PlaybackParams::ConvertOpCallback convert_op_callback) {
SkPictureRecorder recorder;
SkCanvas* canvas = recorder.beginRecording(bounds);
PlaybackParams params(image_provider);
- params.custom_callback = callback;
+ params.custom_callback = std::move(custom_callback);
+ params.convert_op_callback = std::move(convert_op_callback);
record->Playback(canvas, params);
return recorder.finishRecordingAsPicture();
}
diff --git a/chromium/cc/paint/paint_record.h b/chromium/cc/paint/paint_record.h
index 0cb56906a1a..ac495c71841 100644
--- a/chromium/cc/paint/paint_record.h
+++ b/chromium/cc/paint/paint_record.h
@@ -17,20 +17,14 @@ class ImageProvider;
// will become an interface in the future.
using PaintRecord = PaintOpBuffer;
-// TODO(enne): Remove these if possible, they are really expensive.
CC_PAINT_EXPORT sk_sp<SkPicture> ToSkPicture(
- sk_sp<PaintRecord> record,
- const SkRect& bounds,
- ImageProvider* image_provider = nullptr,
- PlaybackParams::CustomDataRasterCallback callback =
- PlaybackParams::CustomDataRasterCallback());
-
-CC_PAINT_EXPORT sk_sp<const SkPicture> ToSkPicture(
sk_sp<const PaintRecord> record,
const SkRect& bounds,
ImageProvider* image_provider = nullptr,
- PlaybackParams::CustomDataRasterCallback callback =
- PlaybackParams::CustomDataRasterCallback());
+ PlaybackParams::CustomDataRasterCallback custom_callback =
+ PlaybackParams::CustomDataRasterCallback(),
+ PlaybackParams::ConvertOpCallback convert_op_callback =
+ PlaybackParams::ConvertOpCallback());
} // namespace cc
diff --git a/chromium/cc/paint/paint_recorder.cc b/chromium/cc/paint/paint_recorder.cc
index d4dfaa603ef..e11367d6459 100644
--- a/chromium/cc/paint/paint_recorder.cc
+++ b/chromium/cc/paint/paint_recorder.cc
@@ -4,55 +4,41 @@
#include "cc/paint/paint_recorder.h"
-#include "cc/paint/display_item_list.h"
-#include "ui/gfx/geometry/skia_conversions.h"
+#include <utility>
namespace cc {
-PaintRecorder::PaintRecorder() {
- display_item_list_ = base::MakeRefCounted<DisplayItemList>(
- DisplayItemList::kToBeReleasedAsPaintOpBuffer);
-}
-PaintRecorder::~PaintRecorder() = default;
-
-PaintCanvas* PaintRecorder::beginRecording(const SkRect& bounds) {
- display_item_list_->StartPaint();
- canvas_ = CreateCanvas(display_item_list_.get(), bounds);
- return getRecordingCanvas();
+PaintCanvas* PaintRecorder::beginRecording() {
+ DCHECK(!is_recording_);
+ is_recording_ = true;
+ return &canvas_;
}
sk_sp<PaintRecord> PaintRecorder::finishRecordingAsPicture() {
- // SkPictureRecorder users expect that their saves are automatically
- // closed for them.
- //
- // NOTE: Blink paint in general doesn't appear to need this, but the
- // RecordingImageBufferSurface::fallBackToRasterCanvas finishing off the
- // current frame depends on this. Maybe we could remove this assumption and
- // just have callers do it.
- canvas_->restoreToCount(1);
-
- // Some users (e.g. printing) use the existence of the recording canvas
- // to know if recording is finished, so reset it here.
- canvas_.reset();
-
- // The rect doesn't matter, since we just release the record.
- display_item_list_->EndPaintOfUnpaired(gfx::Rect());
- display_item_list_->Finalize();
- return display_item_list_->ReleaseAsRecord();
+ DCHECK(is_recording_);
+ is_recording_ = false;
+ return canvas_.ReleaseAsRecord();
}
-std::unique_ptr<RecordPaintCanvas> PaintRecorder::CreateCanvas(
- DisplayItemList* list,
- const SkRect& bounds) {
- return std::make_unique<RecordPaintCanvas>(list, bounds);
-}
+InspectablePaintRecorder::InspectablePaintRecorder() = default;
+InspectablePaintRecorder::~InspectablePaintRecorder() = default;
+
+PaintCanvas* InspectablePaintRecorder::beginRecording(const gfx::Size& size) {
+ DCHECK(!is_recording_);
+ is_recording_ = true;
-bool PaintRecorder::ListHasDrawOps() const {
- return display_item_list_->has_draw_ops();
+ if (!canvas_ || size != size_) {
+ canvas_ = std::make_unique<InspectableRecordPaintCanvas>(size);
+ }
+ size_ = size;
+ return canvas_.get();
}
-size_t PaintRecorder::num_paint_ops() const {
- return display_item_list_->num_paint_ops();
+sk_sp<PaintRecord> InspectablePaintRecorder::finishRecordingAsPicture() {
+ DCHECK(canvas_);
+ DCHECK(is_recording_);
+ is_recording_ = false;
+ return canvas_->ReleaseAsRecord();
}
} // namespace cc
diff --git a/chromium/cc/paint/paint_recorder.h b/chromium/cc/paint/paint_recorder.h
index 229704542ea..410b299dfc5 100644
--- a/chromium/cc/paint/paint_recorder.h
+++ b/chromium/cc/paint/paint_recorder.h
@@ -7,52 +7,53 @@
#include <memory>
#include "base/compiler_specific.h"
-#include "cc/paint/display_item_list.h"
#include "cc/paint/paint_record.h"
#include "cc/paint/record_paint_canvas.h"
+#include "ui/gfx/geometry/size.h"
namespace cc {
-class DisplayItemList;
-
class CC_PAINT_EXPORT PaintRecorder {
public:
- PaintRecorder();
- PaintRecorder(const PaintRecorder&) = delete;
- virtual ~PaintRecorder();
-
- PaintRecorder& operator=(const PaintRecorder&) = delete;
-
- PaintCanvas* beginRecording(const SkRect& bounds);
+ // Begins recording. The returned PaintCanvas doesn't support inspection of
+ // the current clip and the CTM during recording.
+ PaintCanvas* beginRecording();
- // TODO(enne): should make everything go through the non-rect version.
- // See comments in RecordPaintCanvas ctor for why.
- PaintCanvas* beginRecording(SkScalar width, SkScalar height) {
- return beginRecording(SkRect::MakeWH(width, height));
- }
+ sk_sp<PaintRecord> finishRecordingAsPicture();
// Only valid while recording.
- ALWAYS_INLINE RecordPaintCanvas* getRecordingCanvas() {
- return canvas_.get();
+ PaintCanvas* getRecordingCanvas() {
+ return is_recording_ ? &canvas_ : nullptr;
}
- sk_sp<PaintRecord> finishRecordingAsPicture();
+ private:
+ bool is_recording_ = false;
+ RecordPaintCanvas canvas_;
+};
- bool ListHasDrawOps() const;
+class CC_PAINT_EXPORT InspectablePaintRecorder {
+ public:
+ InspectablePaintRecorder();
+ ~InspectablePaintRecorder();
- // Ops with nested paint ops are considered as a single op.
- size_t num_paint_ops() const;
+ // Begins recording. The returned PaintCanvas supports inspection of the
+ // current clip and the CTM during recording. `size` doesn't affect the
+ // recorded results because all operations will be recorded regardless of it,
+ // but it determines the top-level device clip.
+ PaintCanvas* beginRecording(const gfx::Size& size);
- size_t TotalOpCount() const { return display_item_list_->TotalOpCount(); }
- size_t OpBytesUsed() const { return display_item_list_->OpBytesUsed(); }
+ sk_sp<PaintRecord> finishRecordingAsPicture();
- protected:
- virtual std::unique_ptr<RecordPaintCanvas> CreateCanvas(DisplayItemList* list,
- const SkRect& bounds);
+ // Only valid while recording.
+ PaintCanvas* getRecordingCanvas() const {
+ DCHECK(!is_recording_ || canvas_);
+ return is_recording_ ? canvas_.get() : nullptr;
+ }
private:
- scoped_refptr<DisplayItemList> display_item_list_;
- std::unique_ptr<RecordPaintCanvas> canvas_;
+ bool is_recording_ = false;
+ std::unique_ptr<InspectableRecordPaintCanvas> canvas_;
+ gfx::Size size_;
};
} // namespace cc
diff --git a/chromium/cc/paint/paint_shader.cc b/chromium/cc/paint/paint_shader.cc
index ee909e0a7a0..dcda62b102e 100644
--- a/chromium/cc/paint/paint_shader.cc
+++ b/chromium/cc/paint/paint_shader.cc
@@ -75,14 +75,16 @@ sk_sp<PaintShader> PaintShader::MakeColor(SkColor4f color) {
return shader;
}
-sk_sp<PaintShader> PaintShader::MakeLinearGradient(const SkPoint points[],
- const SkColor4f colors[],
- const SkScalar pos[],
- int count,
- SkTileMode mode,
- uint32_t flags,
- const SkMatrix* local_matrix,
- SkColor4f fallback_color) {
+sk_sp<PaintShader> PaintShader::MakeLinearGradient(
+ const SkPoint points[],
+ const SkColor4f colors[],
+ const SkScalar pos[],
+ int count,
+ SkTileMode mode,
+ SkGradientShader::Interpolation interpolation,
+ uint32_t flags,
+ const SkMatrix* local_matrix,
+ SkColor4f fallback_color) {
sk_sp<PaintShader> shader(new PaintShader(Type::kLinearGradient));
// There are always two points, the start and the end.
@@ -91,20 +93,23 @@ sk_sp<PaintShader> PaintShader::MakeLinearGradient(const SkPoint points[],
shader->SetColorsAndPositions(colors, pos, count);
shader->SetMatrixAndTiling(local_matrix, mode, mode);
shader->SetFlagsAndFallback(flags, fallback_color);
+ shader->SetGradientInterpolation(interpolation);
shader->ResolveSkObjects();
return shader;
}
-sk_sp<PaintShader> PaintShader::MakeRadialGradient(const SkPoint& center,
- SkScalar radius,
- const SkColor4f colors[],
- const SkScalar pos[],
- int count,
- SkTileMode mode,
- uint32_t flags,
- const SkMatrix* local_matrix,
- SkColor4f fallback_color) {
+sk_sp<PaintShader> PaintShader::MakeRadialGradient(
+ const SkPoint& center,
+ SkScalar radius,
+ const SkColor4f colors[],
+ const SkScalar pos[],
+ int count,
+ SkTileMode mode,
+ SkGradientShader::Interpolation interpolation,
+ uint32_t flags,
+ const SkMatrix* local_matrix,
+ SkColor4f fallback_color) {
sk_sp<PaintShader> shader(new PaintShader(Type::kRadialGradient));
shader->center_ = center;
@@ -112,6 +117,7 @@ sk_sp<PaintShader> PaintShader::MakeRadialGradient(const SkPoint& center,
shader->SetColorsAndPositions(colors, pos, count);
shader->SetMatrixAndTiling(local_matrix, mode, mode);
shader->SetFlagsAndFallback(flags, fallback_color);
+ shader->SetGradientInterpolation(interpolation);
shader->ResolveSkObjects();
return shader;
@@ -126,6 +132,7 @@ sk_sp<PaintShader> PaintShader::MakeTwoPointConicalGradient(
const SkScalar pos[],
int count,
SkTileMode mode,
+ SkGradientShader::Interpolation interpolation,
uint32_t flags,
const SkMatrix* local_matrix,
SkColor4f fallback_color) {
@@ -138,22 +145,25 @@ sk_sp<PaintShader> PaintShader::MakeTwoPointConicalGradient(
shader->SetColorsAndPositions(colors, pos, count);
shader->SetMatrixAndTiling(local_matrix, mode, mode);
shader->SetFlagsAndFallback(flags, fallback_color);
+ shader->SetGradientInterpolation(interpolation);
shader->ResolveSkObjects();
return shader;
}
-sk_sp<PaintShader> PaintShader::MakeSweepGradient(SkScalar cx,
- SkScalar cy,
- const SkColor4f colors[],
- const SkScalar pos[],
- int color_count,
- SkTileMode mode,
- SkScalar start_degrees,
- SkScalar end_degrees,
- uint32_t flags,
- const SkMatrix* local_matrix,
- SkColor4f fallback_color) {
+sk_sp<PaintShader> PaintShader::MakeSweepGradient(
+ SkScalar cx,
+ SkScalar cy,
+ const SkColor4f colors[],
+ const SkScalar pos[],
+ int color_count,
+ SkTileMode mode,
+ SkScalar start_degrees,
+ SkScalar end_degrees,
+ SkGradientShader::Interpolation interpolation,
+ uint32_t flags,
+ const SkMatrix* local_matrix,
+ SkColor4f fallback_color) {
sk_sp<PaintShader> shader(new PaintShader(Type::kSweepGradient));
shader->center_ = SkPoint::Make(cx, cy);
@@ -162,6 +172,7 @@ sk_sp<PaintShader> PaintShader::MakeSweepGradient(SkScalar cx,
shader->SetColorsAndPositions(colors, pos, color_count);
shader->SetMatrixAndTiling(local_matrix, mode, mode);
shader->SetFlagsAndFallback(flags, fallback_color);
+ shader->SetGradientInterpolation(interpolation);
shader->ResolveSkObjects();
return shader;
@@ -386,13 +397,6 @@ sk_sp<SkShader> PaintShader::GetSkShader(
SkSamplingOptions sampling(
PaintFlags::FilterQualityToSkSamplingOptions(quality));
- // TODO(crbug/1308932): Remove this helper vector colors and make all
- // SkColor4f.
- std::vector<SkColor> colors;
- colors.reserve(colors.size());
- for (auto& c : colors_)
- colors.push_back(c.toSkColor());
-
switch (shader_type_) {
case Type::kEmpty:
return SkShaders::Empty();
@@ -401,12 +405,10 @@ sk_sp<SkShader> PaintShader::GetSkShader(
break;
case Type::kLinearGradient: {
SkPoint points[2] = {start_point_, end_point_};
- // TODO(crbug/1308932): Remove this helper vector colors and make all
- // SkColor4f.
return SkGradientShader::MakeLinear(
- points, colors.data(),
+ points, colors_.data(), nullptr /*sk_sp<SkColorSpace>*/,
positions_.empty() ? nullptr : positions_.data(),
- static_cast<int>(colors.size()), tx_, flags_,
+ static_cast<int>(colors_.size()), tx_, gradient_interpolation_,
base::OptionalToPtr(local_matrix_));
}
case Type::kRadialGradient:
@@ -414,14 +416,14 @@ sk_sp<SkShader> PaintShader::GetSkShader(
center_, start_radius_, colors_.data(),
nullptr /*sk_sp<SkColorSpace>*/,
positions_.empty() ? nullptr : positions_.data(),
- static_cast<int>(colors_.size()), tx_, flags_,
+ static_cast<int>(colors_.size()), tx_, gradient_interpolation_,
base::OptionalToPtr(local_matrix_));
case Type::kTwoPointConicalGradient:
return SkGradientShader::MakeTwoPointConical(
start_point_, start_radius_, end_point_, end_radius_, colors_.data(),
nullptr /*sk_sp<SkColorSpace>*/,
positions_.empty() ? nullptr : positions_.data(),
- static_cast<int>(colors_.size()), tx_, flags_,
+ static_cast<int>(colors_.size()), tx_, gradient_interpolation_,
base::OptionalToPtr(local_matrix_));
case Type::kSweepGradient:
return SkGradientShader::MakeSweep(
@@ -429,7 +431,7 @@ sk_sp<SkShader> PaintShader::GetSkShader(
nullptr /*sk_sp<SkColorSpace>*/,
positions_.empty() ? nullptr : positions_.data(),
static_cast<int>(colors_.size()), tx_, start_degrees_, end_degrees_,
- flags_, base::OptionalToPtr(local_matrix_));
+ gradient_interpolation_, base::OptionalToPtr(local_matrix_));
case Type::kImage:
if (sk_cached_image_) {
return sk_cached_image_->makeShader(tx_, ty_, sampling,
diff --git a/chromium/cc/paint/paint_shader.h b/chromium/cc/paint/paint_shader.h
index 1cc771ec2b3..9344725905c 100644
--- a/chromium/cc/paint/paint_shader.h
+++ b/chromium/cc/paint/paint_shader.h
@@ -16,6 +16,7 @@
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/skia/include/core/SkImage.h"
#include "third_party/skia/include/core/SkScalar.h"
+#include "third_party/skia/include/effects/SkGradientShader.h"
#include "ui/gfx/geometry/size_f.h"
class SkShader;
@@ -62,6 +63,7 @@ class CC_PAINT_EXPORT PaintShader : public SkRefCnt {
const SkScalar* pos,
int count,
SkTileMode mode,
+ SkGradientShader::Interpolation interpolation = DefaultInterpolation(),
uint32_t flags = 0,
const SkMatrix* local_matrix = nullptr,
SkColor4f fallback_color = SkColors::kTransparent);
@@ -73,6 +75,7 @@ class CC_PAINT_EXPORT PaintShader : public SkRefCnt {
const SkScalar pos[],
int color_count,
SkTileMode mode,
+ SkGradientShader::Interpolation interpolation = DefaultInterpolation(),
uint32_t flags = 0,
const SkMatrix* local_matrix = nullptr,
SkColor4f fallback_color = SkColors::kTransparent);
@@ -86,6 +89,7 @@ class CC_PAINT_EXPORT PaintShader : public SkRefCnt {
const SkScalar pos[],
int color_count,
SkTileMode mode,
+ SkGradientShader::Interpolation interpolation = DefaultInterpolation(),
uint32_t flags = 0,
const SkMatrix* local_matrix = nullptr,
SkColor4f fallback_color = SkColors::kTransparent);
@@ -99,6 +103,7 @@ class CC_PAINT_EXPORT PaintShader : public SkRefCnt {
SkTileMode mode,
SkScalar start_degrees,
SkScalar end_degrees,
+ SkGradientShader::Interpolation interpolation = DefaultInterpolation(),
uint32_t flags = 0,
const SkMatrix* local_matrix = nullptr,
SkColor4f fallback_color = SkColors::kTransparent);
@@ -183,6 +188,11 @@ class CC_PAINT_EXPORT PaintShader : public SkRefCnt {
FRIEND_TEST_ALL_PREFIXES(PaintOpBufferTest, PaintRecordShaderSerialization);
FRIEND_TEST_ALL_PREFIXES(PaintOpBufferTest, RecordShadersCached);
+ static SkGradientShader::Interpolation DefaultInterpolation() {
+ SkGradientShader::Interpolation default_interpolation;
+ return default_interpolation;
+ }
+
explicit PaintShader(Type type);
bool GetClampedRasterizationTileRect(const SkMatrix& ctm,
@@ -231,6 +241,9 @@ class CC_PAINT_EXPORT PaintShader : public SkRefCnt {
int count);
void SetMatrixAndTiling(const SkMatrix* matrix, SkTileMode tx, SkTileMode ty);
void SetFlagsAndFallback(uint32_t flags, SkColor4f fallback_color);
+ void SetGradientInterpolation(SkGradientShader::Interpolation interpolation) {
+ gradient_interpolation_ = interpolation;
+ }
Type shader_type_ = Type::kShaderCount;
@@ -263,6 +276,8 @@ class CC_PAINT_EXPORT PaintShader : public SkRefCnt {
std::vector<SkColor4f> colors_;
std::vector<SkScalar> positions_;
+ SkGradientShader::Interpolation gradient_interpolation_;
+
// Cached intermediates, for Paint objects that may not be thread-safe
sk_sp<SkPicture> sk_cached_picture_;
sk_sp<SkImage> sk_cached_image_;
diff --git a/chromium/cc/paint/paint_shader_unittest.cc b/chromium/cc/paint/paint_shader_unittest.cc
index 8a9a1fb8d67..32fb20e7747 100644
--- a/chromium/cc/paint/paint_shader_unittest.cc
+++ b/chromium/cc/paint/paint_shader_unittest.cc
@@ -7,7 +7,7 @@
#include "cc/paint/draw_image.h"
#include "cc/paint/image_provider.h"
#include "cc/paint/paint_image_builder.h"
-#include "cc/paint/paint_op_buffer.h"
+#include "cc/paint/paint_op.h"
#include "cc/test/fake_paint_image_generator.h"
#include "cc/test/skia_common.h"
#include "cc/test/test_skcanvas.h"
diff --git a/chromium/cc/paint/record_paint_canvas.cc b/chromium/cc/paint/record_paint_canvas.cc
index 6f378a60a88..d08866332b1 100644
--- a/chromium/cc/paint/record_paint_canvas.cc
+++ b/chromium/cc/paint/record_paint_canvas.cc
@@ -6,8 +6,8 @@
#include <utility>
-#include "cc/paint/display_item_list.h"
#include "cc/paint/paint_image_builder.h"
+#include "cc/paint/paint_op.h"
#include "cc/paint/paint_record.h"
#include "cc/paint/paint_recorder.h"
#include "cc/paint/skottie_frame_data.h"
@@ -18,20 +18,19 @@
namespace cc {
-RecordPaintCanvas::RecordPaintCanvas(DisplayItemList* list,
- const SkRect& bounds)
- : list_(list), recording_bounds_(bounds) {
- DCHECK(list_);
-}
-
+RecordPaintCanvas::RecordPaintCanvas() = default;
RecordPaintCanvas::~RecordPaintCanvas() = default;
-SkImageInfo RecordPaintCanvas::imageInfo() const {
- return GetCanvas()->imageInfo();
+sk_sp<PaintRecord> RecordPaintCanvas::ReleaseAsRecord() {
+ // Some users expect that their saves are automatically closed for them.
+ // Maybe we could remove this assumption and just have callers do it.
+ restoreToCount(1);
+ needs_flush_ = false;
+ return buffer_.MoveRetainingBufferIfPossible();
}
template <typename T, typename... Args>
-size_t RecordPaintCanvas::push(Args&&... args) {
+void RecordPaintCanvas::push(Args&&... args) {
#if DCHECK_IS_ON()
// The following check fails if client code does not check and handle
// NeedsFlush() before issuing draw calls.
@@ -43,7 +42,7 @@ size_t RecordPaintCanvas::push(Args&&... args) {
(std::is_same<T, RestoreOp>::value) ||
(std::is_same<T, SetNodeIdOp>::value));
#endif
- return list_->push<T>(std::forward<Args>(args)...);
+ buffer_.push<T>(std::forward<Args>(args)...);
}
void* RecordPaintCanvas::accessTopLayerPixels(SkImageInfo* info,
@@ -58,9 +57,9 @@ void RecordPaintCanvas::flush() {
// pipeline. So instead we make note of the flush request so that it can be
// handled by code that owns the recording.
//
- // Note: The value of needs_flush_ never gets reset. That is because
- // flushing a recording implies closing this RecordPaintCanvas and starting a
- // new one.
+ // Note: The value of needs_flush_ never gets reset until the end of
+ // recording. That is because flushing a recording implies ReleaseAsRecord()
+ // and starting a new recording.
needs_flush_ = true;
}
@@ -70,52 +69,44 @@ bool RecordPaintCanvas::NeedsFlush() const {
int RecordPaintCanvas::save() {
push<SaveOp>();
- return GetCanvas()->save();
+ return save_count_++;
}
int RecordPaintCanvas::saveLayer(const SkRect* bounds,
const PaintFlags* flags) {
- if (flags) {
- if (flags->IsSimpleOpacity()) {
- // TODO(enne): maybe more callers should know this and call
- // saveLayerAlpha instead of needing to check here.
- uint8_t alpha = SkColorGetA(flags->getColor());
- return saveLayerAlpha(bounds, alpha);
- }
-
- // TODO(enne): it appears that image filters affect matrices and color
- // matrices affect transparent flags on SkCanvas layers, but it's not clear
- // whether those are actually needed and we could just skip ToSkPaint here.
- push<SaveLayerOp>(bounds, flags);
- SkPaint paint = flags->ToSkPaint();
- return GetCanvas()->saveLayer(bounds, &paint);
+ if (flags && flags->IsSimpleOpacity()) {
+ // TODO(enne): maybe more callers should know this and call
+ // saveLayerAlpha instead of needing to check here.
+ uint8_t alpha = SkColorGetA(flags->getColor());
+ return saveLayerAlpha(bounds, alpha);
}
+ return saveLayerInternal(bounds, flags);
+}
+
+int RecordPaintCanvas::saveLayerInternal(const SkRect* bounds,
+ const PaintFlags* flags) {
push<SaveLayerOp>(bounds, flags);
- return GetCanvas()->saveLayer(bounds, nullptr);
+ return save_count_++;
}
int RecordPaintCanvas::saveLayerAlpha(const SkRect* bounds, uint8_t alpha) {
push<SaveLayerAlphaOp>(bounds, static_cast<float>(alpha / 255.0f));
- return GetCanvas()->saveLayerAlpha(bounds, alpha);
+ return save_count_++;
}
void RecordPaintCanvas::restore() {
push<RestoreOp>();
- GetCanvas()->restore();
+ --save_count_;
+ DCHECK_GE(save_count_, 1);
}
int RecordPaintCanvas::getSaveCount() const {
- return GetCanvas()->getSaveCount();
+ return save_count_;
}
void RecordPaintCanvas::restoreToCount(int save_count) {
- if (!canvas_) {
- DCHECK_EQ(save_count, 1);
- return;
- }
-
DCHECK_GE(save_count, 1);
- int diff = GetCanvas()->getSaveCount() - save_count;
+ int diff = getSaveCount() - save_count;
DCHECK_GE(diff, 0);
for (int i = 0; i < diff; ++i)
restore();
@@ -123,68 +114,59 @@ void RecordPaintCanvas::restoreToCount(int save_count) {
void RecordPaintCanvas::translate(SkScalar dx, SkScalar dy) {
push<TranslateOp>(dx, dy);
- GetCanvas()->translate(dx, dy);
}
void RecordPaintCanvas::scale(SkScalar sx, SkScalar sy) {
push<ScaleOp>(sx, sy);
- GetCanvas()->scale(sx, sy);
}
void RecordPaintCanvas::rotate(SkScalar degrees) {
push<RotateOp>(degrees);
- GetCanvas()->rotate(degrees);
}
void RecordPaintCanvas::concat(const SkMatrix& matrix) {
- SkM44 m = SkM44(matrix);
- push<ConcatOp>(m);
- GetCanvas()->concat(m);
+ concat(SkM44(matrix));
}
void RecordPaintCanvas::concat(const SkM44& matrix) {
push<ConcatOp>(matrix);
- GetCanvas()->concat(matrix);
}
void RecordPaintCanvas::setMatrix(const SkMatrix& matrix) {
- SkM44 m = SkM44(matrix);
- push<SetMatrixOp>(m);
- GetCanvas()->setMatrix(m);
+ setMatrix(SkM44(matrix));
}
void RecordPaintCanvas::setMatrix(const SkM44& matrix) {
push<SetMatrixOp>(matrix);
- GetCanvas()->setMatrix(matrix);
}
void RecordPaintCanvas::clipRect(const SkRect& rect,
SkClipOp op,
bool antialias) {
push<ClipRectOp>(rect, op, antialias);
- GetCanvas()->clipRect(rect, op, antialias);
}
void RecordPaintCanvas::clipRRect(const SkRRect& rrect,
SkClipOp op,
bool antialias) {
- // TODO(enne): does this happen? Should the caller know this?
if (rrect.isRect()) {
clipRect(rrect.getBounds(), op, antialias);
return;
}
+ clipRRectInternal(rrect, op, antialias);
+}
+
+void RecordPaintCanvas::clipRRectInternal(const SkRRect& rrect,
+ SkClipOp op,
+ bool antialias) {
push<ClipRRectOp>(rrect, op, antialias);
- GetCanvas()->clipRRect(rrect, op, antialias);
}
void RecordPaintCanvas::clipPath(const SkPath& path,
SkClipOp op,
bool antialias,
UsePaintCache use_paint_cache) {
- if (!path.isInverseFillType() &&
- GetCanvas()->getTotalMatrix().rectStaysRect()) {
- // TODO(enne): do these cases happen? should the caller know that this isn't
- // a path?
+ if (!path.isInverseFillType()) {
SkRect rect;
if (path.isRect(&rect)) {
clipRect(rect, op, antialias);
@@ -201,30 +183,54 @@ void RecordPaintCanvas::clipPath(const SkPath& path,
return;
}
}
+ clipPathInternal(path, op, antialias, use_paint_cache);
+}
+void RecordPaintCanvas::clipPathInternal(const SkPath& path,
+ SkClipOp op,
+ bool antialias,
+ UsePaintCache use_paint_cache) {
push<ClipPathOp>(path, op, antialias, use_paint_cache);
- GetCanvas()->clipPath(path, op, antialias);
- return;
+}
+
+SkImageInfo RecordPaintCanvas::imageInfo() const {
+ NOTREACHED();
+ return SkImageInfo();
}
SkRect RecordPaintCanvas::getLocalClipBounds() const {
- DCHECK(InitializedWithRecordingBounds());
- return GetCanvas()->getLocalClipBounds();
+ NOTREACHED();
+ return SkRect();
}
bool RecordPaintCanvas::getLocalClipBounds(SkRect* bounds) const {
- DCHECK(InitializedWithRecordingBounds());
- return GetCanvas()->getLocalClipBounds(bounds);
+ NOTREACHED();
+ return false;
}
SkIRect RecordPaintCanvas::getDeviceClipBounds() const {
- DCHECK(InitializedWithRecordingBounds());
- return GetCanvas()->getDeviceClipBounds();
+ NOTREACHED();
+ return SkIRect();
}
bool RecordPaintCanvas::getDeviceClipBounds(SkIRect* bounds) const {
- DCHECK(InitializedWithRecordingBounds());
- return GetCanvas()->getDeviceClipBounds(bounds);
+ NOTREACHED();
+ return false;
+}
+
+bool RecordPaintCanvas::isClipEmpty() const {
+ NOTREACHED();
+ return true;
+}
+
+SkMatrix RecordPaintCanvas::getTotalMatrix() const {
+ NOTREACHED();
+ return SkMatrix();
+}
+
+SkM44 RecordPaintCanvas::getLocalToDevice() const {
+ NOTREACHED();
+ return SkM44();
}
void RecordPaintCanvas::drawColor(SkColor4f color, SkBlendMode mode) {
@@ -341,19 +347,6 @@ void RecordPaintCanvas::drawPicture(sk_sp<const PaintRecord> record) {
push<DrawRecordOp>(record);
}
-bool RecordPaintCanvas::isClipEmpty() const {
- DCHECK(InitializedWithRecordingBounds());
- return GetCanvas()->isClipEmpty();
-}
-
-SkMatrix RecordPaintCanvas::getTotalMatrix() const {
- return GetCanvas()->getTotalMatrix();
-}
-
-SkM44 RecordPaintCanvas::getLocalToDevice() const {
- return GetCanvas()->getLocalToDevice();
-}
-
void RecordPaintCanvas::Annotate(AnnotationType type,
const SkRect& rect,
sk_sp<SkData> data) {
@@ -368,34 +361,129 @@ void RecordPaintCanvas::setNodeId(int node_id) {
push<SetNodeIdOp>(node_id);
}
-const SkNoDrawCanvas* RecordPaintCanvas::GetCanvas() const {
- return const_cast<RecordPaintCanvas*>(this)->GetCanvas();
+InspectableRecordPaintCanvas::InspectableRecordPaintCanvas(
+ const gfx::Size& size)
+ : canvas_(size.width(), size.height()) {}
+
+InspectableRecordPaintCanvas::~InspectableRecordPaintCanvas() = default;
+
+int InspectableRecordPaintCanvas::save() {
+ return CheckSaveCount(RecordPaintCanvas::save(), canvas_.save());
+}
+
+int InspectableRecordPaintCanvas::saveLayerInternal(const SkRect* bounds,
+ const PaintFlags* flags) {
+ int canvas_prev_save_count;
+ // TODO(enne): it appears that image filters affect matrices and color
+ // matrices affect transparent flags on SkCanvas layers, but it's not clear
+ // whether those are actually needed and we could just skip ToSkPaint here.
+ if (flags) {
+ SkPaint paint = flags->ToSkPaint();
+ canvas_prev_save_count = canvas_.saveLayer(bounds, &paint);
+ } else {
+ canvas_prev_save_count = canvas_.saveLayer(bounds, nullptr);
+ }
+ return CheckSaveCount(RecordPaintCanvas::saveLayerInternal(bounds, flags),
+ canvas_prev_save_count);
+}
+
+int InspectableRecordPaintCanvas::saveLayerAlpha(const SkRect* bounds,
+ uint8_t alpha) {
+ return CheckSaveCount(RecordPaintCanvas::saveLayerAlpha(bounds, alpha),
+ canvas_.saveLayerAlpha(bounds, alpha));
+}
+
+void InspectableRecordPaintCanvas::restore() {
+ RecordPaintCanvas::restore();
+ canvas_.restore();
+ DCHECK_EQ(getSaveCount(), canvas_.getSaveCount());
+}
+
+int InspectableRecordPaintCanvas::CheckSaveCount(int super_prev_save_count,
+ int canvas_prev_save_count) {
+ DCHECK_EQ(super_prev_save_count, canvas_prev_save_count);
+ DCHECK_EQ(getSaveCount(), canvas_.getSaveCount());
+ return super_prev_save_count;
+}
+
+void InspectableRecordPaintCanvas::translate(SkScalar dx, SkScalar dy) {
+ RecordPaintCanvas::translate(dx, dy);
+ canvas_.translate(dx, dy);
+}
+
+void InspectableRecordPaintCanvas::scale(SkScalar sx, SkScalar sy) {
+ RecordPaintCanvas::scale(sx, sy);
+ canvas_.scale(sx, sy);
+}
+
+void InspectableRecordPaintCanvas::rotate(SkScalar degrees) {
+ RecordPaintCanvas::rotate(degrees);
+ canvas_.rotate(degrees);
+}
+
+void InspectableRecordPaintCanvas::concat(const SkM44& matrix) {
+ RecordPaintCanvas::concat(matrix);
+ canvas_.concat(matrix);
+}
+
+void InspectableRecordPaintCanvas::setMatrix(const SkM44& matrix) {
+ RecordPaintCanvas::setMatrix(matrix);
+ canvas_.setMatrix(matrix);
+}
+
+void InspectableRecordPaintCanvas::clipRect(const SkRect& rect,
+ SkClipOp op,
+ bool antialias) {
+ RecordPaintCanvas::clipRect(rect, op, antialias);
+ canvas_.clipRect(rect, op, antialias);
}
-SkNoDrawCanvas* RecordPaintCanvas::GetCanvas() {
- if (canvas_)
- return &*canvas_;
+void InspectableRecordPaintCanvas::clipRRectInternal(const SkRRect& rrect,
+ SkClipOp op,
+ bool antialias) {
+ RecordPaintCanvas::clipRRectInternal(rrect, op, antialias);
+ canvas_.clipRRect(rrect, op, antialias);
+}
+
+void InspectableRecordPaintCanvas::clipPathInternal(
+ const SkPath& path,
+ SkClipOp op,
+ bool antialias,
+ UsePaintCache use_paint_cache) {
+ RecordPaintCanvas::clipPathInternal(path, op, antialias, use_paint_cache);
+ canvas_.clipPath(path, op, antialias);
+}
+
+SkImageInfo InspectableRecordPaintCanvas::imageInfo() const {
+ return canvas_.imageInfo();
+}
- // Size the canvas to be large enough to contain the |recording_bounds|, which
- // may not be positioned at the origin.
- SkIRect enclosing_rect = recording_bounds_.roundOut();
- canvas_.emplace(enclosing_rect.right(), enclosing_rect.bottom());
+SkRect InspectableRecordPaintCanvas::getLocalClipBounds() const {
+ return canvas_.getLocalClipBounds();
+}
+
+bool InspectableRecordPaintCanvas::getLocalClipBounds(SkRect* bounds) const {
+ return canvas_.getLocalClipBounds(bounds);
+}
+
+SkIRect InspectableRecordPaintCanvas::getDeviceClipBounds() const {
+ return canvas_.getDeviceClipBounds();
+}
+
+bool InspectableRecordPaintCanvas::getDeviceClipBounds(SkIRect* bounds) const {
+ return canvas_.getDeviceClipBounds(bounds);
+}
+
+bool InspectableRecordPaintCanvas::isClipEmpty() const {
+ return canvas_.isClipEmpty();
+}
- // This is part of the "recording canvases have a size, but why" dance.
- // By creating a canvas of size (right x bottom) and then clipping it,
- // It makes getDeviceClipBounds return the original cull rect, which code
- // in GraphicsContextCanvas on Mac expects. (Just creating an SkNoDrawCanvas
- // with the recording_bounds_ makes a canvas of size (width x height) instead
- // which is incorrect. SkRecorder cheats with private resetForNextCanvas.
- canvas_->clipRect(recording_bounds_, SkClipOp::kIntersect, false);
- return &*canvas_;
+SkMatrix InspectableRecordPaintCanvas::getTotalMatrix() const {
+ return canvas_.getTotalMatrix();
}
-bool RecordPaintCanvas::InitializedWithRecordingBounds() const {
- // If the RecordPaintCanvas is initialized with an empty bounds then
- // the various clip related functions are not valid and should not
- // be called.
- return !recording_bounds_.isEmpty();
+SkM44 InspectableRecordPaintCanvas::getLocalToDevice() const {
+ return canvas_.getLocalToDevice();
}
} // namespace cc
diff --git a/chromium/cc/paint/record_paint_canvas.h b/chromium/cc/paint/record_paint_canvas.h
index 456b6d1e6f5..4980f8c30c7 100644
--- a/chromium/cc/paint/record_paint_canvas.h
+++ b/chromium/cc/paint/record_paint_canvas.h
@@ -10,6 +10,7 @@
#include "build/build_config.h"
#include "cc/paint/paint_canvas.h"
#include "cc/paint/paint_flags.h"
+#include "cc/paint/paint_op_buffer.h"
#include "cc/paint/paint_record.h"
#include "cc/paint/skottie_color_map.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
@@ -17,55 +18,69 @@
namespace cc {
-class DisplayItemList;
-class PaintFlags;
-
+// This implementation of PaintCanvas records paint operations into the given
+// PaintOpBuffer. The methods that inspect the current clip or CTM are not
+// implemented (DCHECK will fail if called). Use InspectableRecordPaintCanvas
+// instead if the client needs to call those methods.
class CC_PAINT_EXPORT RecordPaintCanvas : public PaintCanvas {
public:
- RecordPaintCanvas(DisplayItemList* list, const SkRect& bounds);
- RecordPaintCanvas(const RecordPaintCanvas&) = delete;
+ RecordPaintCanvas();
~RecordPaintCanvas() override;
+ RecordPaintCanvas(const RecordPaintCanvas&) = delete;
RecordPaintCanvas& operator=(const RecordPaintCanvas&) = delete;
- SkImageInfo imageInfo() const override;
+ virtual sk_sp<PaintRecord> ReleaseAsRecord();
+
+ bool HasRecordedDrawOps() const { return buffer_.has_draw_ops(); }
+ size_t TotalOpCount() const { return buffer_.total_op_count(); }
+ size_t OpBytesUsed() const { return buffer_.paint_ops_size(); }
void* accessTopLayerPixels(SkImageInfo* info,
size_t* rowBytes,
SkIPoint* origin = nullptr) override;
void flush() override;
+ bool NeedsFlush() const override;
int save() override;
- int saveLayer(const SkRect* bounds, const PaintFlags* flags) override;
+ int saveLayer(const SkRect* bounds, const PaintFlags* flags) final;
int saveLayerAlpha(const SkRect* bounds, uint8_t alpha) override;
-
void restore() override;
- int getSaveCount() const override;
+ int getSaveCount() const final;
void restoreToCount(int save_count) override;
+
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 SkMatrix& matrix) final;
+ void setMatrix(const SkMatrix& matrix) final;
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;
+ void clipRRect(const SkRRect& rrect, SkClipOp op, bool antialias) final;
void clipPath(const SkPath& path,
SkClipOp op,
bool antialias,
- UsePaintCache use_paint_cache) override;
+ UsePaintCache use_paint_cache) final;
+
+ // These state-query functions can be called only if `size` is not empty in
+ // the constructor. With this restriction, we don't need to create
+ // SkNoDrawCanvas for clients that only need recording.
+ SkImageInfo imageInfo() const override;
SkRect getLocalClipBounds() const override;
bool getLocalClipBounds(SkRect* bounds) const override;
SkIRect getDeviceClipBounds() const override;
bool getDeviceClipBounds(SkIRect* bounds) const override;
+ bool isClipEmpty() const override;
+ SkMatrix getTotalMatrix() const override;
+ SkM44 getLocalToDevice() const override;
+
void drawColor(SkColor4f color, SkBlendMode mode) override;
void clear(SkColor4f color) override;
-
void drawLine(SkScalar x0,
SkScalar y0,
SkScalar x1,
@@ -111,27 +126,21 @@ class CC_PAINT_EXPORT RecordPaintCanvas : public PaintCanvas {
SkScalar y,
NodeId node_id,
const PaintFlags& flags) override;
-
void drawPicture(sk_sp<const PaintRecord> record) override;
- bool isClipEmpty() const override;
- SkMatrix getTotalMatrix() const override;
- SkM44 getLocalToDevice() const override;
-
void Annotate(AnnotationType type,
const SkRect& rect,
sk_sp<SkData> data) override;
void recordCustomData(uint32_t id) override;
void setNodeId(int) override;
- bool NeedsFlush() const override;
-
// Don't shadow non-virtual helper functions.
+ using PaintCanvas::clipPath;
using PaintCanvas::clipRect;
using PaintCanvas::clipRRect;
- using PaintCanvas::clipPath;
using PaintCanvas::drawColor;
using PaintCanvas::drawImage;
+ using PaintCanvas::drawPath;
using PaintCanvas::drawPicture;
#if DCHECK_IS_ON()
@@ -170,33 +179,75 @@ class CC_PAINT_EXPORT RecordPaintCanvas : public PaintCanvas {
#endif
};
+ protected:
+ virtual int saveLayerInternal(const SkRect* bounds, const PaintFlags* flags);
+ virtual void clipRRectInternal(const SkRRect& rrect,
+ SkClipOp op,
+ bool antialias);
+ virtual void clipPathInternal(const SkPath& path,
+ SkClipOp op,
+ bool antialias,
+ UsePaintCache use_paint_cache);
+
private:
template <typename T, typename... Args>
- size_t push(Args&&... args);
-
- const SkNoDrawCanvas* GetCanvas() const;
- SkNoDrawCanvas* GetCanvas();
-
- bool InitializedWithRecordingBounds() const;
+ void push(Args&&... args);
- DisplayItemList* list_;
+ PaintOpBuffer buffer_;
+ int save_count_ = 1;
- // TODO(enne): Although RecordPaintCanvas is mostly a write-only interface
- // where paint commands are stored, occasionally users of PaintCanvas want
- // to ask stateful questions mid-stream of clip and transform state.
- // To avoid duplicating all this code (for now?), just forward to an SkCanvas
- // that's not backed by anything but can answer these questions.
- //
- // This is mutable so that const functions (e.g. quickReject) that may
- // lazy initialize the canvas can still be const.
- mutable absl::optional<SkNoDrawCanvas> canvas_;
- SkRect recording_bounds_;
bool needs_flush_ = false;
#if DCHECK_IS_ON()
unsigned disable_flush_check_scope_ = 0;
#endif
};
+// Besides the recording functions, this implementation of PaintCanvas allows
+// inspection of the current clip and CTM during recording.
+class CC_PAINT_EXPORT InspectableRecordPaintCanvas : public RecordPaintCanvas {
+ public:
+ explicit InspectableRecordPaintCanvas(const gfx::Size& size);
+ ~InspectableRecordPaintCanvas() override;
+
+ int save() override;
+ int saveLayerAlpha(const SkRect* bounds, uint8_t alpha) override;
+ void restore() override;
+
+ void translate(SkScalar dx, SkScalar dy) override;
+ void scale(SkScalar sx, SkScalar sy) override;
+ void rotate(SkScalar degrees) override;
+ void concat(const SkM44& matrix) override;
+ void setMatrix(const SkM44& matrix) override;
+
+ void clipRect(const SkRect& rect, SkClipOp op, bool antialias) override;
+
+ SkImageInfo imageInfo() const override;
+ SkRect getLocalClipBounds() const override;
+ bool getLocalClipBounds(SkRect* bounds) const override;
+ SkIRect getDeviceClipBounds() const override;
+ bool getDeviceClipBounds(SkIRect* bounds) const override;
+ bool isClipEmpty() const override;
+ SkMatrix getTotalMatrix() const override;
+ SkM44 getLocalToDevice() const override;
+
+ // Don't shadow non-virtual helper functions.
+ using RecordPaintCanvas::clipRect;
+
+ private:
+ int saveLayerInternal(const SkRect* bounds, const PaintFlags* flags) override;
+ void clipRRectInternal(const SkRRect& rrect,
+ SkClipOp op,
+ bool antialias) override;
+ void clipPathInternal(const SkPath& path,
+ SkClipOp op,
+ bool antialias,
+ UsePaintCache use_paint_cache) override;
+
+ int CheckSaveCount(int super_prev_save_count, int canvas_prev_save_count);
+
+ SkNoDrawCanvas canvas_;
+};
+
} // namespace cc
#endif // CC_PAINT_RECORD_PAINT_CANVAS_H_
diff --git a/chromium/cc/paint/render_surface_filters.cc b/chromium/cc/paint/render_surface_filters.cc
index b81fdc2724f..922dddd86b2 100644
--- a/chromium/cc/paint/render_surface_filters.cc
+++ b/chromium/cc/paint/render_surface_filters.cc
@@ -199,8 +199,7 @@ sk_sp<PaintFilter> RenderSurfaceFilters::BuildImageFilter(
break;
case FilterOperation::DROP_SHADOW:
image_filter = sk_make_sp<DropShadowPaintFilter>(
- SkIntToScalar(op.drop_shadow_offset().x()),
- SkIntToScalar(op.drop_shadow_offset().y()),
+ SkIntToScalar(op.offset().x()), SkIntToScalar(op.offset().y()),
SkIntToScalar(op.amount()), SkIntToScalar(op.amount()),
op.drop_shadow_color(),
DropShadowPaintFilter::ShadowMode::kDrawShadowAndForeground,
@@ -295,9 +294,9 @@ sk_sp<PaintFilter> RenderSurfaceFilters::BuildImageFilter(
}
break;
}
- case FilterOperation::STRETCH: {
- image_filter = sk_make_sp<StretchPaintFilter>(
- op.amount(), op.outer_threshold(), size.width(), size.height(),
+ case FilterOperation::OFFSET: {
+ image_filter = sk_make_sp<OffsetPaintFilter>(
+ SkIntToScalar(op.offset().x()), SkIntToScalar(op.offset().y()),
std::move(image_filter));
break;
}
diff --git a/chromium/cc/paint/scoped_raster_flags_unittest.cc b/chromium/cc/paint/scoped_raster_flags_unittest.cc
index 1abb9462e64..f971db9862a 100644
--- a/chromium/cc/paint/scoped_raster_flags_unittest.cc
+++ b/chromium/cc/paint/scoped_raster_flags_unittest.cc
@@ -7,7 +7,7 @@
#include <utility>
#include "base/bind.h"
#include "base/callback.h"
-#include "cc/paint/paint_op_buffer.h"
+#include "cc/paint/paint_op.h"
#include "cc/paint/paint_shader.h"
#include "cc/test/skia_common.h"
#include "cc/test/test_paint_worklet_input.h"
diff --git a/chromium/cc/paint/skia_paint_canvas_unittest.cc b/chromium/cc/paint/skia_paint_canvas_unittest.cc
index 7e090f9e271..b772c3327c7 100644
--- a/chromium/cc/paint/skia_paint_canvas_unittest.cc
+++ b/chromium/cc/paint/skia_paint_canvas_unittest.cc
@@ -37,7 +37,7 @@ TEST(SkiaPaintCanvasTest, ContextFlushesRecording) {
PaintRecorder recorder;
SkRect rect = SkRect::MakeWH(10, 10);
PaintFlags flags;
- recorder.beginRecording(rect);
+ recorder.beginRecording();
for (int i = 0; i < 11; i++)
recorder.getRecordingCanvas()->drawRect(rect, flags);
auto record = recorder.finishRecordingAsPicture();
diff --git a/chromium/cc/paint/skottie_mru_resource_provider.cc b/chromium/cc/paint/skottie_mru_resource_provider.cc
index 991bf024b39..58e055b4c0e 100644
--- a/chromium/cc/paint/skottie_mru_resource_provider.cc
+++ b/chromium/cc/paint/skottie_mru_resource_provider.cc
@@ -32,20 +32,28 @@ base::flat_map</*asset_id*/ std::string, gfx::Size> ParseImageAssetDimensions(
absl::optional<base::Value> animation_dict =
base::JSONReader::Read(animation_json);
- if (!animation_dict) {
+ if (!animation_dict || !animation_dict->is_dict()) {
LOG(ERROR) << "Failed to parse Lottie animation json";
return image_asset_sizes;
}
- const base::Value* assets = animation_dict->FindListKey(kAssetsKey);
+ const base::Value::List* assets =
+ animation_dict->GetDict().FindList(kAssetsKey);
// An animation may legitimately have no assets in it.
if (!assets)
return image_asset_sizes;
- for (const base::Value& asset : assets->GetListDeprecated()) {
- const std::string* id = asset.FindStringKey(kIdKey);
- absl::optional<int> width = asset.FindIntKey(kWidthKey);
- absl::optional<int> height = asset.FindIntKey(kHeightKey);
+ for (const base::Value& asset : *assets) {
+ if (!asset.is_dict()) {
+ LOG(ERROR) << "Found invalid asset in animation with type "
+ << base::Value::GetTypeName(asset.type());
+ continue;
+ }
+ const base::Value::Dict& asset_dict = asset.GetDict();
+
+ const std::string* id = asset_dict.FindString(kIdKey);
+ absl::optional<int> width = asset_dict.FindInt(kWidthKey);
+ absl::optional<int> height = asset_dict.FindInt(kHeightKey);
if (id && width && height && *width > 0 && *height > 0 &&
!image_asset_sizes.emplace(*id, gfx::Size(*width, *height)).second) {
LOG(WARNING) << "Multiple assets found in animation with id " << *id;
diff --git a/chromium/cc/paint/skottie_mru_resource_provider_unittest.cc b/chromium/cc/paint/skottie_mru_resource_provider_unittest.cc
index f3e584e7269..9d2d1afe61d 100644
--- a/chromium/cc/paint/skottie_mru_resource_provider_unittest.cc
+++ b/chromium/cc/paint/skottie_mru_resource_provider_unittest.cc
@@ -272,5 +272,20 @@ TEST_F(SkottieMRUResourceProviderTest, HandlesInvalidDimensions) {
Eq(absl::nullopt)))));
}
+TEST_F(SkottieMRUResourceProviderTest, GracefullyHandlesInvalidJson) {
+ // No expectations needed. Just make sure the code doesn't crash.
+ Init("invalid-json");
+ // Lottie animation json is expected to be a dictionary.
+ Init(R"(["valid", "json", "list"])");
+ // Assets are expected to be a list.
+ Init(R"({"assets": "invalid-asset-set"})");
+ // Each asset is expected to be a dictionary.
+ Init(R"({
+ "assets": [
+ "invalid-asset-value"
+ ]
+ })");
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/paint/skottie_text_property_value.cc b/chromium/cc/paint/skottie_text_property_value.cc
index e593a48e03e..e8de888cf1c 100644
--- a/chromium/cc/paint/skottie_text_property_value.cc
+++ b/chromium/cc/paint/skottie_text_property_value.cc
@@ -39,7 +39,7 @@ void SkottieTextPropertyValue::SetText(std::string text) {
if (incoming_text_hash == text_hash_)
return;
text_hash_ = incoming_text_hash;
- text_ = base::RefCountedString::TakeString(&text);
+ text_ = base::MakeRefCounted<base::RefCountedString>(std::move(text));
}
} // namespace cc
diff --git a/chromium/cc/paint/solid_color_analyzer.cc b/chromium/cc/paint/solid_color_analyzer.cc
index dc8eca0fca3..15967c63950 100644
--- a/chromium/cc/paint/solid_color_analyzer.cc
+++ b/chromium/cc/paint/solid_color_analyzer.cc
@@ -8,7 +8,8 @@
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
-#include "cc/paint/paint_op_buffer.h"
+#include "cc/paint/paint_op.h"
+#include "cc/paint/paint_op_buffer_iterator.h"
#include "third_party/skia/include/core/SkTypes.h"
#include "third_party/skia/include/utils/SkNoDrawCanvas.h"
diff --git a/chromium/cc/paint/solid_color_analyzer_unittest.cc b/chromium/cc/paint/solid_color_analyzer_unittest.cc
index fa2cadd2713..d62a1feb850 100644
--- a/chromium/cc/paint/solid_color_analyzer_unittest.cc
+++ b/chromium/cc/paint/solid_color_analyzer_unittest.cc
@@ -17,85 +17,52 @@ namespace cc {
namespace {
class SolidColorAnalyzerTest : public testing::Test {
- public:
- void SetUp() override {
- display_item_list_ = base::MakeRefCounted<DisplayItemList>(
- DisplayItemList::kToBeReleasedAsPaintOpBuffer);
- display_item_list_->StartPaint();
- }
-
- void TearDown() override {
- Finalize();
- canvas_.reset();
- display_item_list_ = nullptr;
- buffer_ = nullptr;
- }
+ protected:
+ void TearDown() override { Reset(); }
+ void Reset() { canvas_.ReleaseAsRecord(); }
- void Reset() {
- TearDown();
- SetUp();
- }
-
- void Initialize(const gfx::Rect& rect = gfx::Rect(0, 0, 100, 100)) {
- canvas_.emplace(display_item_list_.get(), gfx::RectToSkRect(rect));
- rect_ = rect;
- }
- RecordPaintCanvas* canvas() { return &*canvas_; }
-
- bool IsSolidColor(int max_ops_to_analyze = 1) {
- Finalize();
+ bool IsSolidColor(int max_ops_to_analyze = 1,
+ const gfx::Rect& rect = gfx::Rect(0, 0, 100, 100)) {
+ sk_sp<PaintRecord> record = canvas_.ReleaseAsRecord();
auto color = SolidColorAnalyzer::DetermineIfSolidColor(
- buffer_.get(), rect_, max_ops_to_analyze, nullptr);
+ record.get(), rect, max_ops_to_analyze, nullptr);
return !!color;
}
- SkColor4f GetColor(int max_ops_to_analyze = 1) {
- Finalize();
+ SkColor4f GetColor(int max_ops_to_analyze = 1,
+ const gfx::Rect rect = gfx::Rect(0, 0, 100, 100)) {
+ sk_sp<PaintRecord> record = canvas_.ReleaseAsRecord();
auto color = SolidColorAnalyzer::DetermineIfSolidColor(
- buffer_.get(), rect_, max_ops_to_analyze, nullptr);
+ record.get(), rect, max_ops_to_analyze, nullptr);
EXPECT_TRUE(color);
return color ? *color : SkColors::kTransparent;
}
- private:
- void Finalize() {
- if (buffer_)
- return;
- display_item_list_->EndPaintOfUnpaired(gfx::Rect());
- display_item_list_->Finalize();
- buffer_ = display_item_list_->ReleaseAsRecord();
- }
+ RecordPaintCanvas canvas_;
- gfx::Rect rect_;
- scoped_refptr<DisplayItemList> display_item_list_;
- sk_sp<PaintOpBuffer> buffer_;
- absl::optional<RecordPaintCanvas> canvas_;
+ private:
absl::optional<SolidColorAnalyzer> analyzer_;
};
TEST_F(SolidColorAnalyzerTest, Empty) {
- Initialize();
EXPECT_EQ(SkColors::kTransparent, GetColor());
}
TEST_F(SolidColorAnalyzerTest, ClearTransparent) {
- Initialize();
SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(0, 12, 34, 56));
- canvas()->clear(color);
+ canvas_.clear(color);
EXPECT_EQ(SkColors::kTransparent, GetColor());
}
TEST_F(SolidColorAnalyzerTest, ClearSolid) {
- Initialize();
SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 65, 43, 21));
- canvas()->clear(color);
+ canvas_.clear(color);
EXPECT_EQ(color, GetColor());
}
TEST_F(SolidColorAnalyzerTest, ClearTranslucent) {
- Initialize();
SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(128, 11, 22, 33));
- canvas()->clear(color);
+ canvas_.clear(color);
#if BUILDFLAG(IS_MAC)
// TODO(andrescj): remove the special treatment of OS_MAC once
// https://crbug.com/922899 is fixed.
@@ -106,29 +73,26 @@ TEST_F(SolidColorAnalyzerTest, ClearTranslucent) {
}
TEST_F(SolidColorAnalyzerTest, DrawColor) {
- Initialize();
SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33));
- canvas()->drawColor(color);
+ canvas_.drawColor(color);
EXPECT_EQ(color, GetColor());
}
TEST_F(SolidColorAnalyzerTest, DrawOval) {
- Initialize();
PaintFlags flags;
SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33));
flags.setColor(color);
- canvas()->drawOval(SkRect::MakeWH(100, 100), flags);
+ canvas_.drawOval(SkRect::MakeWH(100, 100), flags);
EXPECT_FALSE(IsSolidColor());
}
TEST_F(SolidColorAnalyzerTest, DrawRect) {
- Initialize();
PaintFlags flags;
SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33));
flags.setColor(color);
SkRect rect = SkRect::MakeWH(200, 200);
- canvas()->clipRect(rect, SkClipOp::kIntersect, false);
- canvas()->drawRect(rect, flags);
+ canvas_.clipRect(rect, SkClipOp::kIntersect, false);
+ canvas_.drawRect(rect, flags);
EXPECT_EQ(color, GetColor());
}
@@ -138,138 +102,124 @@ TEST_F(SolidColorAnalyzerTest, DrawRRect) {
SkRect rect = SkRect::MakeWH(200, 200);
SkRRect rrect;
rrect.setRectXY(rect, 5, 5);
- gfx::Rect canvas_rect(5, 5, 190, 190);
- Initialize(canvas_rect);
PaintFlags flags;
SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33));
flags.setColor(color);
- canvas()->drawRRect(rrect, flags);
- EXPECT_EQ(color, GetColor());
+ canvas_.drawRRect(rrect, flags);
+ EXPECT_EQ(color, GetColor(1, gfx::Rect(5, 5, 190, 190)));
}
TEST_F(SolidColorAnalyzerTest, DrawRectClipped) {
- Initialize();
PaintFlags flags;
SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33));
flags.setColor(color);
SkRect rect = SkRect::MakeWH(200, 200);
- canvas()->clipRect(SkRect::MakeWH(50, 50), SkClipOp::kIntersect, false);
- canvas()->drawRect(rect, flags);
+ canvas_.clipRect(SkRect::MakeWH(50, 50), SkClipOp::kIntersect, false);
+ canvas_.drawRect(rect, flags);
EXPECT_FALSE(IsSolidColor());
}
TEST_F(SolidColorAnalyzerTest, DrawRectClippedDifference) {
- Initialize();
PaintFlags flags;
SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33));
flags.setColor(color);
SkRect drawRect = SkRect::MakeWH(200, 200);
- canvas()->clipRect(drawRect, SkClipOp::kIntersect, false);
+ canvas_.clipRect(drawRect, SkClipOp::kIntersect, false);
SkRect differenceRect = SkRect::MakeXYWH(50, 50, 200, 200);
// Using difference should always make this fail.
- canvas()->clipRect(differenceRect, SkClipOp::kDifference, false);
- canvas()->drawRect(drawRect, flags);
+ canvas_.clipRect(differenceRect, SkClipOp::kDifference, false);
+ canvas_.drawRect(drawRect, flags);
EXPECT_FALSE(IsSolidColor());
}
TEST_F(SolidColorAnalyzerTest, DrawRectWithTranslateNotSolid) {
- Initialize();
PaintFlags flags;
SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33));
flags.setColor(color);
SkRect rect = SkRect::MakeWH(100, 100);
- canvas()->translate(1, 1);
- canvas()->drawRect(rect, flags);
+ canvas_.translate(1, 1);
+ canvas_.drawRect(rect, flags);
EXPECT_FALSE(IsSolidColor());
}
TEST_F(SolidColorAnalyzerTest, DrawRectWithTranslateSolid) {
- Initialize();
PaintFlags flags;
SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33));
flags.setColor(color);
SkRect rect = SkRect::MakeWH(101, 101);
- canvas()->translate(1, 1);
- canvas()->drawRect(rect, flags);
+ canvas_.translate(1, 1);
+ canvas_.drawRect(rect, flags);
EXPECT_FALSE(IsSolidColor());
}
TEST_F(SolidColorAnalyzerTest, TwoOpsNotSolid) {
- Initialize();
SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 65, 43, 21));
- canvas()->clear(color);
- canvas()->clear(color);
+ canvas_.clear(color);
+ canvas_.clear(color);
EXPECT_FALSE(IsSolidColor());
}
TEST_F(SolidColorAnalyzerTest, DrawRectBlendModeClear) {
- Initialize();
PaintFlags flags;
SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33));
flags.setColor(color);
flags.setBlendMode(SkBlendMode::kClear);
SkRect rect = SkRect::MakeWH(200, 200);
- canvas()->drawRect(rect, flags);
+ canvas_.drawRect(rect, flags);
EXPECT_EQ(SkColors::kTransparent, GetColor());
}
TEST_F(SolidColorAnalyzerTest, DrawRectBlendModeSrcOver) {
- Initialize();
PaintFlags flags;
SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33));
flags.setColor(color);
flags.setBlendMode(SkBlendMode::kSrcOver);
SkRect rect = SkRect::MakeWH(200, 200);
- canvas()->drawRect(rect, flags);
+ canvas_.drawRect(rect, flags);
EXPECT_EQ(color, GetColor());
}
TEST_F(SolidColorAnalyzerTest, DrawRectRotated) {
- Initialize();
PaintFlags flags;
SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33));
flags.setColor(color);
SkRect rect = SkRect::MakeWH(200, 200);
- canvas()->rotate(50);
- canvas()->drawRect(rect, flags);
+ canvas_.rotate(50);
+ canvas_.drawRect(rect, flags);
EXPECT_FALSE(IsSolidColor());
}
TEST_F(SolidColorAnalyzerTest, DrawRectScaledNotSolid) {
- Initialize();
PaintFlags flags;
SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33));
flags.setColor(color);
SkRect rect = SkRect::MakeWH(200, 200);
- canvas()->scale(0.1f, 0.1f);
- canvas()->drawRect(rect, flags);
+ canvas_.scale(0.1f, 0.1f);
+ canvas_.drawRect(rect, flags);
EXPECT_FALSE(IsSolidColor());
}
TEST_F(SolidColorAnalyzerTest, DrawRectScaledSolid) {
- Initialize();
PaintFlags flags;
SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33));
flags.setColor(color);
SkRect rect = SkRect::MakeWH(10, 10);
- canvas()->scale(10, 10);
- canvas()->drawRect(rect, flags);
+ canvas_.scale(10, 10);
+ canvas_.drawRect(rect, flags);
EXPECT_EQ(color, GetColor());
}
TEST_F(SolidColorAnalyzerTest, DrawRectFilterPaint) {
- Initialize();
PaintFlags flags;
SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33));
flags.setColor(color);
flags.setImageFilter(sk_make_sp<OffsetPaintFilter>(10, 10, nullptr));
SkRect rect = SkRect::MakeWH(200, 200);
- canvas()->drawRect(rect, flags);
+ canvas_.drawRect(rect, flags);
EXPECT_FALSE(IsSolidColor());
}
TEST_F(SolidColorAnalyzerTest, DrawRectClipPath) {
- Initialize();
PaintFlags flags;
SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33));
flags.setColor(color);
@@ -282,18 +232,17 @@ TEST_F(SolidColorAnalyzerTest, DrawRectClipPath) {
path.lineTo(0, 255);
SkRect rect = SkRect::MakeWH(200, 200);
- canvas()->clipPath(path, SkClipOp::kIntersect);
- canvas()->drawRect(rect, flags);
+ canvas_.clipPath(path, SkClipOp::kIntersect);
+ canvas_.drawRect(rect, flags);
EXPECT_FALSE(IsSolidColor());
}
TEST_F(SolidColorAnalyzerTest, DrawRectTranslucent) {
- Initialize();
PaintFlags flags;
SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(128, 128, 0, 0));
flags.setColor(color);
SkRect rect = SkRect::MakeWH(100, 100);
- canvas()->drawRect(rect, flags);
+ canvas_.drawRect(rect, flags);
#if BUILDFLAG(IS_MAC)
// TODO(andrescj): remove the special treatment of OS_MAC once
// https://crbug.com/922899 is fixed.
@@ -304,44 +253,41 @@ TEST_F(SolidColorAnalyzerTest, DrawRectTranslucent) {
}
TEST_F(SolidColorAnalyzerTest, DrawRectTranslucentOverNonSolid) {
- Initialize();
PaintFlags flags;
SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 128, 0, 0));
flags.setColor(color);
SkRect rect = SkRect::MakeWH(100, 50);
- canvas()->drawRect(rect, flags);
+ canvas_.drawRect(rect, flags);
color = SkColor4f::FromColor(SkColorSetARGB(128, 0, 128, 0));
flags.setColor(color);
rect = SkRect::MakeWH(100, 100);
- canvas()->drawRect(rect, flags);
+ canvas_.drawRect(rect, flags);
EXPECT_FALSE(IsSolidColor(2 /* max_ops_to_analyze */));
}
TEST_F(SolidColorAnalyzerTest, DrawRectOpaqueOccludesNonSolid) {
- Initialize();
PaintFlags flags;
SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 128, 0, 0));
flags.setColor(color);
SkRect rect = SkRect::MakeWH(100, 50);
- canvas()->drawRect(rect, flags);
+ canvas_.drawRect(rect, flags);
color = SkColor4f::FromColor(SkColorSetARGB(255, 0, 128, 0));
flags.setColor(color);
rect = SkRect::MakeWH(100, 100);
- canvas()->drawRect(rect, flags);
+ canvas_.drawRect(rect, flags);
EXPECT_EQ(color, GetColor(2 /* max_ops_to_analyze */));
}
TEST_F(SolidColorAnalyzerTest, DrawRectSolidWithSrcOverBlending) {
- Initialize();
PaintFlags flags;
SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(64, 40, 50, 60));
flags.setColor(color);
SkRect rect = SkRect::MakeWH(100, 100);
- canvas()->drawRect(rect, flags);
+ canvas_.drawRect(rect, flags);
color = SkColor4f::FromColor(SkColorSetARGB(128, 10, 20, 30));
flags.setColor(color);
rect = SkRect::MakeWH(100, 100);
- canvas()->drawRect(rect, flags);
+ canvas_.drawRect(rect, flags);
#if BUILDFLAG(IS_MAC)
// TODO(andrescj): remove the special treatment of OS_MAC once
// https://crbug.com/922899 is fixed.
@@ -354,13 +300,12 @@ TEST_F(SolidColorAnalyzerTest, DrawRectSolidWithSrcOverBlending) {
}
TEST_F(SolidColorAnalyzerTest, SaveLayer) {
- Initialize();
PaintFlags flags;
SkColor4f color = SkColor4f::FromColor(SkColorSetARGB(255, 11, 22, 33));
flags.setColor(color);
SkRect rect = SkRect::MakeWH(200, 200);
- canvas()->saveLayer(&rect, &flags);
+ canvas_.saveLayer(&rect, &flags);
EXPECT_FALSE(IsSolidColor());
}
@@ -426,7 +371,6 @@ TEST_F(SolidColorAnalyzerTest, ClipRRectCoversCanvas) {
bool scaled = case_scale > 0;
for (size_t i = 0; i < std::size(cases); ++i) {
Reset();
- Initialize(canvas_rect);
SkRect bounding_rect = SkRect::MakeXYWH(
scaled ? cases[i].offset_scale.x() : cases[i].offset.x(),
@@ -436,9 +380,9 @@ TEST_F(SolidColorAnalyzerTest, ClipRRectCoversCanvas) {
SkRRect rr;
rr.setRectRadii(bounding_rect, scaled ? radii_scale : radii);
- canvas()->clipRRect(rr, SkClipOp::kIntersect, false);
- canvas()->drawRect(RectToSkRect(canvas_rect), flags);
- EXPECT_EQ(cases[i].expected, IsSolidColor())
+ canvas_.clipRRect(rr, SkClipOp::kIntersect, false);
+ canvas_.drawRect(RectToSkRect(canvas_rect), flags);
+ EXPECT_EQ(cases[i].expected, IsSolidColor(1, canvas_rect))
<< "Case " << i << ", " << scaled << " failed.";
}
}
diff --git a/chromium/cc/paint/target_color_params.h b/chromium/cc/paint/target_color_params.h
index 5aa8eaada74..bef7ff634f0 100644
--- a/chromium/cc/paint/target_color_params.h
+++ b/chromium/cc/paint/target_color_params.h
@@ -8,7 +8,9 @@
#include <string>
#include "cc/paint/paint_export.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/gfx/color_space.h"
+#include "ui/gfx/hdr_metadata.h"
namespace cc {
@@ -36,20 +38,19 @@ struct CC_PAINT_EXPORT TargetColorParams {
// Whether or not tone mapping should be applied.
bool enable_tone_mapping = true;
+ // The HDR metadata to use in tone mapping.
+ absl::optional<gfx::HDRMetadata> hdr_metadata;
+
bool operator==(const TargetColorParams& other) const {
return color_space == other.color_space &&
sdr_max_luminance_nits == other.sdr_max_luminance_nits &&
- hdr_max_luminance_relative == other.hdr_max_luminance_relative;
+ hdr_max_luminance_relative == other.hdr_max_luminance_relative &&
+ enable_tone_mapping == other.enable_tone_mapping &&
+ hdr_metadata == other.hdr_metadata;
}
bool operator!=(const TargetColorParams& other) const {
return !(*this == other);
}
- bool operator<(const TargetColorParams& other) const {
- return std::tie(color_space, sdr_max_luminance_nits,
- hdr_max_luminance_relative) <
- std::tie(other.color_space, other.sdr_max_luminance_nits,
- other.hdr_max_luminance_relative);
- }
size_t GetHash() const;
std::string ToString() const;
};
diff --git a/chromium/cc/paint/transfer_cache_fuzzer.cc b/chromium/cc/paint/transfer_cache_fuzzer.cc
index 45dbf7cbb0f..28e9971640a 100644
--- a/chromium/cc/paint/transfer_cache_fuzzer.cc
+++ b/chromium/cc/paint/transfer_cache_fuzzer.cc
@@ -18,7 +18,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
scoped_refptr<viz::TestContextProvider> context_provider =
viz::TestContextProvider::Create();
- context_provider->BindToCurrentThread();
+ context_provider->BindToCurrentSequence();
cc::TransferCacheEntryType entry_type =
static_cast<cc::TransferCacheEntryType>(data[0]);
diff --git a/chromium/cc/paint/transfer_cache_unittest.cc b/chromium/cc/paint/transfer_cache_unittest.cc
index 408929b0107..1b33fab37cb 100644
--- a/chromium/cc/paint/transfer_cache_unittest.cc
+++ b/chromium/cc/paint/transfer_cache_unittest.cc
@@ -10,6 +10,7 @@
#include "cc/paint/image_transfer_cache_entry.h"
#include "cc/paint/raw_memory_transfer_cache_entry.h"
#include "cc/paint/transfer_cache_entry.h"
+#include "components/viz/test/test_gpu_memory_buffer_manager.h"
#include "components/viz/test/test_gpu_service_holder.h"
#include "components/viz/test/test_in_process_context_provider.h"
#include "gpu/command_buffer/client/client_transfer_cache.h"
@@ -49,7 +50,7 @@ class TransferCacheTest : public testing::Test {
context_ = std::make_unique<gpu::RasterInProcessContext>();
auto result = context_->Initialize(
viz::TestGpuServiceHolder::GetInstance()->task_executor(), attribs,
- gpu::SharedMemoryLimits(), &image_factory_, nullptr, nullptr);
+ gpu::SharedMemoryLimits(), nullptr, nullptr);
ASSERT_EQ(result, gpu::ContextResult::kSuccess);
ASSERT_TRUE(context_->GetCapabilities().supports_oop_raster);
@@ -84,7 +85,6 @@ class TransferCacheTest : public testing::Test {
private:
viz::TestGpuMemoryBufferManager gpu_memory_buffer_manager_;
- viz::TestImageFactory image_factory_;
std::unique_ptr<gpu::RasterInProcessContext> context_;
gl::DisableNullDrawGLBindings enable_pixel_output_;
ClientRawMemoryTransferCacheEntry test_client_entry_;
diff --git a/chromium/cc/raster/gpu_raster_buffer_provider.cc b/chromium/cc/raster/gpu_raster_buffer_provider.cc
index c58c0623043..d516c15fb7f 100644
--- a/chromium/cc/raster/gpu_raster_buffer_provider.cc
+++ b/chromium/cc/raster/gpu_raster_buffer_provider.cc
@@ -412,12 +412,6 @@ void GpuRasterBufferProvider::RasterBufferImpl::RasterizeSource(
playback_rect, transform.translation(), recording_to_raster_scale,
raster_source->requires_clear(),
const_cast<RasterSource*>(raster_source)->max_op_size_hint());
- UMA_HISTOGRAM_COUNTS_1000(
- "Gpu.Rasterization.Raster.NumPaintOps",
- raster_source->GetDisplayItemList()->num_paint_ops());
- UMA_HISTOGRAM_COUNTS_100(
- "Gpu.Rasterization.Raster.NumSlowPathsUpToMinForMSAA",
- raster_source->GetDisplayItemList()->num_slow_paths_up_to_min_for_MSAA());
ri->EndRasterCHROMIUM();
// TODO(ericrk): Handle unpremultiply+dither for 4444 cases.
diff --git a/chromium/cc/raster/raster_buffer_provider.cc b/chromium/cc/raster/raster_buffer_provider.cc
index a86d14d0ddb..653355b6511 100644
--- a/chromium/cc/raster/raster_buffer_provider.cc
+++ b/chromium/cc/raster/raster_buffer_provider.cc
@@ -49,6 +49,7 @@ bool IsSupportedPlaybackToMemoryFormat(viz::ResourceFormat format) {
case viz::BGRA_1010102:
case viz::YVU_420:
case viz::YUV_420_BIPLANAR:
+ case viz::YUVA_420_TRIPLANAR:
case viz::P010:
return false;
}
@@ -149,6 +150,7 @@ void RasterBufferProvider::PlaybackToMemory(
case viz::BGRA_1010102:
case viz::YVU_420:
case viz::YUV_420_BIPLANAR:
+ case viz::YUVA_420_TRIPLANAR:
case viz::P010:
NOTREACHED();
return;
diff --git a/chromium/cc/raster/raster_buffer_provider_perftest.cc b/chromium/cc/raster/raster_buffer_provider_perftest.cc
index 6f181542239..5a1cd48e24a 100644
--- a/chromium/cc/raster/raster_buffer_provider_perftest.cc
+++ b/chromium/cc/raster/raster_buffer_provider_perftest.cc
@@ -95,7 +95,7 @@ class PerfContextProvider
base::RefCountedThreadSafe<PerfContextProvider>::Release();
}
- gpu::ContextResult BindToCurrentThread() override {
+ gpu::ContextResult BindToCurrentSequence() override {
return gpu::ContextResult::kSuccess;
}
const gpu::Capabilities& ContextCapabilities() const override {
diff --git a/chromium/cc/raster/raster_buffer_provider_unittest.cc b/chromium/cc/raster/raster_buffer_provider_unittest.cc
index 4618ad1ef29..c274c87d1f7 100644
--- a/chromium/cc/raster/raster_buffer_provider_unittest.cc
+++ b/chromium/cc/raster/raster_buffer_provider_unittest.cc
@@ -27,7 +27,6 @@
#include "base/run_loop.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/metrics/histogram_tester.h"
-#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
@@ -166,7 +165,7 @@ class RasterBufferProviderTest
RasterBufferProviderTest()
: all_tile_tasks_finished_(
- base::ThreadTaskRunnerHandle::Get().get(),
+ base::SingleThreadTaskRunner::GetCurrentDefault().get(),
base::BindRepeating(&RasterBufferProviderTest::AllTileTasksFinished,
base::Unretained(this))),
timeout_seconds_(5),
@@ -185,10 +184,10 @@ class RasterBufferProviderTest
case RASTER_BUFFER_PROVIDER_TYPE_ONE_COPY:
Create3dResourceProvider();
raster_buffer_provider_ = std::make_unique<OneCopyRasterBufferProvider>(
- base::ThreadTaskRunnerHandle::Get().get(), context_provider_.get(),
- worker_context_provider_.get(), &gpu_memory_buffer_manager_,
- kMaxBytesPerCopyOperation, false, false, kMaxStagingBuffers,
- viz::RGBA_8888);
+ base::SingleThreadTaskRunner::GetCurrentDefault().get(),
+ context_provider_.get(), worker_context_provider_.get(),
+ &gpu_memory_buffer_manager_, kMaxBytesPerCopyOperation, false,
+ false, kMaxStagingBuffers, viz::RGBA_8888);
break;
case RASTER_BUFFER_PROVIDER_TYPE_GPU:
Create3dResourceProvider();
@@ -208,7 +207,8 @@ class RasterBufferProviderTest
pool_ = std::make_unique<ResourcePool>(
resource_provider_.get(), context_provider_.get(),
- base::ThreadTaskRunnerHandle::Get(), base::TimeDelta(), true);
+ base::SingleThreadTaskRunner::GetCurrentDefault(), base::TimeDelta(),
+ true);
tile_task_manager_ = TileTaskManagerImpl::Create(&task_graph_runner_);
}
@@ -336,7 +336,7 @@ class RasterBufferProviderTest
auto gl_owned = std::make_unique<viz::TestGLES2Interface>();
gl_owned->set_support_sync_query(true);
context_provider_ = viz::TestContextProvider::Create(std::move(gl_owned));
- context_provider_->BindToCurrentThread();
+ context_provider_->BindToCurrentSequence();
worker_context_provider_ = viz::TestContextProvider::CreateWorker();
DCHECK(worker_context_provider_);
diff --git a/chromium/cc/raster/scoped_gpu_raster_unittest.cc b/chromium/cc/raster/scoped_gpu_raster_unittest.cc
index b52983c3ff4..069b88366c8 100644
--- a/chromium/cc/raster/scoped_gpu_raster_unittest.cc
+++ b/chromium/cc/raster/scoped_gpu_raster_unittest.cc
@@ -3,6 +3,9 @@
// found in the LICENSE file.
#include "cc/raster/scoped_gpu_raster.h"
+
+#include <memory>
+
#include "components/viz/test/test_context_provider.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -18,7 +21,7 @@ class ScopedGpuRasterTest : public testing::Test {
TEST(ScopedGpuRasterTest, RestoresUnpackAlignment) {
scoped_refptr<viz::TestContextProvider> provider =
viz::TestContextProvider::Create();
- ASSERT_EQ(provider->BindToCurrentThread(), gpu::ContextResult::kSuccess);
+ ASSERT_EQ(provider->BindToCurrentSequence(), gpu::ContextResult::kSuccess);
gpu::gles2::GLES2Interface* gl = provider->ContextGL();
GLint unpack_alignment = 0;
gl->GetIntegerv(GL_UNPACK_ALIGNMENT, &unpack_alignment);
diff --git a/chromium/cc/raster/staging_buffer_pool.cc b/chromium/cc/raster/staging_buffer_pool.cc
index 94303f86860..8df0569404b 100644
--- a/chromium/cc/raster/staging_buffer_pool.cc
+++ b/chromium/cc/raster/staging_buffer_pool.cc
@@ -12,7 +12,7 @@
#include "base/containers/contains.h"
#include "base/ranges/algorithm.h"
#include "base/strings/stringprintf.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/task/single_thread_task_runner.h"
#include "base/trace_event/memory_dump_manager.h"
#include "cc/base/container_util.h"
#include "components/viz/common/gpu/raster_context_provider.h"
@@ -135,7 +135,8 @@ StagingBufferPool::StagingBufferPool(
reduce_memory_usage_pending_(false) {
DCHECK(worker_context_provider_);
base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
- this, "cc::StagingBufferPool", base::ThreadTaskRunnerHandle::Get());
+ this, "cc::StagingBufferPool",
+ base::SingleThreadTaskRunner::GetCurrentDefault());
memory_pressure_listener_ = std::make_unique<base::MemoryPressureListener>(
FROM_HERE, base::BindRepeating(&StagingBufferPool::OnMemoryPressure,
diff --git a/chromium/cc/raster/staging_buffer_pool_unittest.cc b/chromium/cc/raster/staging_buffer_pool_unittest.cc
index 30a816fea41..6c4eda8ab1a 100644
--- a/chromium/cc/raster/staging_buffer_pool_unittest.cc
+++ b/chromium/cc/raster/staging_buffer_pool_unittest.cc
@@ -5,8 +5,8 @@
#include "cc/raster/staging_buffer_pool.h"
#include "base/run_loop.h"
+#include "base/task/single_thread_task_runner.h"
#include "base/test/task_environment.h"
-#include "base/threading/thread_task_runner_handle.h"
#include "components/viz/test/test_context_provider.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -16,7 +16,7 @@ TEST(StagingBufferPoolTest, ShutdownImmediatelyAfterCreation) {
auto context_provider = viz::TestContextProvider::CreateWorker();
bool use_partial_raster = false;
int max_staging_buffer_usage_in_bytes = 1024;
- auto task_runner = base::ThreadTaskRunnerHandle::Get();
+ auto task_runner = base::SingleThreadTaskRunner::GetCurrentDefault();
// Create a StagingBufferPool and immediately shut it down.
auto pool = std::make_unique<StagingBufferPool>(
task_runner.get(), context_provider.get(), use_partial_raster,
@@ -25,8 +25,8 @@ TEST(StagingBufferPoolTest, ShutdownImmediatelyAfterCreation) {
// Flush the message loop.
auto flush_message_loop = [] {
base::RunLoop runloop;
- base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
- runloop.QuitClosure());
+ base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
+ FROM_HERE, runloop.QuitClosure());
runloop.Run();
};
diff --git a/chromium/cc/raster/task.h b/chromium/cc/raster/task.h
index c8c3807530f..a5f01446b42 100644
--- a/chromium/cc/raster/task.h
+++ b/chromium/cc/raster/task.h
@@ -10,6 +10,7 @@
#include <string>
#include <vector>
+#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "cc/cc_export.h"
@@ -131,8 +132,8 @@ struct CC_EXPORT TaskGraph {
Edge(const Task* task, Task* dependent)
: task(task), dependent(dependent) {}
- const Task* task;
- Task* dependent;
+ raw_ptr<const Task, DanglingUntriaged> task;
+ raw_ptr<Task, DanglingUntriaged> dependent;
};
TaskGraph();
diff --git a/chromium/cc/raster/task_graph_runner.h b/chromium/cc/raster/task_graph_runner.h
index 1d8ac31429b..69e4d0690e2 100644
--- a/chromium/cc/raster/task_graph_runner.h
+++ b/chromium/cc/raster/task_graph_runner.h
@@ -8,7 +8,6 @@
#include <stddef.h>
#include <stdint.h>
-#include "base/memory/ref_counted.h"
#include "cc/cc_export.h"
#include "cc/raster/task.h"
diff --git a/chromium/cc/raster/task_graph_work_queue.cc b/chromium/cc/raster/task_graph_work_queue.cc
index 5533d6ec3d7..d6f6cb77aff 100644
--- a/chromium/cc/raster/task_graph_work_queue.cc
+++ b/chromium/cc/raster/task_graph_work_queue.cc
@@ -82,7 +82,7 @@ class DependentIterator {
// Now find the node for the dependent of this edge.
auto it = base::ranges::find(graph_->nodes,
- graph_->edges[current_index_].dependent,
+ graph_->edges[current_index_].dependent.get(),
&TaskGraph::Node::task);
DCHECK(it != graph_->nodes.end());
current_node_ = &(*it);
@@ -178,7 +178,7 @@ void TaskGraphWorkQueue::ScheduleTasks(NamespaceToken token, TaskGraph* graph) {
continue;
// Skip if already running.
- if (base::Contains(task_namespace.running_tasks, node.task,
+ if (base::Contains(task_namespace.running_tasks, node.task.get(),
&CategorizedTask::second)) {
continue;
}
@@ -208,12 +208,12 @@ void TaskGraphWorkQueue::ScheduleTasks(NamespaceToken token, TaskGraph* graph) {
continue;
// Skip if already running.
- if (base::Contains(task_namespace.running_tasks, node.task,
+ if (base::Contains(task_namespace.running_tasks, node.task.get(),
&CategorizedTask::second)) {
continue;
}
- DCHECK(!base::Contains(task_namespace.completed_tasks, node.task));
+ DCHECK(!base::Contains(task_namespace.completed_tasks, node.task.get()));
node.task->state().DidCancel();
task_namespace.completed_tasks.push_back(node.task);
}
diff --git a/chromium/cc/resources/resource_pool.cc b/chromium/cc/resources/resource_pool.cc
index 23d37ccd584..c18adef30c8 100644
--- a/chromium/cc/resources/resource_pool.cc
+++ b/chromium/cc/resources/resource_pool.cc
@@ -79,7 +79,7 @@ void ResourcePool::GpuBacking::InitOverlayCandidateAndTextureTarget(
const gpu::Capabilities& caps,
bool use_gpu_memory_buffer_resources) {
overlay_candidate = use_gpu_memory_buffer_resources &&
- caps.texture_storage_image &&
+ caps.supports_scanout_shared_images &&
IsGpuMemoryBufferFormatSupported(format);
if (overlay_candidate) {
texture_target = gpu::GetBufferTextureTarget(gfx::BufferUsage::SCANOUT,
@@ -122,7 +122,7 @@ ResourcePool::~ResourcePool() {
SetResourceUsageLimits(0, 0);
DCHECK_EQ(0u, unused_resources_.size());
- DCHECK_EQ(0u, in_use_memory_usage_bytes_);
+ DCHECK_EQ(0u, unused_memory_usage_bytes_);
DCHECK_EQ(0u, total_memory_usage_bytes_);
DCHECK_EQ(0u, total_resource_count_);
}
@@ -150,7 +150,8 @@ ResourcePool::PoolResource* ResourcePool::ReuseResource(
// Transfer resource to |in_use_resources_|.
in_use_resources_[resource->unique_id()] = std::move(*it);
unused_resources_.erase(it);
- in_use_memory_usage_bytes_ += resource->memory_usage();
+ DCHECK_GE(unused_memory_usage_bytes_, resource->memory_usage());
+ unused_memory_usage_bytes_ -= resource->memory_usage();
DCHECK_EQ(resource->state(), PoolResource::kUnused);
resource->set_state(PoolResource::kInUse);
return resource;
@@ -265,7 +266,8 @@ ResourcePool::TryAcquireResourceForPartialRaster(
in_use_resources_[resource->unique_id()] =
std::move(*iter_resource_to_return);
unused_resources_.erase(iter_resource_to_return);
- in_use_memory_usage_bytes_ += resource->memory_usage();
+ DCHECK_GE(unused_memory_usage_bytes_, resource->memory_usage());
+ unused_memory_usage_bytes_ -= resource->memory_usage();
*total_invalidated_rect = resource->invalidated_rect();
// Clear the invalidated rect and content ID on the resource being returned.
@@ -282,8 +284,8 @@ ResourcePool::TryAcquireResourceForPartialRaster(
void ResourcePool::OnBackingAllocated(PoolResource* resource) {
size_t size = resource->memory_usage();
total_memory_usage_bytes_ += size;
- if (resource->state() == PoolResource::kInUse)
- in_use_memory_usage_bytes_ += size;
+ if (resource->state() == PoolResource::kUnused)
+ unused_memory_usage_bytes_ += size;
}
void ResourcePool::OnResourceReleased(size_t unique_id,
@@ -355,8 +357,14 @@ bool ResourcePool::PrepareForExport(const InUsePoolResource& in_use_resource) {
}
void ResourcePool::InvalidateResources() {
- while (!unused_resources_.empty())
+ while (!unused_resources_.empty()) {
+ DCHECK_GE(unused_memory_usage_bytes_,
+ unused_resources_.back()->memory_usage());
+ unused_memory_usage_bytes_ -= unused_resources_.back()->memory_usage();
DeleteResource(PopBack(&unused_resources_));
+ }
+ DCHECK_EQ(unused_memory_usage_bytes_, 0U);
+
for (auto& pool_resource : busy_resources_)
pool_resource->mark_avoid_reuse();
for (auto& pair : in_use_resources_)
@@ -398,7 +406,6 @@ void ResourcePool::ReleaseResource(InUsePoolResource in_use_resource) {
CHECK(it->second.get());
pool_resource->set_last_usage(clock_->NowTicks());
- in_use_memory_usage_bytes_ -= pool_resource->memory_usage();
// Save the ResourceId since the |pool_resource| can be deleted in the next
// step.
@@ -459,6 +466,9 @@ void ResourcePool::ReduceResourceUsage() {
// can't be locked for write might also not be truly free-able.
// We can free the resource here but it doesn't mean that the
// memory is necessarily returned to the OS.
+ DCHECK_GE(unused_memory_usage_bytes_,
+ unused_resources_.back()->memory_usage());
+ unused_memory_usage_bytes_ -= unused_resources_.back()->memory_usage();
DeleteResource(PopBack(&unused_resources_));
}
}
@@ -472,8 +482,8 @@ bool ResourcePool::ResourceUsageTooHigh() {
}
void ResourcePool::DeleteResource(std::unique_ptr<PoolResource> resource) {
- size_t resource_bytes = resource->memory_usage();
- total_memory_usage_bytes_ -= resource_bytes;
+ DCHECK_GE(total_memory_usage_bytes_, resource->memory_usage());
+ total_memory_usage_bytes_ -= resource->memory_usage();
--total_resource_count_;
if (flush_evicted_resources_deadline_ == base::TimeTicks::Max()) {
flush_evicted_resources_deadline_ =
@@ -495,6 +505,7 @@ void ResourcePool::UpdateResourceContentIdAndInvalidation(
void ResourcePool::DidFinishUsingResource(
std::unique_ptr<PoolResource> resource) {
+ unused_memory_usage_bytes_ += resource->memory_usage();
unused_resources_.push_front(std::move(resource));
}
@@ -546,6 +557,9 @@ void ResourcePool::EvictResourcesNotUsedSince(base::TimeTicks time_limit) {
if (unused_resources_.back()->last_usage() > time_limit)
return;
+ DCHECK_GE(unused_memory_usage_bytes_,
+ unused_resources_.back()->memory_usage());
+ unused_memory_usage_bytes_ -= unused_resources_.back()->memory_usage();
DeleteResource(PopBack(&unused_resources_));
}
}
diff --git a/chromium/cc/resources/resource_pool.h b/chromium/cc/resources/resource_pool.h
index 23b3d968041..b579879040c 100644
--- a/chromium/cc/resources/resource_pool.h
+++ b/chromium/cc/resources/resource_pool.h
@@ -22,7 +22,6 @@
#include "base/time/time.h"
#include "base/trace_event/memory_allocator_dump_guid.h"
#include "base/trace_event/memory_dump_provider.h"
-#include "base/unguessable_token.h"
#include "cc/cc_export.h"
#include "components/viz/common/resources/resource_format.h"
#include "components/viz/common/resources/resource_id.h"
@@ -264,7 +263,9 @@ class CC_EXPORT ResourcePool : public base::trace_event::MemoryDumpProvider {
void ReduceResourceUsage();
bool ResourceUsageTooHigh();
- size_t memory_usage_bytes() const { return in_use_memory_usage_bytes_; }
+ size_t memory_usage_bytes() const {
+ return total_memory_usage_bytes_ - unused_memory_usage_bytes_;
+ }
size_t resource_count() const { return in_use_resources_.size(); }
// Overridden from base::trace_event::MemoryDumpProvider:
@@ -471,7 +472,7 @@ class CC_EXPORT ResourcePool : public base::trace_event::MemoryDumpProvider {
size_t next_resource_unique_id_ = 1;
size_t max_memory_usage_bytes_ = 0;
size_t max_resource_count_ = 0;
- size_t in_use_memory_usage_bytes_ = 0;
+ size_t unused_memory_usage_bytes_ = 0;
size_t total_memory_usage_bytes_ = 0;
size_t total_resource_count_ = 0;
bool evict_expired_resources_pending_ = false;
diff --git a/chromium/cc/resources/resource_pool_unittest.cc b/chromium/cc/resources/resource_pool_unittest.cc
index 67435e35fd6..047d139b8c7 100644
--- a/chromium/cc/resources/resource_pool_unittest.cc
+++ b/chromium/cc/resources/resource_pool_unittest.cc
@@ -32,7 +32,7 @@ class ResourcePoolTest : public testing::Test {
context_support_ = context_support.get();
context_provider_ =
viz::TestContextProvider::Create(std::move(context_support));
- context_provider_->BindToCurrentThread();
+ context_provider_->BindToCurrentSequence();
resource_provider_ = std::make_unique<viz::ClientResourceProvider>();
test_task_runner_ = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
resource_pool_ = std::make_unique<ResourcePool>(
@@ -290,7 +290,7 @@ TEST_F(ResourcePoolTest, BusyResourcesNotFreed) {
resource_pool_->ReleaseResource(std::move(resource));
EXPECT_EQ(40000u, resource_pool_->GetTotalMemoryUsageForTesting());
- EXPECT_EQ(0u, resource_pool_->memory_usage_bytes());
+ EXPECT_EQ(40000u, resource_pool_->memory_usage_bytes());
EXPECT_EQ(1u, resource_pool_->GetBusyResourceCountForTesting());
// Wait for our resource pool to evict resources. Wait 10x the expiration
@@ -300,8 +300,14 @@ TEST_F(ResourcePoolTest, BusyResourcesNotFreed) {
// Busy resources are still held, since they may be in flight to the display
// compositor and should not be freed.
EXPECT_EQ(40000u, resource_pool_->GetTotalMemoryUsageForTesting());
- EXPECT_EQ(0u, resource_pool_->memory_usage_bytes());
+ EXPECT_EQ(40000u, resource_pool_->memory_usage_bytes());
EXPECT_EQ(1u, resource_pool_->GetBusyResourceCountForTesting());
+
+ resource_provider_->ReleaseAllExportedResources(/*lose=*/false);
+
+ EXPECT_EQ(40000u, resource_pool_->GetTotalMemoryUsageForTesting());
+ EXPECT_EQ(0u, resource_pool_->memory_usage_bytes());
+ EXPECT_EQ(0u, resource_pool_->GetBusyResourceCountForTesting());
}
TEST_F(ResourcePoolTest, UnusedResourcesEventuallyFreed) {
diff --git a/chromium/cc/resources/scoped_ui_resource.h b/chromium/cc/resources/scoped_ui_resource.h
index 3658f7f12b8..b621cb1c1ca 100644
--- a/chromium/cc/resources/scoped_ui_resource.h
+++ b/chromium/cc/resources/scoped_ui_resource.h
@@ -8,7 +8,6 @@
#include <memory>
#include "base/memory/raw_ptr.h"
-#include "base/memory/ref_counted.h"
#include "cc/cc_export.h"
#include "cc/resources/ui_resource_bitmap.h"
#include "cc/resources/ui_resource_client.h"
diff --git a/chromium/cc/resources/ui_resource_bitmap.h b/chromium/cc/resources/ui_resource_bitmap.h
index 4e8af30e827..e879c531c1b 100644
--- a/chromium/cc/resources/ui_resource_bitmap.h
+++ b/chromium/cc/resources/ui_resource_bitmap.h
@@ -7,7 +7,6 @@
#include <stdint.h>
-#include "base/memory/ref_counted.h"
#include "cc/cc_export.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkCanvas.h"
diff --git a/chromium/cc/resources/ui_resource_client.h b/chromium/cc/resources/ui_resource_client.h
index 044f5d969fb..84a661029b0 100644
--- a/chromium/cc/resources/ui_resource_client.h
+++ b/chromium/cc/resources/ui_resource_client.h
@@ -6,7 +6,6 @@
#define CC_RESOURCES_UI_RESOURCE_CLIENT_H_
#include "base/callback.h"
-#include "base/memory/ref_counted.h"
#include "cc/cc_export.h"
namespace cc {
diff --git a/chromium/cc/resources/ui_resource_manager.cc b/chromium/cc/resources/ui_resource_manager.cc
index 7edb67e606f..14b98b497f1 100644
--- a/chromium/cc/resources/ui_resource_manager.cc
+++ b/chromium/cc/resources/ui_resource_manager.cc
@@ -65,7 +65,7 @@ base::flat_map<UIResourceId, gfx::Size> UIResourceManager::GetUIResourceSizes()
const {
base::flat_map<UIResourceId, gfx::Size>::container_type items(
ui_resource_client_map_.size());
- for (const auto pair : ui_resource_client_map_)
+ for (const auto& pair : ui_resource_client_map_)
items.push_back({pair.first, pair.second.size});
return base::flat_map<UIResourceId, gfx::Size>(std::move(items));
}
diff --git a/chromium/cc/resources/ui_resource_manager.h b/chromium/cc/resources/ui_resource_manager.h
index 482361f34f8..34733ed074f 100644
--- a/chromium/cc/resources/ui_resource_manager.h
+++ b/chromium/cc/resources/ui_resource_manager.h
@@ -10,6 +10,7 @@
#include <vector>
#include "base/containers/flat_map.h"
+#include "base/memory/raw_ptr.h"
#include "cc/cc_export.h"
#include "cc/resources/ui_resource_request.h"
@@ -67,7 +68,7 @@ class CC_EXPORT UIResourceManager {
private:
struct UIResourceClientData {
- UIResourceClient* client;
+ raw_ptr<UIResourceClient> client;
gfx::Size size;
};
diff --git a/chromium/cc/resources/ui_resource_request.h b/chromium/cc/resources/ui_resource_request.h
index 0e5e77a9171..5a6fb6f79b6 100644
--- a/chromium/cc/resources/ui_resource_request.h
+++ b/chromium/cc/resources/ui_resource_request.h
@@ -19,7 +19,6 @@ class CC_EXPORT UIResourceRequest {
enum UIResourceRequestType {
UI_RESOURCE_CREATE,
UI_RESOURCE_DELETE,
- UI_RESOURCE_INVALID_REQUEST
};
UIResourceRequest(UIResourceRequestType type, UIResourceId id);
diff --git a/chromium/cc/scheduler/scheduler.cc b/chromium/cc/scheduler/scheduler.cc
index 60afd6953b0..70d851879fd 100644
--- a/chromium/cc/scheduler/scheduler.cc
+++ b/chromium/cc/scheduler/scheduler.cc
@@ -13,6 +13,7 @@
#include "base/check_op.h"
#include "base/location.h"
#include "base/metrics/histogram_macros.h"
+#include "base/task/delay_policy.h"
#include "base/task/single_thread_task_runner.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/traced_value.h"
@@ -224,6 +225,7 @@ void Scheduler::NotifyReadyToCommit(
state_machine_.NotifyReadyToCommit();
next_commit_origin_frame_args_ = last_dispatched_begin_main_frame_args_;
}
+ trace_actions_ = true;
ProcessScheduledActions();
}
@@ -775,7 +777,9 @@ void Scheduler::ScheduleBeginImplFrameDeadline() {
FROM_HERE, deadline_,
base::BindOnce(&Scheduler::OnBeginImplFrameDeadline,
base::Unretained(this)),
- base::ExactDeadline(true));
+ deadline_mode_ == DeadlineMode::LATE
+ ? base::subtle::DelayPolicy::kFlexibleNoSooner
+ : base::subtle::DelayPolicy::kPrecise);
}
}
@@ -889,6 +893,10 @@ void Scheduler::ProcessScheduledActions() {
SchedulerStateMachine::Action action;
do {
action = state_machine_.NextAction();
+
+ if (trace_actions_ && action != SchedulerStateMachine::Action::NONE &&
+ commit_debug_action_sequence_.size() < 40)
+ commit_debug_action_sequence_.push_back(action);
TRACE_EVENT(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
"SchedulerStateMachine", [this](perfetto::EventContext ctx) {
this->AsProtozeroInto(ctx,
@@ -922,6 +930,8 @@ void Scheduler::ProcessScheduledActions() {
state_machine_.WillCommit(/*commit_had_no_updates=*/false);
compositor_timing_history_->WillCommit();
compositor_frame_reporting_controller_->WillCommit();
+ commit_debug_action_sequence_.clear();
+ trace_actions_ = false;
client_->ScheduledActionCommit();
compositor_timing_history_->DidCommit();
compositor_frame_reporting_controller_->DidCommit();
@@ -1072,4 +1082,47 @@ void Scheduler::UpdatePowerModeVote() {
}
}
+std::string Scheduler::GetHungCommitDebugInfo() const {
+ // Convert the stored actions into a debug string.
+ std::string sequence;
+ // We convert each action to a char 'a' plus the enum value. So we only need
+ // the number of actions we're outputting.
+ sequence.reserve(commit_debug_action_sequence_.size());
+ for (auto action : commit_debug_action_sequence_) {
+ sequence.push_back('a' + static_cast<int>(action));
+ }
+ return base::StringPrintf(
+ "a[a%s] bmfs%d hpt%d atnfd%d pw%d aw%d rfa%d", sequence.c_str(),
+ static_cast<int>(state_machine_.begin_main_frame_state()),
+ static_cast<int>(state_machine_.has_pending_tree()),
+ static_cast<int>(state_machine_.active_tree_needs_first_draw()),
+ static_cast<int>(
+ state_machine_.processing_paint_worklets_for_pending_tree()),
+ static_cast<int>(
+ state_machine_.processing_animation_worklets_for_pending_tree()),
+ static_cast<int>(state_machine_.pending_tree_is_ready_for_activation()));
+}
+
+void Scheduler::TraceHungCommitDebugInfo() const {
+ // First output a series of events which have the old actions.
+ for (auto action : commit_debug_action_sequence_) {
+ TRACE_EVENT_INSTANT(
+ "cc", "ProxyImpl::OnHungCommit OldAction",
+ [action](perfetto::EventContext ctx) {
+ ctx.event()
+ ->set_cc_scheduler_state()
+ ->set_state_machine()
+ ->set_major_state()
+ ->set_next_action(
+ SchedulerStateMachine::ActionToProtozeroEnum(action));
+ });
+ }
+ // Finally dump the complete state of the scheduler.
+ TRACE_EVENT_INSTANT("cc", "ProxyImpl::OnHungCommit CurrentState",
+ [this](perfetto::EventContext ctx) {
+ this->AsProtozeroInto(
+ ctx, ctx.event()->set_cc_scheduler_state());
+ });
+}
+
} // namespace cc
diff --git a/chromium/cc/scheduler/scheduler.h b/chromium/cc/scheduler/scheduler.h
index 329e4acb227..bc0ec9c976a 100644
--- a/chromium/cc/scheduler/scheduler.h
+++ b/chromium/cc/scheduler/scheduler.h
@@ -283,6 +283,9 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase {
size_t CommitDurationSampleCountForTesting() const;
+ std::string GetHungCommitDebugInfo() const;
+ void TraceHungCommitDebugInfo() const;
+
protected:
// Virtual for testing.
virtual base::TimeTicks Now() const;
@@ -411,6 +414,10 @@ class CC_EXPORT Scheduler : public viz::BeginFrameObserverBase {
// Used only for UMa metric calculations.
base::TimeDelta cc_frame_time_available_;
base::TimeTicks cc_frame_start_; // Begin impl frame time.
+
+ // Temporary for production debugging of renderer hang (crbug.com/1159366).
+ std::vector<SchedulerStateMachine::Action> commit_debug_action_sequence_;
+ bool trace_actions_ = false;
};
} // namespace cc
diff --git a/chromium/cc/scheduler/scheduler_settings.h b/chromium/cc/scheduler/scheduler_settings.h
index b79f9e1465c..edb7455ac6b 100644
--- a/chromium/cc/scheduler/scheduler_settings.h
+++ b/chromium/cc/scheduler/scheduler_settings.h
@@ -7,7 +7,6 @@
#include <memory>
-#include "base/memory/ref_counted.h"
#include "cc/cc_export.h"
namespace base {
diff --git a/chromium/cc/scheduler/scheduler_state_machine.h b/chromium/cc/scheduler/scheduler_state_machine.h
index 0732977ec39..1cb9b340064 100644
--- a/chromium/cc/scheduler/scheduler_state_machine.h
+++ b/chromium/cc/scheduler/scheduler_state_machine.h
@@ -371,6 +371,13 @@ class CC_EXPORT SchedulerStateMachine {
bool resourceless_draw() const { return resourceless_draw_; }
+ bool processing_animation_worklets_for_pending_tree() const {
+ return processing_animation_worklets_for_pending_tree_;
+ }
+ bool processing_paint_worklets_for_pending_tree() const {
+ return processing_paint_worklets_for_pending_tree_;
+ }
+
protected:
bool BeginFrameRequiredForAction() const;
bool BeginFrameNeededForVideo() const;
diff --git a/chromium/cc/tiles/checker_image_tracker_unittest.cc b/chromium/cc/tiles/checker_image_tracker_unittest.cc
index 995eadb5523..8d91d9a8136 100644
--- a/chromium/cc/tiles/checker_image_tracker_unittest.cc
+++ b/chromium/cc/tiles/checker_image_tracker_unittest.cc
@@ -10,7 +10,7 @@
#include "base/bind.h"
#include "base/run_loop.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/task/single_thread_task_runner.h"
#include "cc/paint/paint_image_builder.h"
#include "cc/test/skia_common.h"
#include "cc/tiles/image_controller.h"
@@ -34,8 +34,8 @@ class TestImageController : public ImageController {
// We can use the same thread for the image worker because all use of it in
// the ImageController is over-ridden here.
TestImageController()
- : ImageController(base::ThreadTaskRunnerHandle::Get().get(),
- base::ThreadTaskRunnerHandle::Get()) {
+ : ImageController(base::SingleThreadTaskRunner::GetCurrentDefault().get(),
+ base::SingleThreadTaskRunner::GetCurrentDefault()) {
SetMaxImageCacheLimitBytesForTesting(kMaxImageCacheSizeBytes);
}
diff --git a/chromium/cc/tiles/gpu_image_decode_cache.cc b/chromium/cc/tiles/gpu_image_decode_cache.cc
index 8a49e44647d..58063332d14 100644
--- a/chromium/cc/tiles/gpu_image_decode_cache.cc
+++ b/chromium/cc/tiles/gpu_image_decode_cache.cc
@@ -23,8 +23,9 @@
#include "base/metrics/histogram_macros.h"
#include "base/notreached.h"
#include "base/numerics/safe_math.h"
+#include "base/ranges/algorithm.h"
#include "base/strings/stringprintf.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/task/single_thread_task_runner.h"
#include "base/trace_event/memory_dump_manager.h"
#include "cc/base/devtools_instrumentation.h"
#include "cc/base/features.h"
@@ -640,7 +641,7 @@ class ImageUploadTaskImpl : public TileTask {
~ImageUploadTaskImpl() override = default;
private:
- raw_ptr<GpuImageDecodeCache> cache_;
+ raw_ptr<GpuImageDecodeCache, DanglingUntriaged> cache_;
DrawImage image_;
const ImageDecodeCache::TracingInfo tracing_info_;
};
@@ -1028,9 +1029,10 @@ GpuImageDecodeCache::GpuImageDecodeCache(
// In certain cases, ThreadTaskRunnerHandle isn't set (Android Webview).
// Don't register a dump provider in these cases.
- if (base::ThreadTaskRunnerHandle::IsSet()) {
+ if (base::SingleThreadTaskRunner::HasCurrentDefault()) {
base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
- this, "cc::GpuImageDecodeCache", base::ThreadTaskRunnerHandle::Get());
+ this, "cc::GpuImageDecodeCache",
+ base::SingleThreadTaskRunner::GetCurrentDefault());
}
memory_pressure_listener_ = std::make_unique<base::MemoryPressureListener>(
FROM_HERE, base::BindRepeating(&GpuImageDecodeCache::OnMemoryPressure,
@@ -1047,7 +1049,7 @@ GpuImageDecodeCache::~GpuImageDecodeCache() {
// SetShouldAggressivelyFreeResources will zero our limits and free all
// outstanding image memory.
- SetShouldAggressivelyFreeResources(true);
+ SetShouldAggressivelyFreeResources(true, /*context_lock_acquired=*/false);
// It is safe to unregister, even if we didn't register in the constructor.
base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
@@ -1055,27 +1057,34 @@ GpuImageDecodeCache::~GpuImageDecodeCache() {
}
ImageDecodeCache::TaskResult GpuImageDecodeCache::GetTaskForImageAndRef(
+ ClientId client_id,
const DrawImage& draw_image,
const TracingInfo& tracing_info) {
DCHECK_EQ(tracing_info.task_type, TaskType::kInRaster);
- return GetTaskForImageAndRefInternal(draw_image, tracing_info,
+ return GetTaskForImageAndRefInternal(client_id, draw_image, tracing_info,
DecodeTaskType::kPartOfUploadTask);
}
ImageDecodeCache::TaskResult
GpuImageDecodeCache::GetOutOfRasterDecodeTaskForImageAndRef(
+ ClientId client_id,
const DrawImage& draw_image) {
return GetTaskForImageAndRefInternal(
- draw_image, TracingInfo(0, TilePriority::NOW, TaskType::kOutOfRaster),
+ client_id, draw_image,
+ TracingInfo(0, TilePriority::NOW, TaskType::kOutOfRaster),
DecodeTaskType::kStandAloneDecodeTask);
}
ImageDecodeCache::TaskResult GpuImageDecodeCache::GetTaskForImageAndRefInternal(
+ ClientId client_id,
const DrawImage& draw_image,
const TracingInfo& tracing_info,
DecodeTaskType task_type) {
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
- "GpuImageDecodeCache::GetTaskForImageAndRef");
+ DCHECK_GE(client_id, kDefaultClientId);
+
+ TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
+ "GpuImageDecodeCache::GetTaskForImageAndRef", "client_id",
+ client_id);
if (SkipImage(draw_image)) {
return TaskResult(false /* need_unref */, false /* is_at_raster_decode */,
@@ -1101,20 +1110,71 @@ ImageDecodeCache::TaskResult GpuImageDecodeCache::GetTaskForImageAndRefInternal(
return TaskResult(false /* need_unref */, false /* is_at_raster_decode */,
image_data->decode.can_do_hardware_accelerated_decode());
} else if (task_type == DecodeTaskType::kPartOfUploadTask &&
- image_data->upload.task) {
+ !image_data->upload.task_map.empty() &&
+ !image_data->HasUploadedData()) {
+ // If there are pending upload tasks and we haven't had data uploaded yet,
+ // another task can be created.
+
// We had an existing upload task, ref the image and return the task.
image_data->ValidateBudgeted();
RefImage(draw_image, cache_key);
- return TaskResult(image_data->upload.task,
+
+ // If we had a task for the same image and the |client_id|, refptr will be
+ // returned. Otherwise, create a new task for a new client and the same
+ // image and return it.
+ scoped_refptr<TileTask> task =
+ GetTaskFromMapForClientId(client_id, image_data->upload.task_map);
+ if (!task) {
+ // Given it's a new task for this |client_id|, the image must be reffed
+ // before creating a task - this ref is owned by the caller, and it is
+ // their responsibility to release it by calling UnrefImage.
+ RefImage(draw_image, cache_key);
+
+ task = base::MakeRefCounted<ImageUploadTaskImpl>(
+ this, draw_image,
+ GetImageDecodeTaskAndRef(client_id, draw_image, tracing_info,
+ task_type),
+ tracing_info);
+ image_data->upload.task_map[client_id] = task;
+ }
+ DCHECK(task);
+ return TaskResult(task,
image_data->decode.can_do_hardware_accelerated_decode());
} else if (task_type == DecodeTaskType::kStandAloneDecodeTask &&
- image_data->decode.stand_alone_task) {
+ !image_data->decode.stand_alone_task_map.empty() &&
+ !image_data->HasUploadedData()) {
+ // If there are pending decode tasks and we haven't had decoded data yet,
+ // another task can be created.
+
// We had an existing out of raster task, ref the image and return the task.
image_data->ValidateBudgeted();
RefImage(draw_image, cache_key);
+
+ // If we had a task for the same image and the |client_id|, refptr will be
+ // returned. Otherwise, create a new task for a new client and the same
+ // image and return it.
+ scoped_refptr<TileTask> task = GetTaskFromMapForClientId(
+ client_id, image_data->decode.stand_alone_task_map);
+ if (!task) {
+ // Even though it's a new task for this client, we don't need to have
+ // additional reference here (which the caller is responsible for) as
+ // GetImageDecodeTaskAndRef does that for us.
+
+ task = GetImageDecodeTaskAndRef(client_id, draw_image, tracing_info,
+ task_type);
+#if DCHECK_IS_ON()
+ scoped_refptr<TileTask> found_task = GetTaskFromMapForClientId(
+ client_id, image_data->decode.stand_alone_task_map);
+ CHECK_EQ(task, found_task);
+#endif
+ }
DCHECK(!image_data->decode.can_do_hardware_accelerated_decode());
- return TaskResult(image_data->decode.stand_alone_task,
- false /* can_do_hardware_accelerated_decode */);
+
+ // This will be null if the image was already decoded.
+ if (task)
+ return TaskResult(task, /*can_do_hardware_accelerated_decode=*/false);
+ return TaskResult(/*need_unref=*/true, /*is_at_raster_decode=*/false,
+ /*can_do_hardware_accelerated_decode=*/false);
}
// Ensure that the image we're about to decode/upload will fit in memory, if
@@ -1150,11 +1210,13 @@ ImageDecodeCache::TaskResult GpuImageDecodeCache::GetTaskForImageAndRefInternal(
RefImage(draw_image, cache_key);
task = base::MakeRefCounted<ImageUploadTaskImpl>(
this, draw_image,
- GetImageDecodeTaskAndRef(draw_image, tracing_info, task_type),
+ GetImageDecodeTaskAndRef(client_id, draw_image, tracing_info,
+ task_type),
tracing_info);
- image_data->upload.task = task;
+ image_data->upload.task_map[client_id] = task;
} else {
- task = GetImageDecodeTaskAndRef(draw_image, tracing_info, task_type);
+ task = GetImageDecodeTaskAndRef(client_id, draw_image, tracing_info,
+ task_type);
}
if (task) {
@@ -1305,15 +1367,22 @@ void GpuImageDecodeCache::ReduceCacheUsage() NO_THREAD_SAFETY_ANALYSIS {
}
void GpuImageDecodeCache::SetShouldAggressivelyFreeResources(
- bool aggressively_free_resources) {
+ bool aggressively_free_resources,
+ bool context_lock_acquired) {
TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"GpuImageDecodeCache::SetShouldAggressivelyFreeResources",
"agressive_free_resources", aggressively_free_resources);
if (aggressively_free_resources) {
absl::optional<viz::RasterContextProvider::ScopedRasterContextLock>
context_lock;
- if (context_->GetLock())
- context_lock.emplace(context_);
+ if (auto* lock = context_->GetLock()) {
+ // There are callers that might have already acquired the lock. Thus,
+ // check if that's the case.
+ if (context_lock_acquired)
+ lock->AssertAcquired();
+ else
+ context_lock.emplace(context_);
+ }
base::AutoLock lock(lock_);
aggressively_freeing_resources_ = aggressively_free_resources;
@@ -1585,12 +1654,10 @@ void GpuImageDecodeCache::OnImageDecodeTaskCompleted(
UMA_HISTOGRAM_BOOLEAN("Compositing.DecodeLCPCandidateImage.Hardware",
draw_image.paint_image().may_be_lcp_candidate());
if (task_type == DecodeTaskType::kPartOfUploadTask) {
- DCHECK(image_data->decode.task);
- image_data->decode.task = nullptr;
+ image_data->decode.task_map.clear();
} else {
DCHECK(task_type == DecodeTaskType::kStandAloneDecodeTask);
- DCHECK(image_data->decode.stand_alone_task);
- image_data->decode.stand_alone_task = nullptr;
+ image_data->decode.stand_alone_task_map.clear();
}
// While the decode task is active, we keep a ref on the decoded data.
@@ -1607,8 +1674,7 @@ void GpuImageDecodeCache::OnImageUploadTaskCompleted(
InUseCacheKey cache_key = InUseCacheKeyFromDrawImage(draw_image);
ImageData* image_data = GetImageDataForDrawImage(draw_image, cache_key);
DCHECK(image_data);
- DCHECK(image_data->upload.task);
- image_data->upload.task = nullptr;
+ image_data->upload.task_map.clear();
// While the upload task is active, we keep a ref on both the image it will be
// populating, as well as the decode it needs to populate it. Release these
@@ -1650,6 +1716,7 @@ GpuImageDecodeCache::InUseCacheKeyFromDrawImage(
// Checks if an image decode needs a decode task and returns it.
scoped_refptr<TileTask> GpuImageDecodeCache::GetImageDecodeTaskAndRef(
+ ClientId client_id,
const DrawImage& draw_image,
const TracingInfo& tracing_info,
DecodeTaskType task_type) {
@@ -1679,16 +1746,19 @@ scoped_refptr<TileTask> GpuImageDecodeCache::GetImageDecodeTaskAndRef(
}
// We didn't have an existing locked image, create a task to lock or decode.
- scoped_refptr<TileTask>& existing_task =
- (task_type == DecodeTaskType::kPartOfUploadTask)
- ? image_data->decode.task
- : image_data->decode.stand_alone_task;
+ ImageTaskMap* task_map = &image_data->decode.stand_alone_task_map;
+ if (task_type == DecodeTaskType::kPartOfUploadTask)
+ task_map = &image_data->decode.task_map;
+
+ scoped_refptr<TileTask> existing_task =
+ GetTaskFromMapForClientId(client_id, *task_map);
if (!existing_task) {
// Ref image decode and create a decode task. This ref will be released in
// DecodeTaskCompleted.
RefImageDecode(draw_image, cache_key);
existing_task = base::MakeRefCounted<GpuImageDecodeTaskImpl>(
this, draw_image, tracing_info, task_type);
+ (*task_map)[client_id] = existing_task;
}
return existing_task;
}
@@ -2195,6 +2265,10 @@ void GpuImageDecodeCache::UploadImageIfNecessary(const DrawImage& draw_image,
if (target_color_space) {
target_color_params = draw_image.target_color_params();
target_color_params->color_space = gfx::ColorSpace(*target_color_space);
+ if (const auto* image_metadata =
+ draw_image.paint_image().GetImageHeaderMetadata()) {
+ target_color_params->hdr_metadata = image_metadata->hdr_metadata;
+ }
}
if (image_data->mode == DecodedDataMode::kTransferCache) {
@@ -3255,4 +3329,19 @@ void GpuImageDecodeCache::UpdateMipsIfNeeded(const DrawImage& draw_image,
image_data->upload.gl_id());
}
+// static
+scoped_refptr<TileTask> GpuImageDecodeCache::GetTaskFromMapForClientId(
+ const ClientId client_id,
+ const ImageTaskMap& task_map) {
+ auto task_it = base::ranges::find_if(
+ task_map,
+ [client_id](
+ const std::pair<ClientId, scoped_refptr<TileTask>> task_item) {
+ return client_id == task_item.first;
+ });
+ if (task_it != task_map.end())
+ return task_it->second;
+ return nullptr;
+}
+
} // namespace cc
diff --git a/chromium/cc/tiles/gpu_image_decode_cache.h b/chromium/cc/tiles/gpu_image_decode_cache.h
index 78d1e48225c..e87ab99191a 100644
--- a/chromium/cc/tiles/gpu_image_decode_cache.h
+++ b/chromium/cc/tiles/gpu_image_decode_cache.h
@@ -11,6 +11,7 @@
#include <utility>
#include <vector>
+#include "base/containers/flat_map.h"
#include "base/containers/lru_cache.h"
#include "base/logging.h"
#include "base/memory/discardable_memory.h"
@@ -154,18 +155,22 @@ class CC_EXPORT GpuImageDecodeCache
// ImageDecodeCache overrides.
// Finds the existing uploaded image for the provided DrawImage. Creates an
- // upload task to upload the image if an exsiting image does not exist.
- TaskResult GetTaskForImageAndRef(const DrawImage& image,
+ // upload task to upload the image if an existing image does not exist.
+ // See |GetTaskForImageAndRefInternal| to learn about the |client_id|.
+ TaskResult GetTaskForImageAndRef(ClientId client_id,
+ const DrawImage& image,
const TracingInfo& tracing_info) override;
+ // See |GetTaskForImageAndRefInternal| to learn about the |client_id|.
TaskResult GetOutOfRasterDecodeTaskForImageAndRef(
+ ClientId client_id,
const DrawImage& image) override;
void UnrefImage(const DrawImage& image) override;
DecodedDrawImage GetDecodedImageForDraw(const DrawImage& draw_image) override;
void DrawWithImageFinished(const DrawImage& image,
const DecodedDrawImage& decoded_image) override;
void ReduceCacheUsage() override;
- void SetShouldAggressivelyFreeResources(
- bool aggressively_free_resources) override;
+ void SetShouldAggressivelyFreeResources(bool aggressively_free_resources,
+ bool context_lock_acquired) override;
void ClearCache() override;
size_t GetMaximumMemoryLimitBytes() const override;
bool UseCacheForDrawImage(const DrawImage& image) const override;
@@ -217,6 +222,7 @@ class CC_EXPORT GpuImageDecodeCache
private:
enum class DecodedDataMode { kGpu, kCpu, kTransferCache };
+ using ImageTaskMap = base::flat_map<ClientId, scoped_refptr<TileTask>>;
// Stores stats tracked by both DecodedImageData and UploadedImageData.
struct ImageDataBase {
@@ -235,7 +241,7 @@ class CC_EXPORT GpuImageDecodeCache
uint32_t ref_count = 0;
// If non-null, this is the pending task to populate this data.
- scoped_refptr<TileTask> task;
+ ImageTaskMap task_map;
protected:
using YUVSkImages = std::array<sk_sp<SkImage>, kNumYUVPlanes>;
@@ -311,7 +317,7 @@ class CC_EXPORT GpuImageDecodeCache
bool decode_failure = false;
// Similar to |task|, but only is generated if there is no associated upload
// generated for this task (ie, this is an out-of-raster request for decode.
- scoped_refptr<TileTask> stand_alone_task;
+ ImageTaskMap stand_alone_task_map;
// Dark mode color filter cache.
struct SkIRectCompare {
@@ -596,13 +602,18 @@ class CC_EXPORT GpuImageDecodeCache
// Similar to GetTaskForImageAndRef, but gets the dependent decode task
// rather than the upload task, if necessary.
scoped_refptr<TileTask> GetImageDecodeTaskAndRef(
+ ClientId client_id,
const DrawImage& image,
const TracingInfo& tracing_info,
DecodeTaskType task_type);
// Note that this function behaves as if it was public (all of the same locks
- // need to be acquired).
- TaskResult GetTaskForImageAndRefInternal(const DrawImage& image,
+ // need to be acquired). Uses |client_id| to identify which client created a
+ // task as the client run their tasks in different namespaces. The client
+ // which ran their task first will execute the task. All the other clients
+ // will have their tasks executed as no-op.
+ TaskResult GetTaskForImageAndRefInternal(ClientId client_id,
+ const DrawImage& image,
const TracingInfo& tracing_info,
DecodeTaskType task_type);
@@ -762,6 +773,10 @@ class CC_EXPORT GpuImageDecodeCache
// Adds mips to an image if required.
void UpdateMipsIfNeeded(const DrawImage& draw_image, ImageData* image_data);
+ static scoped_refptr<TileTask> GetTaskFromMapForClientId(
+ const ClientId client_id,
+ const ImageTaskMap& task_map);
+
const SkColorType color_type_;
const bool use_transfer_cache_ = false;
raw_ptr<viz::RasterContextProvider> context_;
diff --git a/chromium/cc/tiles/gpu_image_decode_cache_perftest.cc b/chromium/cc/tiles/gpu_image_decode_cache_perftest.cc
index 545b7c582b3..63094669333 100644
--- a/chromium/cc/tiles/gpu_image_decode_cache_perftest.cc
+++ b/chromium/cc/tiles/gpu_image_decode_cache_perftest.cc
@@ -51,7 +51,7 @@ class GpuImageDecodeCachePerfTest
/*support_locking=*/false)) {}
void SetUp() override {
- gpu::ContextResult result = context_provider_->BindToCurrentThread();
+ gpu::ContextResult result = context_provider_->BindToCurrentSequence();
ASSERT_EQ(result, gpu::ContextResult::kSuccess);
cache_ = std::make_unique<GpuImageDecodeCache>(
context_provider_.get(), UseTransferCache(), kRGBA_8888_SkColorType,
diff --git a/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc b/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc
index 2f2b44e66d5..d64b3060e1a 100644
--- a/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc
+++ b/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc
@@ -82,6 +82,8 @@ class FakeDiscardableManager {
cached_textures_limit_ = limit;
}
+ size_t live_textures_count() const { return live_textures_count_; }
+
void ExpectLocked(GLuint texture_id) {
EXPECT_TRUE(textures_.end() != textures_.find(texture_id));
@@ -410,7 +412,7 @@ class GpuImageDecodeCacheTest
advertise_accelerated_decoding_);
discardable_manager_.SetGLES2Interface(
context_provider_->UnboundTestContextGL());
- context_provider_->BindToCurrentThread();
+ context_provider_->BindToCurrentSequence();
{
viz::RasterContextProvider::ScopedRasterContextLock context_lock(
context_provider_.get());
@@ -458,6 +460,26 @@ class GpuImageDecodeCacheTest
size, color_space, allocate_encoded_memory, id, color_type_);
}
+ sk_sp<FakePaintImageGenerator> CreateFakePaintImageGenerator(
+ const gfx::Size& size) {
+ constexpr bool allocate_encoded_memory = true;
+
+ SkImageInfo info =
+ SkImageInfo::Make(size.width(), size.height(), color_type_,
+ kPremul_SkAlphaType, SkColorSpace::MakeSRGB());
+ if (do_yuv_decode_) {
+ SkYUVAPixmapInfo yuva_pixmap_info =
+ GetYUVAPixmapInfo(size, yuv_format_, yuv_data_type_);
+ return sk_make_sp<FakePaintImageGenerator>(
+ info, yuva_pixmap_info, std::vector<FrameMetadata>{FrameMetadata()},
+ allocate_encoded_memory);
+ } else {
+ return sk_make_sp<FakePaintImageGenerator>(
+ info, std::vector<FrameMetadata>{FrameMetadata()},
+ allocate_encoded_memory);
+ }
+ }
+
// Create an image that's too large to upload and will trigger falling back to
// software rendering and decoded data storage.
PaintImage CreateLargePaintImageForSoftwareFallback(
@@ -702,19 +724,20 @@ class GpuImageDecodeCacheTest
TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSameImage) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
DrawImage draw_image =
CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f)));
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
DrawImage another_draw_image =
CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f)));
ImageDecodeCache::TaskResult another_result = cache->GetTaskForImageAndRef(
- another_draw_image, ImageDecodeCache::TracingInfo());
+ client_id, another_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(another_result.need_unref);
EXPECT_TRUE(result.task.get() == another_result.task.get());
@@ -725,13 +748,236 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSameImage) {
cache->UnrefImage(draw_image);
}
+// Tests that when the GpuImageDecodeCache is used by multiple clients at the
+// same time, each client gets own task for the same image and only the task
+// that was executed first does decode/upload. All the consequent tasks for the
+// same image are no-op.
+TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSameImageDifferentClients) {
+ auto cache = CreateCache();
+ const uint32_t kClientId1 = cache->GenerateClientId();
+ const uint32_t kClientId2 = cache->GenerateClientId();
+
+ for (size_t order = 1; order <= 4; ++order) {
+ sk_sp<FakePaintImageGenerator> generator =
+ CreateFakePaintImageGenerator(GetNormalImageSize());
+ PaintImage image =
+ PaintImageBuilder::WithDefault()
+ .set_id(PaintImage::GetNextId())
+ .set_paint_image_generator(generator)
+ .set_decoding_mode(PaintImage::DecodingMode::kUnspecified)
+ .TakePaintImage();
+
+ DrawImage draw_image =
+ CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f)));
+ EXPECT_EQ(draw_image.frame_index(), PaintImage::kDefaultFrameIndex);
+ ImageDecodeCache::TaskResult result1 = cache->GetTaskForImageAndRef(
+ kClientId1, draw_image, ImageDecodeCache::TracingInfo());
+ EXPECT_TRUE(result1.need_unref);
+ EXPECT_TRUE(result1.task);
+
+ ImageDecodeCache::TaskResult result2 = cache->GetTaskForImageAndRef(
+ kClientId2, draw_image, ImageDecodeCache::TracingInfo());
+ EXPECT_TRUE(result2.need_unref);
+ EXPECT_TRUE(result2.task);
+
+ // Ensure each client gets own task.
+ EXPECT_NE(result1.task, result2.task);
+
+ DrawImage draw_image2 =
+ CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f)));
+ EXPECT_EQ(draw_image2.frame_index(), PaintImage::kDefaultFrameIndex);
+ ImageDecodeCache::TaskResult another_result = cache->GetTaskForImageAndRef(
+ kClientId1, draw_image2, ImageDecodeCache::TracingInfo());
+ EXPECT_TRUE(another_result.need_unref);
+ EXPECT_TRUE(result1.task.get() == another_result.task.get());
+
+ DrawImage draw_image3 =
+ CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f)));
+ EXPECT_EQ(draw_image3.frame_index(), PaintImage::kDefaultFrameIndex);
+ ImageDecodeCache::TaskResult another_result2 = cache->GetTaskForImageAndRef(
+ kClientId2, draw_image3, ImageDecodeCache::TracingInfo());
+ EXPECT_TRUE(another_result2.need_unref);
+ EXPECT_TRUE(result2.task.get() == another_result2.task.get());
+
+ testing::InSequence s;
+ if (order == 1u) {
+ // The tasks are executed in the following order - decode1, upload1,
+ // decode2, upload2. Only the first decode/upload is executed.
+ TestTileTaskRunner::ProcessTask(result1.task->dependencies()[0].get());
+ TestTileTaskRunner::ProcessTask(result1.task.get());
+ TestTileTaskRunner::ProcessTask(result2.task->dependencies()[0].get());
+ TestTileTaskRunner::ProcessTask(result2.task.get());
+ } else if (order == 2u) {
+ // Same as above, but the order of tasks is different now - decode2,
+ // decode1, upload1, upload2. Now, only decode2 and upload1 are executed.
+ TestTileTaskRunner::ProcessTask(result2.task->dependencies()[0].get());
+ TestTileTaskRunner::ProcessTask(result1.task->dependencies()[0].get());
+ TestTileTaskRunner::ProcessTask(result1.task.get());
+ TestTileTaskRunner::ProcessTask(result2.task.get());
+ } else if (order == 3u) {
+ TestTileTaskRunner::ProcessTask(result2.task->dependencies()[0].get());
+ TestTileTaskRunner::ProcessTask(result1.task.get());
+ TestTileTaskRunner::ProcessTask(result1.task->dependencies()[0].get());
+ TestTileTaskRunner::ProcessTask(result2.task.get());
+ } else {
+ DCHECK_EQ(order, 4u);
+ // Same as the first one, but now the second client's tasks are executed
+ // first.
+ TestTileTaskRunner::ProcessTask(result2.task->dependencies()[0].get());
+ TestTileTaskRunner::ProcessTask(result2.task.get());
+ TestTileTaskRunner::ProcessTask(result1.task->dependencies()[0].get());
+ TestTileTaskRunner::ProcessTask(result1.task.get());
+ }
+
+ EXPECT_EQ(generator->frames_decoded().size(), 1u);
+ EXPECT_EQ(generator->frames_decoded().count(PaintImage::kDefaultFrameIndex),
+ 1u);
+
+ if (use_transfer_cache_) {
+ EXPECT_EQ(discardable_manager_.live_textures_count(), 0u);
+ EXPECT_EQ(transfer_cache_helper_.num_of_entries(), 1u);
+ } else {
+ const size_t num_of_textures = do_yuv_decode_ ? 3u : 1u;
+ EXPECT_EQ(discardable_manager_.live_textures_count(), num_of_textures);
+
+ EXPECT_EQ(transfer_cache_helper_.num_of_entries(), 0u);
+ }
+
+ EXPECT_TRUE(cache->IsInInUseCacheForTesting(draw_image));
+ EXPECT_TRUE(cache->IsInInUseCacheForTesting(draw_image2));
+ EXPECT_TRUE(cache->IsInInUseCacheForTesting(draw_image3));
+ cache->UnrefImage(draw_image);
+ EXPECT_TRUE(cache->IsInInUseCacheForTesting(draw_image));
+ cache->UnrefImage(draw_image);
+ EXPECT_TRUE(cache->IsInInUseCacheForTesting(draw_image));
+ cache->UnrefImage(draw_image);
+ EXPECT_TRUE(cache->IsInInUseCacheForTesting(draw_image));
+ cache->UnrefImage(draw_image);
+ EXPECT_FALSE(cache->IsInInUseCacheForTesting(draw_image));
+ EXPECT_FALSE(cache->IsInInUseCacheForTesting(draw_image2));
+ EXPECT_FALSE(cache->IsInInUseCacheForTesting(draw_image3));
+
+ cache->ClearCache();
+ }
+}
+
+// Verifies that if a client1 has uploaded the image, but haven't had its task
+// mark as completed, a client2 doesn't have a task created. Otherwise, it'll
+// crash while trying to create a decode task, which checks if the image data
+// has already been uploaded.
+TEST_P(GpuImageDecodeCacheTest, DoesNotCreateATaskForAlreadyUploadedImage) {
+ auto cache = CreateCache();
+ const uint32_t kClientId1 = cache->GenerateClientId();
+ const uint32_t kClientId2 = cache->GenerateClientId();
+
+ sk_sp<FakePaintImageGenerator> generator =
+ CreateFakePaintImageGenerator(GetNormalImageSize());
+ PaintImage image =
+ PaintImageBuilder::WithDefault()
+ .set_id(PaintImage::GetNextId())
+ .set_paint_image_generator(generator)
+ .set_decoding_mode(PaintImage::DecodingMode::kUnspecified)
+ .TakePaintImage();
+
+ DrawImage draw_image =
+ CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f)));
+ EXPECT_EQ(draw_image.frame_index(), PaintImage::kDefaultFrameIndex);
+ ImageDecodeCache::TaskResult result1 = cache->GetTaskForImageAndRef(
+ kClientId1, draw_image, ImageDecodeCache::TracingInfo());
+ EXPECT_TRUE(result1.need_unref);
+ EXPECT_TRUE(result1.task);
+
+ // The tasks are executed in the following order - decode1, upload1,
+ // decode2, upload2. Only the first decode/upload is executed.
+ TestTileTaskRunner::ProcessTask(result1.task->dependencies()[0].get());
+ TestTileTaskRunner::ScheduleTask(result1.task.get());
+ TestTileTaskRunner::RunTask(result1.task.get());
+
+ DrawImage another_draw_image =
+ CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f)));
+ EXPECT_EQ(another_draw_image.frame_index(), PaintImage::kDefaultFrameIndex);
+ ImageDecodeCache::TaskResult result2 = cache->GetTaskForImageAndRef(
+ kClientId2, another_draw_image, ImageDecodeCache::TracingInfo());
+ EXPECT_TRUE(result2.need_unref);
+ EXPECT_FALSE(result2.task);
+
+ TestTileTaskRunner::CompleteTask(result1.task.get());
+
+ cache->UnrefImage(draw_image);
+ cache->UnrefImage(another_draw_image);
+ cache->ClearCache();
+}
+
+// Almost the same as DoesNotCreateATaskForAlreadyUploadedImage, but with a
+// single client and a second request for a standalone decode task.
+TEST_P(GpuImageDecodeCacheTest, DoesNotCreateATaskForAlreadyUploadedImage2) {
+ auto cache = CreateCache();
+ const uint32_t kClientId1 = cache->GenerateClientId();
+
+ sk_sp<FakePaintImageGenerator> generator =
+ CreateFakePaintImageGenerator(GetNormalImageSize());
+ PaintImage image =
+ PaintImageBuilder::WithDefault()
+ .set_id(PaintImage::GetNextId())
+ .set_paint_image_generator(generator)
+ .set_decoding_mode(PaintImage::DecodingMode::kUnspecified)
+ .TakePaintImage();
+
+ DrawImage draw_image =
+ CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f)));
+ EXPECT_EQ(draw_image.frame_index(), PaintImage::kDefaultFrameIndex);
+ // Get upload/decode task.
+ ImageDecodeCache::TaskResult result1 = cache->GetTaskForImageAndRef(
+ kClientId1, draw_image, ImageDecodeCache::TracingInfo());
+ EXPECT_TRUE(result1.need_unref);
+ EXPECT_TRUE(result1.task);
+
+ // Get stand-alone decode task.
+ DrawImage another_draw_image =
+ CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f)));
+ EXPECT_EQ(another_draw_image.frame_index(), PaintImage::kDefaultFrameIndex);
+ ImageDecodeCache::TaskResult result2 =
+ cache->GetOutOfRasterDecodeTaskForImageAndRef(kClientId1,
+ another_draw_image);
+ EXPECT_TRUE(result2.need_unref);
+ // It must be a valid task.
+ EXPECT_TRUE(result2.task);
+
+ // Execute decode/upload, but do not complete.
+ TestTileTaskRunner::ProcessTask(result1.task->dependencies()[0].get());
+ TestTileTaskRunner::ScheduleTask(result1.task.get());
+ TestTileTaskRunner::RunTask(result1.task.get());
+
+ DrawImage yet_another_draw_image =
+ CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f)));
+ EXPECT_EQ(yet_another_draw_image.frame_index(),
+ PaintImage::kDefaultFrameIndex);
+ // Ask for the decode standalone task again.
+ ImageDecodeCache::TaskResult result3 =
+ cache->GetOutOfRasterDecodeTaskForImageAndRef(kClientId1,
+ yet_another_draw_image);
+ EXPECT_TRUE(result3.need_unref);
+ // It mustn't be created now as we already have image decoded/uploaded.
+ EXPECT_FALSE(result3.task);
+
+ // Complete and process created tasks.
+ TestTileTaskRunner::CompleteTask(result1.task.get());
+ TestTileTaskRunner::ProcessTask(result2.task.get());
+
+ cache->UnrefImage(draw_image);
+ cache->UnrefImage(another_draw_image);
+ cache->UnrefImage(yet_another_draw_image);
+ cache->ClearCache();
+}
+
TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSmallerScale) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
DrawImage draw_image =
CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f)));
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
@@ -742,7 +988,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSmallerScale) {
DrawImage another_draw_image =
CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
ImageDecodeCache::TaskResult another_result = cache->GetTaskForImageAndRef(
- another_draw_image, ImageDecodeCache::TracingInfo());
+ client_id, another_draw_image, ImageDecodeCache::TracingInfo());
// |another_draw_image| represents previous image but at a different scale.
// It still has one dependency (decoding), and its upload task is equivalent
@@ -762,11 +1008,12 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSmallerScale) {
TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLowerQuality) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
SkM44 matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f));
DrawImage draw_image = CreateDrawImageInternal(image, matrix);
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
@@ -774,7 +1021,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLowerQuality) {
CreateDrawImageInternal(image, matrix, nullptr /* color_space */,
PaintFlags::FilterQuality::kLow);
ImageDecodeCache::TaskResult another_result = cache->GetTaskForImageAndRef(
- another_draw_image, ImageDecodeCache::TracingInfo());
+ client_id, another_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(another_result.need_unref);
EXPECT_TRUE(result.task.get() == another_result.task.get());
@@ -787,12 +1034,13 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLowerQuality) {
TEST_P(GpuImageDecodeCacheTest, GetTaskForImageDifferentImage) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize());
DrawImage first_draw_image = CreateDrawImageInternal(
first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef(
- first_draw_image, ImageDecodeCache::TracingInfo());
+ client_id, first_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(first_result.need_unref);
EXPECT_TRUE(first_result.task);
@@ -800,7 +1048,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageDifferentImage) {
DrawImage second_draw_image = CreateDrawImageInternal(
second_image, CreateMatrix(SkSize::Make(0.25f, 0.25f)));
ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef(
- second_draw_image, ImageDecodeCache::TracingInfo());
+ client_id, second_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(second_result.need_unref);
EXPECT_TRUE(second_result.task);
EXPECT_TRUE(first_result.task.get() != second_result.task.get());
@@ -816,12 +1064,13 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageDifferentImage) {
TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScale) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize());
DrawImage first_draw_image = CreateDrawImageInternal(
first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef(
- first_draw_image, ImageDecodeCache::TracingInfo());
+ client_id, first_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(first_result.need_unref);
EXPECT_TRUE(first_result.task);
@@ -832,7 +1081,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScale) {
DrawImage second_draw_image = CreateDrawImageInternal(first_image);
ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef(
- second_draw_image, ImageDecodeCache::TracingInfo());
+ client_id, second_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(second_result.need_unref);
EXPECT_TRUE(second_result.task);
EXPECT_TRUE(first_result.task.get() != second_result.task.get());
@@ -840,7 +1089,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScale) {
DrawImage third_draw_image = CreateDrawImageInternal(
first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
ImageDecodeCache::TaskResult third_result = cache->GetTaskForImageAndRef(
- third_draw_image, ImageDecodeCache::TracingInfo());
+ client_id, third_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(third_result.need_unref);
EXPECT_TRUE(third_result.task.get() == second_result.task.get());
@@ -853,17 +1102,18 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScale) {
TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScaleNoReuse) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize());
DrawImage first_draw_image = CreateDrawImageInternal(
first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef(
- first_draw_image, ImageDecodeCache::TracingInfo());
+ client_id, first_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(first_result.need_unref);
EXPECT_TRUE(first_result.task);
DrawImage second_draw_image = CreateDrawImageInternal(first_image);
ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef(
- second_draw_image, ImageDecodeCache::TracingInfo());
+ client_id, second_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(second_result.need_unref);
EXPECT_TRUE(second_result.task);
EXPECT_TRUE(first_result.task.get() != second_result.task.get());
@@ -871,7 +1121,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScaleNoReuse) {
DrawImage third_draw_image = CreateDrawImageInternal(
first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
ImageDecodeCache::TaskResult third_result = cache->GetTaskForImageAndRef(
- third_draw_image, ImageDecodeCache::TracingInfo());
+ client_id, third_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(third_result.need_unref);
EXPECT_TRUE(third_result.task.get() == first_result.task.get());
@@ -887,13 +1137,14 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScaleNoReuse) {
TEST_P(GpuImageDecodeCacheTest, GetTaskForImageHigherQuality) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
SkM44 matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f));
PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize());
DrawImage first_draw_image =
CreateDrawImageInternal(first_image, matrix, nullptr /* color_space */,
PaintFlags::FilterQuality::kLow);
ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef(
- first_draw_image, ImageDecodeCache::TracingInfo());
+ client_id, first_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(first_result.need_unref);
EXPECT_TRUE(first_result.task);
@@ -906,7 +1157,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageHigherQuality) {
CreateDrawImageInternal(first_image, matrix, nullptr /* color_space */,
PaintFlags::FilterQuality::kMedium);
ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef(
- second_draw_image, ImageDecodeCache::TracingInfo());
+ client_id, second_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(second_result.need_unref);
EXPECT_TRUE(second_result.task);
@@ -918,11 +1169,12 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageHigherQuality) {
TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyDecodedAndLocked) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
DrawImage draw_image =
CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
EXPECT_EQ(result.task->dependencies().size(), 1u);
@@ -938,8 +1190,8 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyDecodedAndLocked) {
// Get the image again - we should have an upload task, but no dependent
// decode task, as the decode was already locked.
- ImageDecodeCache::TaskResult another_result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult another_result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(another_result.need_unref);
EXPECT_TRUE(another_result.task);
EXPECT_EQ(another_result.task->dependencies().size(), 0u);
@@ -955,11 +1207,12 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyDecodedAndLocked) {
TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyDecodedNotLocked) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
DrawImage draw_image =
CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
EXPECT_EQ(result.task->dependencies().size(), 1u);
@@ -977,8 +1230,8 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyDecodedNotLocked) {
// Get the image again - we should have an upload task and a dependent decode
// task - this dependent task will typically just re-lock the image.
- ImageDecodeCache::TaskResult another_result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult another_result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(another_result.need_unref);
EXPECT_TRUE(another_result.task);
EXPECT_EQ(another_result.task->dependencies().size(), 1u);
@@ -992,11 +1245,12 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyDecodedNotLocked) {
TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyUploaded) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
DrawImage draw_image =
CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
EXPECT_EQ(result.task->dependencies().size(), 1u);
@@ -1007,8 +1261,8 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyUploaded) {
TestTileTaskRunner::RunTask(result.task.get());
TestTileTaskRunner::CompleteTask(result.task.get());
- ImageDecodeCache::TaskResult another_result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult another_result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(another_result.need_unref);
EXPECT_FALSE(another_result.task);
@@ -1018,18 +1272,19 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyUploaded) {
TEST_P(GpuImageDecodeCacheTest, GetTaskForImageCanceledGetsNewTask) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
DrawImage draw_image =
CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
- ImageDecodeCache::TaskResult another_result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult another_result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(another_result.task.get() == result.task.get());
@@ -1042,8 +1297,8 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageCanceledGetsNewTask) {
cache->UnrefImage(draw_image);
// Here a new task is created.
- ImageDecodeCache::TaskResult third_result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult third_result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(third_result.need_unref);
EXPECT_TRUE(third_result.task);
EXPECT_FALSE(third_result.task.get() == result.task.get());
@@ -1056,19 +1311,20 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageCanceledGetsNewTask) {
TEST_P(GpuImageDecodeCacheTest, GetTaskForImageCanceledWhileReffedGetsNewTask) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
DrawImage draw_image =
CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
ASSERT_GT(result.task->dependencies().size(), 0u);
TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
- ImageDecodeCache::TaskResult another_result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult another_result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(another_result.need_unref);
EXPECT_TRUE(another_result.task.get() == result.task.get());
@@ -1082,8 +1338,8 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageCanceledWhileReffedGetsNewTask) {
// Note that here, everything is reffed, but a new task is created. This is
// possible with repeated schedule/cancel operations.
- ImageDecodeCache::TaskResult third_result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult third_result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(third_result.need_unref);
EXPECT_TRUE(third_result.task);
EXPECT_FALSE(third_result.task.get() == result.task.get());
@@ -1098,11 +1354,12 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageCanceledWhileReffedGetsNewTask) {
TEST_P(GpuImageDecodeCacheTest, GetTaskForImageUploadCanceledButDecodeRun) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
DrawImage draw_image =
CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
EXPECT_EQ(result.task->dependencies().size(), 1u);
@@ -1122,11 +1379,12 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageUploadCanceledButDecodeRun) {
TEST_P(GpuImageDecodeCacheTest, NoTaskForImageAlreadyFailedDecoding) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
DrawImage draw_image =
CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
@@ -1137,8 +1395,8 @@ TEST_P(GpuImageDecodeCacheTest, NoTaskForImageAlreadyFailedDecoding) {
cache->SetImageDecodingFailedForTesting(draw_image);
- ImageDecodeCache::TaskResult another_result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult another_result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_FALSE(another_result.need_unref);
EXPECT_EQ(another_result.task.get(), nullptr);
@@ -1147,11 +1405,12 @@ TEST_P(GpuImageDecodeCacheTest, NoTaskForImageAlreadyFailedDecoding) {
TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDraw) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
DrawImage draw_image =
CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
EXPECT_EQ(result.task->dependencies().size(), 1u);
@@ -1176,6 +1435,7 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDraw) {
TEST_P(GpuImageDecodeCacheTest, GetHdrDecodedImageForDrawToHdr) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
auto color_space = gfx::ColorSpace::CreateHDR10();
auto size = GetNormalImageSize();
auto info =
@@ -1195,8 +1455,8 @@ TEST_P(GpuImageDecodeCacheTest, GetHdrDecodedImageForDrawToHdr) {
image, CreateMatrix(SkSize::Make(0.5f, 0.5f)), &color_space,
PaintFlags::FilterQuality::kMedium, nullptr,
PaintImage::kDefaultFrameIndex, kCustomWhiteLevel);
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_EQ(draw_image.target_color_space(), color_space);
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
@@ -1229,6 +1489,7 @@ TEST_P(GpuImageDecodeCacheTest, GetHdrDecodedImageForDrawToHdr) {
TEST_P(GpuImageDecodeCacheTest, GetHdrDecodedImageForDrawToSdr) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
auto image_color_space = gfx::ColorSpace::CreateHDR10();
auto size = GetNormalImageSize();
auto info = SkImageInfo::Make(size.width(), size.height(),
@@ -1246,8 +1507,8 @@ TEST_P(GpuImageDecodeCacheTest, GetHdrDecodedImageForDrawToSdr) {
auto raster_color_space = gfx::ColorSpace::CreateSRGB();
DrawImage draw_image = CreateDrawImageInternal(
image, CreateMatrix(SkSize::Make(0.5f, 0.5f)), &raster_color_space);
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_EQ(draw_image.target_color_space(), raster_color_space);
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
@@ -1275,11 +1536,12 @@ TEST_P(GpuImageDecodeCacheTest, GetHdrDecodedImageForDrawToSdr) {
TEST_P(GpuImageDecodeCacheTest, GetLargeDecodedImageForDraw) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
PaintImage image = CreateLargePaintImageForSoftwareFallback();
DrawImage draw_image =
CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.0f, 1.0f)));
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
@@ -1304,14 +1566,15 @@ TEST_P(GpuImageDecodeCacheTest, GetLargeDecodedImageForDraw) {
TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawAtRasterDecode) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
cache->SetWorkingSetLimitsForTesting(0 /* max_bytes */, 0 /* max_items */);
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
DrawImage draw_image =
CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.0f, 1.0f)));
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_FALSE(result.need_unref);
EXPECT_FALSE(result.task);
@@ -1335,12 +1598,13 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawAtRasterDecode) {
TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawLargerScale) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
DrawImage draw_image = CreateDrawImageInternal(
image, CreateMatrix(SkSize::Make(0.5f, 0.5f)), nullptr /* color_space */,
PaintFlags::FilterQuality::kLow);
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
@@ -1350,7 +1614,7 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawLargerScale) {
DrawImage larger_draw_image =
CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(1.5f, 1.5f)));
ImageDecodeCache::TaskResult larger_result = cache->GetTaskForImageAndRef(
- larger_draw_image, ImageDecodeCache::TracingInfo());
+ client_id, larger_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(larger_result.need_unref);
EXPECT_TRUE(larger_result.task);
@@ -1384,13 +1648,14 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawLargerScale) {
TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawHigherQuality) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
SkM44 matrix = CreateMatrix(SkSize::Make(0.5f, 0.5f));
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
DrawImage draw_image =
CreateDrawImageInternal(image, matrix, nullptr /* color_space */,
PaintFlags::FilterQuality::kLow);
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
@@ -1399,7 +1664,7 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawHigherQuality) {
DrawImage higher_quality_draw_image = CreateDrawImageInternal(image, matrix);
ImageDecodeCache::TaskResult hq_result = cache->GetTaskForImageAndRef(
- higher_quality_draw_image, ImageDecodeCache::TracingInfo());
+ client_id, higher_quality_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(hq_result.need_unref);
EXPECT_TRUE(hq_result.task);
TestTileTaskRunner::ProcessTask(hq_result.task->dependencies()[0].get());
@@ -1432,11 +1697,12 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawHigherQuality) {
TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawNegative) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
DrawImage draw_image =
CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(-0.5f, 0.5f)));
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
@@ -1465,13 +1731,14 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawNegative) {
TEST_P(GpuImageDecodeCacheTest, GetLargeScaledDecodedImageForDraw) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
PaintImage image = CreatePaintImageForFallbackToRGB(
gfx::Size(GetLargeImageSize().width(), GetLargeImageSize().height() * 2));
DrawImage draw_image = CreateDrawImageInternal(
image, CreateMatrix(SkSize::Make(0.5f, 0.5f)), nullptr /* color_space */,
PaintFlags::FilterQuality::kHigh);
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
@@ -1503,14 +1770,15 @@ TEST_P(GpuImageDecodeCacheTest, GetLargeScaledDecodedImageForDraw) {
TEST_P(GpuImageDecodeCacheTest, AtRasterUsedDirectlyIfSpaceAllows) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
const gfx::Size test_image_size = GetNormalImageSize();
cache->SetWorkingSetLimitsForTesting(0 /* max_bytes */, 0 /* max_items */);
PaintImage image = CreatePaintImageInternal(test_image_size);
DrawImage draw_image = CreateDrawImageInternal(image);
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_FALSE(result.need_unref);
EXPECT_FALSE(result.task);
@@ -1531,8 +1799,8 @@ TEST_P(GpuImageDecodeCacheTest, AtRasterUsedDirectlyIfSpaceAllows) {
GetBytesNeededForSingleImage(test_image_size);
cache->SetWorkingSetLimitsForTesting(bytes_for_test_image /* max_bytes */,
256 /* max_items */);
- ImageDecodeCache::TaskResult another_result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult another_result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(another_result.need_unref);
EXPECT_FALSE(another_result.task);
cache->UnrefImage(draw_image);
@@ -1607,12 +1875,13 @@ TEST_P(GpuImageDecodeCacheTest,
TEST_P(GpuImageDecodeCacheTest, ZeroSizedImagesAreSkipped) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
DrawImage draw_image =
CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.f, 0.f)));
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_FALSE(result.task);
EXPECT_FALSE(result.need_unref);
@@ -1628,6 +1897,7 @@ TEST_P(GpuImageDecodeCacheTest, ZeroSizedImagesAreSkipped) {
TEST_P(GpuImageDecodeCacheTest, NonOverlappingSrcRectImagesAreSkipped) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
DrawImage draw_image(
image, false,
@@ -1636,8 +1906,8 @@ TEST_P(GpuImageDecodeCacheTest, NonOverlappingSrcRectImagesAreSkipped) {
PaintFlags::FilterQuality::kMedium, CreateMatrix(SkSize::Make(1.f, 1.f)),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_FALSE(result.task);
EXPECT_FALSE(result.need_unref);
@@ -1653,14 +1923,15 @@ TEST_P(GpuImageDecodeCacheTest, NonOverlappingSrcRectImagesAreSkipped) {
TEST_P(GpuImageDecodeCacheTest, CanceledTasksDoNotCountAgainstBudget) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
SkIRect src_rect = SkIRect::MakeXYWH(0, 0, image.width(), image.height());
DrawImage draw_image = CreateDrawImageInternal(
image, CreateMatrix(SkSize::Make(1.f, 1.f)), nullptr /* color_space */,
PaintFlags::FilterQuality::kMedium, &src_rect);
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_NE(0u, cache->GetNumCacheEntriesForTesting());
EXPECT_TRUE(result.task);
EXPECT_TRUE(result.need_unref);
@@ -1676,12 +1947,13 @@ TEST_P(GpuImageDecodeCacheTest, CanceledTasksDoNotCountAgainstBudget) {
TEST_P(GpuImageDecodeCacheTest, ShouldAggressivelyFreeResources) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
DrawImage draw_image =
CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
{
ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
- draw_image, ImageDecodeCache::TracingInfo());
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
@@ -1694,7 +1966,8 @@ TEST_P(GpuImageDecodeCacheTest, ShouldAggressivelyFreeResources) {
EXPECT_GT(cache->GetNumCacheEntriesForTesting(), 0u);
// Tell our cache to aggressively free resources.
- cache->SetShouldAggressivelyFreeResources(true);
+ cache->SetShouldAggressivelyFreeResources(true,
+ /*context_lock_acquired=*/false);
EXPECT_EQ(0u, cache->GetNumCacheEntriesForTesting());
}
@@ -1702,7 +1975,7 @@ TEST_P(GpuImageDecodeCacheTest, ShouldAggressivelyFreeResources) {
// be cached past its use.
{
ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
- draw_image, ImageDecodeCache::TracingInfo());
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
@@ -1715,10 +1988,11 @@ TEST_P(GpuImageDecodeCacheTest, ShouldAggressivelyFreeResources) {
// We now tell the cache to not aggressively free resources. The image may
// now be cached past its use.
- cache->SetShouldAggressivelyFreeResources(false);
+ cache->SetShouldAggressivelyFreeResources(false,
+ /*context_lock_acquired=*/false);
{
ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
- draw_image, ImageDecodeCache::TracingInfo());
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
@@ -1732,12 +2006,13 @@ TEST_P(GpuImageDecodeCacheTest, ShouldAggressivelyFreeResources) {
TEST_P(GpuImageDecodeCacheTest, OrphanedImagesFreeOnReachingZeroRefs) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
// Create a downscaled image.
PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize());
DrawImage first_draw_image = CreateDrawImageInternal(
first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef(
- first_draw_image, ImageDecodeCache::TracingInfo());
+ client_id, first_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(first_result.need_unref);
EXPECT_TRUE(first_result.task);
@@ -1750,7 +2025,7 @@ TEST_P(GpuImageDecodeCacheTest, OrphanedImagesFreeOnReachingZeroRefs) {
DrawImage second_draw_image = CreateDrawImageInternal(
first_image, CreateMatrix(SkSize::Make(1.0f, 1.0f)));
ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef(
- second_draw_image, ImageDecodeCache::TracingInfo());
+ client_id, second_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(second_result.need_unref);
EXPECT_TRUE(second_result.task);
EXPECT_TRUE(first_result.task.get() != second_result.task.get());
@@ -1773,12 +2048,13 @@ TEST_P(GpuImageDecodeCacheTest, OrphanedImagesFreeOnReachingZeroRefs) {
TEST_P(GpuImageDecodeCacheTest, OrphanedZeroRefImagesImmediatelyDeleted) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
// Create a downscaled image.
PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize());
DrawImage first_draw_image = CreateDrawImageInternal(
first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef(
- first_draw_image, ImageDecodeCache::TracingInfo());
+ client_id, first_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(first_result.need_unref);
EXPECT_TRUE(first_result.task);
@@ -1794,7 +2070,7 @@ TEST_P(GpuImageDecodeCacheTest, OrphanedZeroRefImagesImmediatelyDeleted) {
// memory used by |first_image| for the smaller scale.
DrawImage second_draw_image = CreateDrawImageInternal(first_image);
ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef(
- second_draw_image, ImageDecodeCache::TracingInfo());
+ client_id, second_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(second_result.need_unref);
EXPECT_TRUE(second_result.task);
EXPECT_TRUE(first_result.task.get() != second_result.task.get());
@@ -1811,6 +2087,7 @@ TEST_P(GpuImageDecodeCacheTest, OrphanedZeroRefImagesImmediatelyDeleted) {
TEST_P(GpuImageDecodeCacheTest, QualityCappedAtMedium) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
SkM44 matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f));
@@ -1819,7 +2096,7 @@ TEST_P(GpuImageDecodeCacheTest, QualityCappedAtMedium) {
CreateDrawImageInternal(image, matrix, nullptr /* color_space */,
PaintFlags::FilterQuality::kLow);
ImageDecodeCache::TaskResult low_result = cache->GetTaskForImageAndRef(
- low_draw_image, ImageDecodeCache::TracingInfo());
+ client_id, low_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(low_result.need_unref);
EXPECT_TRUE(low_result.task);
@@ -1827,7 +2104,7 @@ TEST_P(GpuImageDecodeCacheTest, QualityCappedAtMedium) {
// low, so we should get a new task/ref.
DrawImage medium_draw_image = CreateDrawImageInternal(image);
ImageDecodeCache::TaskResult medium_result = cache->GetTaskForImageAndRef(
- medium_draw_image, ImageDecodeCache::TracingInfo());
+ client_id, medium_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(medium_result.need_unref);
EXPECT_TRUE(medium_result.task.get());
EXPECT_FALSE(low_result.task.get() == medium_result.task.get());
@@ -1838,7 +2115,7 @@ TEST_P(GpuImageDecodeCacheTest, QualityCappedAtMedium) {
CreateDrawImageInternal(image, matrix, nullptr /* color_space */,
PaintFlags::FilterQuality::kHigh);
ImageDecodeCache::TaskResult high_quality_result =
- cache->GetTaskForImageAndRef(high_quality_draw_image,
+ cache->GetTaskForImageAndRef(client_id, high_quality_draw_image,
ImageDecodeCache::TracingInfo());
EXPECT_TRUE(high_quality_result.need_unref);
EXPECT_TRUE(medium_result.task.get() == high_quality_result.task.get());
@@ -1857,11 +2134,12 @@ TEST_P(GpuImageDecodeCacheTest, QualityCappedAtMedium) {
// cache entry creation doesn't cause a buffer overflow/crash.
TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawMipUsageChange) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
// Create an image decode task and cache entry that does not need mips.
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
DrawImage draw_image = CreateDrawImageInternal(image);
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
@@ -1887,6 +2165,7 @@ TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawMipUsageChange) {
TEST_P(GpuImageDecodeCacheTest, OutOfRasterDecodeTask) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
SkM44 matrix = CreateMatrix(SkSize::Make(1.0f, 1.0f));
DrawImage draw_image =
@@ -1894,7 +2173,7 @@ TEST_P(GpuImageDecodeCacheTest, OutOfRasterDecodeTask) {
PaintFlags::FilterQuality::kLow);
ImageDecodeCache::TaskResult result =
- cache->GetOutOfRasterDecodeTaskForImageAndRef(draw_image);
+ cache->GetOutOfRasterDecodeTaskForImageAndRef(client_id, draw_image);
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
EXPECT_TRUE(cache->IsInInUseCacheForTesting(draw_image));
@@ -1907,15 +2186,126 @@ TEST_P(GpuImageDecodeCacheTest, OutOfRasterDecodeTask) {
cache->UnrefImage(draw_image);
}
+// Verifies that only one client's task does real decoding. All the consequent
+// clients who want to decode the same image have their tasks as no-op.
+TEST_P(GpuImageDecodeCacheTest, OutOfRasterDecodeTaskMultipleClients) {
+ auto cache = CreateCache();
+ const uint32_t kClientId1 = cache->GenerateClientId();
+ const uint32_t kClientId2 = cache->GenerateClientId();
+
+ for (size_t order = 1; order <= 2; ++order) {
+ sk_sp<FakePaintImageGenerator> generator =
+ CreateFakePaintImageGenerator(GetNormalImageSize());
+ PaintImage image =
+ PaintImageBuilder::WithDefault()
+ .set_id(PaintImage::GetNextId())
+ .set_paint_image_generator(generator)
+ .set_decoding_mode(PaintImage::DecodingMode::kUnspecified)
+ .TakePaintImage();
+
+ SkM44 matrix = CreateMatrix(SkSize::Make(1.0f, 1.0f));
+ DrawImage draw_image =
+ CreateDrawImageInternal(image, matrix, nullptr /* color_space */,
+ PaintFlags::FilterQuality::kLow);
+
+ ImageDecodeCache::TaskResult result1 =
+ cache->GetOutOfRasterDecodeTaskForImageAndRef(kClientId1, draw_image);
+ EXPECT_TRUE(result1.need_unref);
+ EXPECT_TRUE(result1.task);
+ EXPECT_TRUE(cache->IsInInUseCacheForTesting(draw_image));
+
+ DrawImage draw_image2 =
+ CreateDrawImageInternal(image, matrix, nullptr /* color_space */,
+ PaintFlags::FilterQuality::kLow);
+ ImageDecodeCache::TaskResult result2 =
+ cache->GetOutOfRasterDecodeTaskForImageAndRef(kClientId2, draw_image);
+ EXPECT_TRUE(result2.need_unref);
+ EXPECT_TRUE(result2.task);
+ EXPECT_TRUE(cache->IsInInUseCacheForTesting(draw_image2));
+
+ // Run the decode task in different orders.
+ if (order == 1u) {
+ TestTileTaskRunner::ProcessTask(result1.task.get());
+ TestTileTaskRunner::ProcessTask(result2.task.get());
+ } else {
+ DCHECK_EQ(order, 2u);
+ TestTileTaskRunner::ProcessTask(result2.task.get());
+ TestTileTaskRunner::ProcessTask(result1.task.get());
+ }
+
+ EXPECT_EQ(generator->frames_decoded().size(), 1u);
+ EXPECT_EQ(generator->frames_decoded().count(PaintImage::kDefaultFrameIndex),
+ 1u);
+
+ // The image should remain in the cache till we unref it.
+ EXPECT_TRUE(cache->IsInInUseCacheForTesting(draw_image));
+ EXPECT_TRUE(cache->IsInInUseCacheForTesting(draw_image2));
+ cache->UnrefImage(draw_image);
+ cache->UnrefImage(draw_image2);
+ EXPECT_FALSE(cache->IsInInUseCacheForTesting(draw_image));
+ EXPECT_FALSE(cache->IsInInUseCacheForTesting(draw_image2));
+ }
+}
+
+TEST_P(GpuImageDecodeCacheTest,
+ DoesNotCreateOutOfRasterDecodeTaskForNonCompletedTask) {
+ auto cache = CreateCache();
+ const uint32_t kClientId1 = cache->GenerateClientId();
+ const uint32_t kClientId2 = cache->GenerateClientId();
+
+ sk_sp<FakePaintImageGenerator> generator =
+ CreateFakePaintImageGenerator(GetNormalImageSize());
+ PaintImage image =
+ PaintImageBuilder::WithDefault()
+ .set_id(PaintImage::GetNextId())
+ .set_paint_image_generator(generator)
+ .set_decoding_mode(PaintImage::DecodingMode::kUnspecified)
+ .TakePaintImage();
+
+ SkM44 matrix = CreateMatrix(SkSize::Make(1.0f, 1.0f));
+ DrawImage draw_image =
+ CreateDrawImageInternal(image, matrix, nullptr /* color_space */,
+ PaintFlags::FilterQuality::kLow);
+
+ ImageDecodeCache::TaskResult result1 =
+ cache->GetOutOfRasterDecodeTaskForImageAndRef(kClientId1, draw_image);
+ EXPECT_TRUE(result1.need_unref);
+ EXPECT_TRUE(result1.task);
+ EXPECT_TRUE(cache->IsInInUseCacheForTesting(draw_image));
+
+ TestTileTaskRunner::ScheduleTask(result1.task.get());
+ TestTileTaskRunner::RunTask(result1.task.get());
+
+ DrawImage draw_image2 =
+ CreateDrawImageInternal(image, matrix, nullptr /* color_space */,
+ PaintFlags::FilterQuality::kLow);
+ ImageDecodeCache::TaskResult result2 =
+ cache->GetOutOfRasterDecodeTaskForImageAndRef(kClientId2, draw_image);
+ EXPECT_TRUE(result2.need_unref);
+ EXPECT_FALSE(result2.task);
+ EXPECT_TRUE(cache->IsInInUseCacheForTesting(draw_image2));
+
+ TestTileTaskRunner::CompleteTask(result1.task.get());
+
+ // The image should remain in the cache till we unref it.
+ EXPECT_TRUE(cache->IsInInUseCacheForTesting(draw_image));
+ EXPECT_TRUE(cache->IsInInUseCacheForTesting(draw_image2));
+ cache->UnrefImage(draw_image);
+ cache->UnrefImage(draw_image2);
+ EXPECT_FALSE(cache->IsInInUseCacheForTesting(draw_image));
+ EXPECT_FALSE(cache->IsInInUseCacheForTesting(draw_image2));
+}
+
TEST_P(GpuImageDecodeCacheTest, ZeroCacheNormalWorkingSet) {
SetCachedTexturesLimit(0);
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
// Add an image to the cache-> Due to normal working set, this should produce
// a task and a ref.
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
DrawImage draw_image = CreateDrawImageInternal(image);
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
EXPECT_EQ(result.task->dependencies().size(), 1u);
@@ -1926,8 +2316,8 @@ TEST_P(GpuImageDecodeCacheTest, ZeroCacheNormalWorkingSet) {
TestTileTaskRunner::ProcessTask(result.task.get());
// Request the same image - it should be cached.
- ImageDecodeCache::TaskResult second_result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(second_result.need_unref);
EXPECT_FALSE(second_result.task);
@@ -1940,8 +2330,8 @@ TEST_P(GpuImageDecodeCacheTest, ZeroCacheNormalWorkingSet) {
// Get the image again. As it was fully unreffed, it is no longer in the
// working set and will be evicted due to 0 cache size.
- ImageDecodeCache::TaskResult third_result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult third_result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(third_result.need_unref);
EXPECT_TRUE(third_result.task);
EXPECT_EQ(third_result.task->dependencies().size(), 1u);
@@ -1957,6 +2347,7 @@ TEST_P(GpuImageDecodeCacheTest, SmallCacheNormalWorkingSet) {
// Cache will fit one image.
SetCachedTexturesLimit(1);
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
DrawImage draw_image = CreateDrawImageInternal(image);
@@ -1970,7 +2361,7 @@ TEST_P(GpuImageDecodeCacheTest, SmallCacheNormalWorkingSet) {
// Add an image to the cache and un-ref it.
{
ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
- draw_image, ImageDecodeCache::TracingInfo());
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
EXPECT_EQ(result.task->dependencies().size(), 1u);
@@ -1985,7 +2376,7 @@ TEST_P(GpuImageDecodeCacheTest, SmallCacheNormalWorkingSet) {
// Request the same image - it should be cached.
{
ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
- draw_image, ImageDecodeCache::TracingInfo());
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_FALSE(result.task);
cache->UnrefImage(draw_image);
@@ -1994,7 +2385,7 @@ TEST_P(GpuImageDecodeCacheTest, SmallCacheNormalWorkingSet) {
// Add a new image to the cache It should push out the old one.
{
ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
- draw_image2, ImageDecodeCache::TracingInfo());
+ client_id, draw_image2, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
EXPECT_EQ(result.task->dependencies().size(), 1u);
@@ -2009,7 +2400,7 @@ TEST_P(GpuImageDecodeCacheTest, SmallCacheNormalWorkingSet) {
// Request the second image - it should be cached.
{
ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
- draw_image2, ImageDecodeCache::TracingInfo());
+ client_id, draw_image2, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_FALSE(result.task);
cache->UnrefImage(draw_image2);
@@ -2019,7 +2410,7 @@ TEST_P(GpuImageDecodeCacheTest, SmallCacheNormalWorkingSet) {
// task.
{
ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
- draw_image, ImageDecodeCache::TracingInfo());
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
EXPECT_EQ(result.task->dependencies().size(), 1u);
@@ -2034,11 +2425,12 @@ TEST_P(GpuImageDecodeCacheTest, SmallCacheNormalWorkingSet) {
TEST_P(GpuImageDecodeCacheTest, ClearCache) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
for (int i = 0; i < 10; ++i) {
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
DrawImage draw_image = CreateDrawImageInternal(image);
ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
- draw_image, ImageDecodeCache::TracingInfo());
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
@@ -2058,11 +2450,12 @@ TEST_P(GpuImageDecodeCacheTest, ClearCache) {
TEST_P(GpuImageDecodeCacheTest, ClearCacheInUse) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
// Create an image but keep it reffed so it can't be immediately freed.
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
DrawImage draw_image = CreateDrawImageInternal(image);
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
@@ -2087,6 +2480,7 @@ TEST_P(GpuImageDecodeCacheTest, ClearCacheInUse) {
TEST_P(GpuImageDecodeCacheTest, GetTaskForImageDifferentColorSpace) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
gfx::ColorSpace color_space_a = gfx::ColorSpace::CreateSRGB();
gfx::ColorSpace color_space_b = gfx::ColorSpace::CreateXYZD50();
@@ -2094,14 +2488,14 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageDifferentColorSpace) {
DrawImage first_draw_image = CreateDrawImageInternal(
first_image, CreateMatrix(SkSize::Make(1.0f, 1.0f)), &color_space_a);
ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef(
- first_draw_image, ImageDecodeCache::TracingInfo());
+ client_id, first_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(first_result.need_unref);
EXPECT_TRUE(first_result.task);
DrawImage second_draw_image = CreateDrawImageInternal(
first_image, CreateMatrix(SkSize::Make(1.0f, 1.0f)), &color_space_b);
ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef(
- second_draw_image, ImageDecodeCache::TracingInfo());
+ client_id, second_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(second_result.need_unref);
EXPECT_TRUE(second_result.task);
EXPECT_TRUE(first_result.task.get() != second_result.task.get());
@@ -2109,7 +2503,7 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageDifferentColorSpace) {
DrawImage third_draw_image = CreateDrawImageInternal(
first_image, CreateMatrix(SkSize::Make(1.0f, 1.0f)), &color_space_a);
ImageDecodeCache::TaskResult third_result = cache->GetTaskForImageAndRef(
- third_draw_image, ImageDecodeCache::TracingInfo());
+ client_id, third_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(third_result.need_unref);
EXPECT_TRUE(third_result.task.get() == first_result.task.get());
@@ -2125,12 +2519,13 @@ TEST_P(GpuImageDecodeCacheTest, GetTaskForImageDifferentColorSpace) {
TEST_P(GpuImageDecodeCacheTest, GetTaskForLargeImageNonSRGBColorSpace) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
gfx::ColorSpace color_space = gfx::ColorSpace::CreateXYZD50();
PaintImage image = CreateLargePaintImageForSoftwareFallback();
DrawImage draw_image = CreateDrawImageInternal(
image, CreateMatrix(SkSize::Make(1.0f, 1.0f)), &color_space);
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
@@ -2211,12 +2606,13 @@ TEST_P(GpuImageDecodeCacheTest, CacheDecodesExpectedFrames) {
TEST_P(GpuImageDecodeCacheTest, OrphanedDataCancelledWhileReplaced) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
// Create a downscaled image.
PaintImage first_image = CreatePaintImageInternal(GetNormalImageSize());
DrawImage first_draw_image = CreateDrawImageInternal(
first_image, CreateMatrix(SkSize::Make(0.5f, 0.5f)));
ImageDecodeCache::TaskResult first_result = cache->GetTaskForImageAndRef(
- first_draw_image, ImageDecodeCache::TracingInfo());
+ client_id, first_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(first_result.need_unref);
EXPECT_TRUE(first_result.task);
@@ -2227,7 +2623,7 @@ TEST_P(GpuImageDecodeCacheTest, OrphanedDataCancelledWhileReplaced) {
// the memory used by |first_image| for the smaller scale.
DrawImage second_draw_image = CreateDrawImageInternal(first_image);
ImageDecodeCache::TaskResult second_result = cache->GetTaskForImageAndRef(
- second_draw_image, ImageDecodeCache::TracingInfo());
+ client_id, second_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(second_result.need_unref);
EXPECT_TRUE(second_result.task);
EXPECT_TRUE(first_result.task.get() != second_result.task.get());
@@ -2258,6 +2654,7 @@ TEST_P(GpuImageDecodeCacheTest, OrphanedDataCancelledWhileReplaced) {
TEST_P(GpuImageDecodeCacheTest, AlreadyBudgetedImagesAreNotAtRaster) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
const gfx::Size test_image_size = GetNormalImageSize();
PaintImage image = CreatePaintImageInternal(test_image_size);
@@ -2269,15 +2666,15 @@ TEST_P(GpuImageDecodeCacheTest, AlreadyBudgetedImagesAreNotAtRaster) {
cache->SetWorkingSetLimitsForTesting(bytes_for_test_image,
1u /* max_items */);
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
// Try locking the same image again, its already budgeted so it shouldn't be
// at-raster.
- result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ result = cache->GetTaskForImageAndRef(client_id, draw_image,
+ ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
@@ -2294,6 +2691,7 @@ TEST_P(GpuImageDecodeCacheTest, AlreadyBudgetedImagesAreNotAtRaster) {
TEST_P(GpuImageDecodeCacheTest, ImageBudgetingByCount) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
const gfx::Size test_image_size = GetNormalImageSize();
// Allow a single image by count. Use a high byte limit as we want to test the
@@ -2319,7 +2717,7 @@ TEST_P(GpuImageDecodeCacheTest, ImageBudgetingByCount) {
// Should be at raster.
ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
- second_draw_image, ImageDecodeCache::TracingInfo());
+ client_id, second_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_FALSE(result.need_unref);
EXPECT_FALSE(result.task);
// Image retrieved from at-raster decode should not be budgeted.
@@ -2334,6 +2732,7 @@ TEST_P(GpuImageDecodeCacheTest, ImageBudgetingByCount) {
TEST_P(GpuImageDecodeCacheTest, ImageBudgetingBySize) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
const gfx::Size test_image_size = GetNormalImageSize();
PaintImage image = CreatePaintImageInternal(test_image_size);
@@ -2360,7 +2759,7 @@ TEST_P(GpuImageDecodeCacheTest, ImageBudgetingBySize) {
// Should be at raster.
ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
- second_draw_image, ImageDecodeCache::TracingInfo());
+ client_id, second_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_FALSE(result.need_unref);
EXPECT_FALSE(result.task);
// Image retrieved from at-raster decode should not be budgeted.
@@ -2376,6 +2775,7 @@ TEST_P(GpuImageDecodeCacheTest, ImageBudgetingBySize) {
TEST_P(GpuImageDecodeCacheTest,
ColorConversionDuringDecodeForLargeImageNonSRGBColorSpace) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
sk_sp<SkColorSpace> image_color_space =
gfx::ColorSpace::CreateDisplayP3D65().ToSkColorSpace();
gfx::ColorSpace color_space = gfx::ColorSpace::CreateXYZD50();
@@ -2384,8 +2784,8 @@ TEST_P(GpuImageDecodeCacheTest,
CreateLargePaintImageForSoftwareFallback(image_color_space);
DrawImage draw_image = CreateDrawImageInternal(
image, CreateMatrix(SkSize::Make(1.0f, 1.0f)), &color_space);
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
@@ -2432,13 +2832,14 @@ TEST_P(GpuImageDecodeCacheTest,
TEST_P(GpuImageDecodeCacheTest,
ColorConversionDuringUploadForSmallImageNonSRGBColorSpace) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
gfx::ColorSpace color_space = gfx::ColorSpace::CreateDisplayP3D65();
PaintImage image = CreatePaintImageInternal(gfx::Size(11, 12));
DrawImage draw_image = CreateDrawImageInternal(
image, CreateMatrix(SkSize::Make(1.0f, 1.0f)), &color_space);
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
@@ -2503,11 +2904,12 @@ TEST_P(GpuImageDecodeCacheTest, NonLazyImageUploadTaskHasNoDeps) {
return;
}
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
PaintImage image = CreateBitmapImageInternal(GetNormalImageSize());
DrawImage draw_image = CreateDrawImageInternal(image);
- auto result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ auto result = cache->GetTaskForImageAndRef(client_id, draw_image,
+ ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
EXPECT_TRUE(result.task->dependencies().empty());
@@ -2522,18 +2924,56 @@ TEST_P(GpuImageDecodeCacheTest, NonLazyImageUploadTaskCancelled) {
return;
}
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
+
+ PaintImage image = CreateBitmapImageInternal(GetNormalImageSize());
+ DrawImage draw_image = CreateDrawImageInternal(image);
+ auto result = cache->GetTaskForImageAndRef(client_id, draw_image,
+ ImageDecodeCache::TracingInfo());
+ EXPECT_TRUE(result.need_unref);
+ EXPECT_TRUE(result.task);
+ EXPECT_TRUE(result.task->dependencies().empty());
+ TestTileTaskRunner::CancelTask(result.task.get());
+ TestTileTaskRunner::CompleteTask(result.task.get());
+
+ cache->UnrefImage(draw_image);
+}
+
+TEST_P(GpuImageDecodeCacheTest,
+ NonLazyImageUploadTaskCancelledMultipleClients) {
+ if (do_yuv_decode_) {
+ // YUV bitmap images do not happen, so this test will always skip for YUV.
+ GTEST_SKIP();
+ }
+
+ auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
+ const uint32_t client_id2 = cache->GenerateClientId();
PaintImage image = CreateBitmapImageInternal(GetNormalImageSize());
DrawImage draw_image = CreateDrawImageInternal(image);
- auto result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ auto result = cache->GetTaskForImageAndRef(client_id, draw_image,
+ ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
EXPECT_TRUE(result.task->dependencies().empty());
+
+ DrawImage draw_image2 = CreateDrawImageInternal(image);
+ auto result2 = cache->GetTaskForImageAndRef(client_id2, draw_image2,
+ ImageDecodeCache::TracingInfo());
+
+ EXPECT_TRUE(result2.need_unref);
+ EXPECT_TRUE(result2.task);
+ EXPECT_TRUE(result2.task->dependencies().empty());
+
TestTileTaskRunner::CancelTask(result.task.get());
TestTileTaskRunner::CompleteTask(result.task.get());
+ TestTileTaskRunner::CancelTask(result2.task.get());
+ TestTileTaskRunner::CompleteTask(result2.task.get());
+
cache->UnrefImage(draw_image);
+ cache->UnrefImage(draw_image2);
}
TEST_P(GpuImageDecodeCacheTest, NonLazyImageLargeImageNotColorConverted) {
@@ -2707,12 +3147,13 @@ TEST_P(GpuImageDecodeCacheTest, BasicMips) {
SkSize scale, gfx::ColorSpace color_space,
bool should_have_mips) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
DrawImage draw_image = CreateDrawImageInternal(
image, CreateMatrix(scale), &color_space, filter_quality);
ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
- draw_image, ImageDecodeCache::TracingInfo());
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
@@ -2773,6 +3214,7 @@ TEST_P(GpuImageDecodeCacheTest, BasicMips) {
TEST_P(GpuImageDecodeCacheTest, MipsAddedSubsequentDraw) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
@@ -2780,7 +3222,7 @@ TEST_P(GpuImageDecodeCacheTest, MipsAddedSubsequentDraw) {
{
DrawImage draw_image = CreateDrawImageInternal(image);
ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
- draw_image, ImageDecodeCache::TracingInfo());
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
@@ -2830,7 +3272,7 @@ TEST_P(GpuImageDecodeCacheTest, MipsAddedSubsequentDraw) {
DrawImage draw_image =
CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.6f, 0.6f)));
ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
- draw_image, ImageDecodeCache::TracingInfo());
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_FALSE(result.task);
@@ -2870,6 +3312,7 @@ TEST_P(GpuImageDecodeCacheTest, MipsAddedSubsequentDraw) {
TEST_P(GpuImageDecodeCacheTest, MipsAddedWhileOriginalInUse) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
struct Decode {
@@ -2882,7 +3325,7 @@ TEST_P(GpuImageDecodeCacheTest, MipsAddedWhileOriginalInUse) {
{
DrawImage draw_image = CreateDrawImageInternal(image);
ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
- draw_image, ImageDecodeCache::TracingInfo());
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
@@ -2925,7 +3368,7 @@ TEST_P(GpuImageDecodeCacheTest, MipsAddedWhileOriginalInUse) {
DrawImage draw_image =
CreateDrawImageInternal(image, CreateMatrix(SkSize::Make(0.6f, 0.6f)));
ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
- draw_image, ImageDecodeCache::TracingInfo());
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_FALSE(result.task);
@@ -3006,7 +3449,9 @@ TEST_P(GpuImageDecodeCacheTest,
return;
}
auto owned_cache = CreateCache();
- auto decode_and_check_plane_sizes = [this, cache = owned_cache.get()]() {
+ const uint32_t owned_cache_client_id = owned_cache->GenerateClientId();
+ auto decode_and_check_plane_sizes = [this, cache = owned_cache.get(),
+ client_id = owned_cache_client_id]() {
PaintFlags::FilterQuality filter_quality =
PaintFlags::FilterQuality::kMedium;
SkSize requires_decode_at_original_scale = SkSize::Make(0.8f, 0.8f);
@@ -3017,7 +3462,7 @@ TEST_P(GpuImageDecodeCacheTest,
filter_quality, CreateMatrix(requires_decode_at_original_scale),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
- draw_image, ImageDecodeCache::TracingInfo());
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
@@ -3078,6 +3523,7 @@ TEST_P(GpuImageDecodeCacheTest, HighBitDepthYUVDecoding) {
auto decode_and_check_plane_sizes = [this](
GpuImageDecodeCache* cache,
+ uint32_t client_id,
bool decodes_to_yuv,
SkYUVAPixmapInfo::DataType
yuv_data_type = SkYUVAPixmapInfo::
@@ -3113,7 +3559,7 @@ TEST_P(GpuImageDecodeCacheTest, HighBitDepthYUVDecoding) {
filter_quality, CreateMatrix(requires_decode_at_original_scale),
PaintImage::kDefaultFrameIndex, target_color_params);
ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
- draw_image, ImageDecodeCache::TracingInfo());
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
@@ -3197,35 +3643,36 @@ TEST_P(GpuImageDecodeCacheTest, HighBitDepthYUVDecoding) {
r16_caps.texture_half_float_linear = true;
context_provider_->SetContextCapabilitiesOverride(r16_caps);
auto r16_cache = CreateCache();
+ const uint32_t client_id = r16_cache->GenerateClientId();
yuv_data_type_ = SkYUVAPixmapInfo::DataType::kUnorm16;
yuv_format_ = YUVSubsampling::k420;
- decode_and_check_plane_sizes(r16_cache.get(), true,
+ decode_and_check_plane_sizes(r16_cache.get(), client_id, true,
SkYUVAPixmapInfo::DataType::kUnorm16,
DefaultColorSpace());
yuv_format_ = YUVSubsampling::k422;
- decode_and_check_plane_sizes(r16_cache.get(), true,
+ decode_and_check_plane_sizes(r16_cache.get(), client_id, true,
SkYUVAPixmapInfo::DataType::kUnorm16,
DefaultColorSpace());
yuv_format_ = YUVSubsampling::k444;
- decode_and_check_plane_sizes(r16_cache.get(), true,
+ decode_and_check_plane_sizes(r16_cache.get(), client_id, true,
SkYUVAPixmapInfo::DataType::kUnorm16,
DefaultColorSpace());
// Verify HDR decoding has white level adjustment.
yuv_format_ = YUVSubsampling::k420;
- decode_and_check_plane_sizes(r16_cache.get(), true,
+ decode_and_check_plane_sizes(r16_cache.get(), client_id, true,
SkYUVAPixmapInfo::DataType::kUnorm16, hdr_cs);
yuv_format_ = YUVSubsampling::k422;
- decode_and_check_plane_sizes(r16_cache.get(), true,
+ decode_and_check_plane_sizes(r16_cache.get(), client_id, true,
SkYUVAPixmapInfo::DataType::kUnorm16, hdr_cs);
yuv_format_ = YUVSubsampling::k444;
- decode_and_check_plane_sizes(r16_cache.get(), true,
+ decode_and_check_plane_sizes(r16_cache.get(), client_id, true,
SkYUVAPixmapInfo::DataType::kUnorm16, hdr_cs);
}
@@ -3236,35 +3683,36 @@ TEST_P(GpuImageDecodeCacheTest, HighBitDepthYUVDecoding) {
f16_caps.texture_half_float_linear = true;
context_provider_->SetContextCapabilitiesOverride(f16_caps);
auto f16_cache = CreateCache();
+ const uint32_t client_id = f16_cache->GenerateClientId();
yuv_data_type_ = SkYUVAPixmapInfo::DataType::kFloat16;
yuv_format_ = YUVSubsampling::k420;
- decode_and_check_plane_sizes(f16_cache.get(), true,
+ decode_and_check_plane_sizes(f16_cache.get(), client_id, true,
SkYUVAPixmapInfo::DataType::kFloat16,
DefaultColorSpace());
yuv_format_ = YUVSubsampling::k422;
- decode_and_check_plane_sizes(f16_cache.get(), true,
+ decode_and_check_plane_sizes(f16_cache.get(), client_id, true,
SkYUVAPixmapInfo::DataType::kFloat16,
DefaultColorSpace());
yuv_format_ = YUVSubsampling::k444;
- decode_and_check_plane_sizes(f16_cache.get(), true,
+ decode_and_check_plane_sizes(f16_cache.get(), client_id, true,
SkYUVAPixmapInfo::DataType::kFloat16,
DefaultColorSpace());
// Verify HDR decoding.
yuv_format_ = YUVSubsampling::k420;
- decode_and_check_plane_sizes(f16_cache.get(), true,
+ decode_and_check_plane_sizes(f16_cache.get(), client_id, true,
SkYUVAPixmapInfo::DataType::kFloat16, hdr_cs);
yuv_format_ = YUVSubsampling::k422;
- decode_and_check_plane_sizes(f16_cache.get(), true,
+ decode_and_check_plane_sizes(f16_cache.get(), client_id, true,
SkYUVAPixmapInfo::DataType::kFloat16, hdr_cs);
yuv_format_ = YUVSubsampling::k444;
- decode_and_check_plane_sizes(f16_cache.get(), true,
+ decode_and_check_plane_sizes(f16_cache.get(), client_id, true,
SkYUVAPixmapInfo::DataType::kFloat16, hdr_cs);
}
@@ -3275,28 +3723,29 @@ TEST_P(GpuImageDecodeCacheTest, HighBitDepthYUVDecoding) {
no_yuv16_caps.texture_half_float_linear = false;
context_provider_->SetContextCapabilitiesOverride(no_yuv16_caps);
auto no_yuv16_cache = CreateCache();
+ const uint32_t client_id = no_yuv16_cache->GenerateClientId();
yuv_data_type_ = SkYUVAPixmapInfo::DataType::kUnorm16;
yuv_format_ = YUVSubsampling::k420;
- decode_and_check_plane_sizes(no_yuv16_cache.get(), false);
+ decode_and_check_plane_sizes(no_yuv16_cache.get(), client_id, false);
yuv_format_ = YUVSubsampling::k422;
- decode_and_check_plane_sizes(no_yuv16_cache.get(), false);
+ decode_and_check_plane_sizes(no_yuv16_cache.get(), client_id, false);
yuv_format_ = YUVSubsampling::k444;
- decode_and_check_plane_sizes(no_yuv16_cache.get(), false);
+ decode_and_check_plane_sizes(no_yuv16_cache.get(), client_id, false);
yuv_data_type_ = SkYUVAPixmapInfo::DataType::kFloat16;
yuv_format_ = YUVSubsampling::k420;
- decode_and_check_plane_sizes(no_yuv16_cache.get(), false);
+ decode_and_check_plane_sizes(no_yuv16_cache.get(), client_id, false);
yuv_format_ = YUVSubsampling::k422;
- decode_and_check_plane_sizes(no_yuv16_cache.get(), false);
+ decode_and_check_plane_sizes(no_yuv16_cache.get(), client_id, false);
yuv_format_ = YUVSubsampling::k444;
- decode_and_check_plane_sizes(no_yuv16_cache.get(), false);
+ decode_and_check_plane_sizes(no_yuv16_cache.get(), client_id, false);
}
}
@@ -3313,8 +3762,9 @@ TEST_P(GpuImageDecodeCacheTest, ScaledYUVDecodeScaledDrawCorrectlyMipsPlanes) {
return;
}
auto owned_cache = CreateCache();
+ const uint32_t owned_cache_client_id = owned_cache->GenerateClientId();
auto decode_and_check_plane_sizes =
- [this, cache = owned_cache.get()](
+ [this, cache = owned_cache.get(), client_id = owned_cache_client_id](
SkSize scaled_size,
const SkISize mipped_plane_sizes[SkYUVAInfo::kMaxPlanes]) {
PaintFlags::FilterQuality filter_quality =
@@ -3327,7 +3777,7 @@ TEST_P(GpuImageDecodeCacheTest, ScaledYUVDecodeScaledDrawCorrectlyMipsPlanes) {
filter_quality, CreateMatrix(scaled_size),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
- draw_image, ImageDecodeCache::TracingInfo());
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
@@ -3421,12 +3871,13 @@ TEST_P(GpuImageDecodeCacheTest, GetBorderlineLargeDecodedImageForDraw) {
// We will create a texture that's at the maximum size the GPU says it can
// support for uploads.
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
PaintImage almost_too_large_image =
CreatePaintImageInternal(gfx::Size(max_texture_size_, max_texture_size_));
DrawImage draw_image = CreateDrawImageInternal(almost_too_large_image);
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
ASSERT_TRUE(result.task);
@@ -3452,11 +3903,12 @@ TEST_P(GpuImageDecodeCacheTest, GetBorderlineLargeDecodedImageForDraw) {
TEST_P(GpuImageDecodeCacheTest, OutOfRasterDecodeForBitmaps) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
PaintImage image = CreateBitmapImageInternal(GetNormalImageSize());
DrawImage draw_image = CreateDrawImageInternal(image);
ImageDecodeCache::TaskResult result =
- cache->GetOutOfRasterDecodeTaskForImageAndRef(draw_image);
+ cache->GetOutOfRasterDecodeTaskForImageAndRef(client_id, draw_image);
EXPECT_TRUE(result.need_unref);
EXPECT_FALSE(result.task);
EXPECT_FALSE(result.is_at_raster_decode);
@@ -3472,11 +3924,12 @@ TEST_P(GpuImageDecodeCacheTest, DarkModeDecodedDrawImage) {
std::unique_ptr<FakeRasterDarkModeFilter> dark_mode_filter =
std::make_unique<FakeRasterDarkModeFilter>();
auto cache = CreateCache(kGpuMemoryLimitBytes, dark_mode_filter.get());
+ const uint32_t client_id = cache->GenerateClientId();
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
DrawImage draw_image = CreateDrawImageWithDarkModeInternal(image);
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
TestTileTaskRunner::ProcessTask(result.task->dependencies()[0].get());
TestTileTaskRunner::ProcessTask(result.task.get());
GetImageAndDrawFinishedForDarkMode(cache.get(), draw_image,
@@ -3492,6 +3945,7 @@ TEST_P(GpuImageDecodeCacheTest, DarkModeImageCacheSize) {
std::unique_ptr<FakeRasterDarkModeFilter> dark_mode_filter =
std::make_unique<FakeRasterDarkModeFilter>();
auto cache = CreateCache(kGpuMemoryLimitBytes, dark_mode_filter.get());
+ const uint32_t client_id = cache->GenerateClientId();
PaintImage image1 = CreatePaintImageInternal(GetNormalImageSize());
PaintImage image2 = CreatePaintImageInternal(gfx::Size(50, 50));
@@ -3499,7 +3953,7 @@ TEST_P(GpuImageDecodeCacheTest, DarkModeImageCacheSize) {
DrawImage draw_image11 = CreateDrawImageWithDarkModeInternal(image1);
EXPECT_EQ(cache->GetDarkModeImageCacheSizeForTesting(draw_image11), 0u);
ImageDecodeCache::TaskResult result11 = cache->GetTaskForImageAndRef(
- draw_image11, ImageDecodeCache::TracingInfo());
+ client_id, draw_image11, ImageDecodeCache::TracingInfo());
TestTileTaskRunner::ProcessTask(result11.task->dependencies()[0].get());
TestTileTaskRunner::ProcessTask(result11.task.get());
GetImageAndDrawFinishedForDarkMode(cache.get(), draw_image11,
@@ -3516,7 +3970,7 @@ TEST_P(GpuImageDecodeCacheTest, DarkModeImageCacheSize) {
DrawImage draw_image12 = CreateDrawImageWithDarkModeInternal(
image1, SkM44(), nullptr, PaintFlags::FilterQuality::kMedium, &src);
ImageDecodeCache::TaskResult result12 = cache->GetTaskForImageAndRef(
- draw_image12, ImageDecodeCache::TracingInfo());
+ client_id, draw_image12, ImageDecodeCache::TracingInfo());
GetImageAndDrawFinishedForDarkMode(cache.get(), draw_image12,
dark_mode_filter.get());
EXPECT_EQ(cache->GetDarkModeImageCacheSizeForTesting(draw_image12), 2u);
@@ -3524,7 +3978,7 @@ TEST_P(GpuImageDecodeCacheTest, DarkModeImageCacheSize) {
// Another draw image with full src rect for image1.
DrawImage draw_image13 = CreateDrawImageWithDarkModeInternal(image1);
ImageDecodeCache::TaskResult result13 = cache->GetTaskForImageAndRef(
- draw_image13, ImageDecodeCache::TracingInfo());
+ client_id, draw_image13, ImageDecodeCache::TracingInfo());
GetImageAndDrawFinishedForDarkMode(cache.get(), draw_image13,
dark_mode_filter.get());
EXPECT_EQ(cache->GetDarkModeImageCacheSizeForTesting(draw_image13), 2u);
@@ -3533,7 +3987,7 @@ TEST_P(GpuImageDecodeCacheTest, DarkModeImageCacheSize) {
DrawImage draw_image21 = CreateDrawImageWithDarkModeInternal(image2);
EXPECT_EQ(cache->GetDarkModeImageCacheSizeForTesting(draw_image21), 0u);
ImageDecodeCache::TaskResult result21 = cache->GetTaskForImageAndRef(
- draw_image21, ImageDecodeCache::TracingInfo());
+ client_id, draw_image21, ImageDecodeCache::TracingInfo());
TestTileTaskRunner::ProcessTask(result21.task->dependencies()[0].get());
TestTileTaskRunner::ProcessTask(result21.task.get());
GetImageAndDrawFinishedForDarkMode(cache.get(), draw_image21,
@@ -3558,8 +4012,9 @@ TEST_P(GpuImageDecodeCacheTest, DarkModeNeedsDarkModeFilter) {
std::unique_ptr<FakeRasterDarkModeFilter> dark_mode_filter =
std::make_unique<FakeRasterDarkModeFilter>();
auto cache = CreateCache(kGpuMemoryLimitBytes, dark_mode_filter.get());
+ const uint32_t client_id = cache->GenerateClientId();
ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
- draw_image_with_dark_mode, ImageDecodeCache::TracingInfo());
+ client_id, draw_image_with_dark_mode, ImageDecodeCache::TracingInfo());
// Draw image without dark mode bit set should not need dark mode filter.
EXPECT_FALSE(
@@ -3588,6 +4043,7 @@ TEST_P(GpuImageDecodeCacheTest, DarkModeNeedsDarkModeFilter) {
TEST_P(GpuImageDecodeCacheTest, ClippedAndScaledDrawImageRemovesCacheEntry) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
cache->SetWorkingSetLimitsForTesting(0 /* max_bytes */, 0 /* max_items */);
PaintImage image = CreatePaintImageInternal(GetNormalImageSize());
@@ -3613,7 +4069,7 @@ TEST_P(GpuImageDecodeCacheTest, ClippedAndScaledDrawImageRemovesCacheEntry) {
image, CreateMatrix(SkSize::Make(0.5f, 0.5f)), nullptr,
PaintFlags::FilterQuality::kMedium, &clipped_rect);
ImageDecodeCache::TaskResult clipped_result = cache->GetTaskForImageAndRef(
- clipped_draw_image, ImageDecodeCache::TracingInfo());
+ client_id, clipped_draw_image, ImageDecodeCache::TracingInfo());
// Unless |enable_clipped_image_scaling_| is true, we throw away the
// previously cached entry.
@@ -3700,6 +4156,7 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
for (const auto& subsampling_and_expected_data_size :
subsamplings_and_expected_data_sizes) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
const PaintImage image = CreatePaintImageForDecodeAcceleration(
ImageType::kJPEG, subsampling_and_expected_data_size.first);
const PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kHigh;
@@ -3708,7 +4165,7 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
quality, CreateMatrix(SkSize::Make(0.75f, 0.75f)),
PaintImage::kDefaultFrameIndex, TargetColorParams());
ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
- draw_image, ImageDecodeCache::TracingInfo());
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
ASSERT_TRUE(result.task);
EXPECT_TRUE(result.can_do_hardware_accelerated_decode);
@@ -3739,6 +4196,7 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
RequestAcceleratedDecodeSuccessfullyWithColorSpaceConversion) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
const TargetColorParams target_color_params(gfx::ColorSpace::CreateXYZD50());
ASSERT_TRUE(target_color_params.color_space.IsValid());
const PaintImage image = CreatePaintImageForDecodeAcceleration();
@@ -3747,8 +4205,8 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
SkIRect::MakeWH(image.width(), image.height()), quality,
CreateMatrix(SkSize::Make(0.75f, 0.75f)),
PaintImage::kDefaultFrameIndex, target_color_params);
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
ASSERT_TRUE(result.task);
EXPECT_TRUE(result.can_do_hardware_accelerated_decode);
@@ -3779,6 +4237,7 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
AcceleratedDecodeRequestFails) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
const TargetColorParams target_color_params(gfx::ColorSpace::CreateXYZD50());
ASSERT_TRUE(target_color_params.color_space.IsValid());
const PaintImage image = CreatePaintImageForDecodeAcceleration();
@@ -3787,8 +4246,8 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
SkIRect::MakeWH(image.width(), image.height()), quality,
CreateMatrix(SkSize::Make(0.75f, 0.75f)),
PaintImage::kDefaultFrameIndex, target_color_params);
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
ASSERT_TRUE(result.task);
EXPECT_TRUE(result.can_do_hardware_accelerated_decode);
@@ -3809,8 +4268,8 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
// Attempting to get another task for the image should result in no task
// because the decode is considered to have failed before.
- ImageDecodeCache::TaskResult result_after_run =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result_after_run = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_FALSE(result_after_run.need_unref);
EXPECT_FALSE(result_after_run.task);
EXPECT_TRUE(result_after_run.can_do_hardware_accelerated_decode);
@@ -3828,6 +4287,7 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
CannotRequestAcceleratedDecodeBecauseOfStandAloneDecode) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
const TargetColorParams target_color_params;
ASSERT_TRUE(target_color_params.color_space.IsValid());
const PaintImage image = CreatePaintImageForDecodeAcceleration();
@@ -3837,7 +4297,7 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
CreateMatrix(SkSize::Make(1.0f, 1.0f)),
PaintImage::kDefaultFrameIndex, target_color_params);
ImageDecodeCache::TaskResult result =
- cache->GetOutOfRasterDecodeTaskForImageAndRef(draw_image);
+ cache->GetOutOfRasterDecodeTaskForImageAndRef(client_id, draw_image);
EXPECT_TRUE(result.need_unref);
ASSERT_TRUE(result.task);
EXPECT_FALSE(result.can_do_hardware_accelerated_decode);
@@ -3851,6 +4311,7 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
CannotRequestAcceleratedDecodeBecauseOfNonZeroUploadMipLevel) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
const TargetColorParams target_color_params;
ASSERT_TRUE(target_color_params.color_space.IsValid());
const PaintImage image = CreatePaintImageForDecodeAcceleration();
@@ -3859,8 +4320,8 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
SkIRect::MakeWH(image.width(), image.height()), quality,
CreateMatrix(SkSize::Make(0.5f, 0.5f)),
PaintImage::kDefaultFrameIndex, target_color_params);
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
ASSERT_TRUE(result.task);
EXPECT_FALSE(result.can_do_hardware_accelerated_decode);
@@ -3876,6 +4337,7 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
RequestAcceleratedDecodeSuccessfullyAfterCancellation) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
const TargetColorParams target_color_params;
ASSERT_TRUE(target_color_params.color_space.IsValid());
const PaintImage image = CreatePaintImageForDecodeAcceleration();
@@ -3884,8 +4346,8 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
SkIRect::MakeWH(image.width(), image.height()), quality,
CreateMatrix(SkSize::Make(0.75f, 0.75f)),
PaintImage::kDefaultFrameIndex, target_color_params);
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
ASSERT_TRUE(result.task);
EXPECT_TRUE(result.can_do_hardware_accelerated_decode);
@@ -3898,8 +4360,8 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
TestTileTaskRunner::CompleteTask(result.task.get());
// Get the image again - we should have an upload task.
- ImageDecodeCache::TaskResult another_result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult another_result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(another_result.need_unref);
ASSERT_TRUE(another_result.task);
EXPECT_TRUE(another_result.can_do_hardware_accelerated_decode);
@@ -3926,6 +4388,7 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
RequestAcceleratedDecodeSuccessfullyAtRasterTime) {
// We force at-raster decodes by setting the cache memory limit to 0 bytes.
auto cache = CreateCache(0u /* memory_limit_bytes */);
+ const uint32_t client_id = cache->GenerateClientId();
const TargetColorParams target_color_params;
ASSERT_TRUE(target_color_params.color_space.IsValid());
const PaintImage image = CreatePaintImageForDecodeAcceleration();
@@ -3934,8 +4397,8 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesTest,
SkIRect::MakeWH(image.width(), image.height()), quality,
CreateMatrix(SkSize::Make(0.75f, 0.75f)),
PaintImage::kDefaultFrameIndex, target_color_params);
- ImageDecodeCache::TaskResult result =
- cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache->GetTaskForImageAndRef(
+ client_id, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_FALSE(result.need_unref);
EXPECT_FALSE(result.task);
EXPECT_TRUE(result.is_at_raster_decode);
@@ -3973,6 +4436,7 @@ class GpuImageDecodeCacheWithAcceleratedDecodesFlagsTest
TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesFlagsTest,
RequestAcceleratedDecodeSuccessfully) {
auto cache = CreateCache();
+ const uint32_t client_id = cache->GenerateClientId();
const PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kHigh;
const TargetColorParams target_color_params;
ASSERT_TRUE(target_color_params.color_space.IsValid());
@@ -3986,7 +4450,7 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesFlagsTest,
CreateMatrix(SkSize::Make(0.75f, 0.75f)), PaintImage::kDefaultFrameIndex,
target_color_params);
ImageDecodeCache::TaskResult jpeg_task = cache->GetTaskForImageAndRef(
- jpeg_draw_image, ImageDecodeCache::TracingInfo());
+ client_id, jpeg_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(jpeg_task.need_unref);
ASSERT_TRUE(jpeg_task.task);
// If the hardware decoder claims support for the image (i.e.,
@@ -4016,7 +4480,7 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesFlagsTest,
// After scheduling the task, trying to get another task for the image should
// result in the original task.
ImageDecodeCache::TaskResult jpeg_task_again = cache->GetTaskForImageAndRef(
- jpeg_draw_image, ImageDecodeCache::TracingInfo());
+ client_id, jpeg_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(jpeg_task_again.need_unref);
EXPECT_EQ(jpeg_task_again.task.get(), jpeg_task.task.get());
EXPECT_EQ(advertise_accelerated_decoding_,
@@ -4028,7 +4492,7 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesFlagsTest,
// After running the tasks, trying to get another task for the image should
// result in no task.
- jpeg_task = cache->GetTaskForImageAndRef(jpeg_draw_image,
+ jpeg_task = cache->GetTaskForImageAndRef(client_id, jpeg_draw_image,
ImageDecodeCache::TracingInfo());
EXPECT_TRUE(jpeg_task.need_unref);
EXPECT_FALSE(jpeg_task.task);
@@ -4047,7 +4511,7 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesFlagsTest,
CreateMatrix(SkSize::Make(0.75f, 0.75f)), PaintImage::kDefaultFrameIndex,
target_color_params);
ImageDecodeCache::TaskResult webp_task = cache->GetTaskForImageAndRef(
- webp_draw_image, ImageDecodeCache::TracingInfo());
+ client_id, webp_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(webp_task.need_unref);
ASSERT_TRUE(webp_task.task);
EXPECT_EQ(advertise_accelerated_decoding_,
@@ -4069,7 +4533,7 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesFlagsTest,
testing::Mock::VerifyAndClearExpectations(raster_implementation());
// The image should have been cached.
- webp_task = cache->GetTaskForImageAndRef(webp_draw_image,
+ webp_task = cache->GetTaskForImageAndRef(client_id, webp_draw_image,
ImageDecodeCache::TracingInfo());
EXPECT_TRUE(webp_task.need_unref);
EXPECT_FALSE(webp_task.task);
@@ -4087,7 +4551,7 @@ TEST_P(GpuImageDecodeCacheWithAcceleratedDecodesFlagsTest,
CreateMatrix(SkSize::Make(0.75f, 0.75f)), PaintImage::kDefaultFrameIndex,
target_color_params);
ImageDecodeCache::TaskResult png_task = cache->GetTaskForImageAndRef(
- png_draw_image, ImageDecodeCache::TracingInfo());
+ client_id, png_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(png_task.need_unref);
ASSERT_TRUE(png_task.task);
EXPECT_FALSE(png_task.can_do_hardware_accelerated_decode);
diff --git a/chromium/cc/tiles/image_controller.cc b/chromium/cc/tiles/image_controller.cc
index 44a5ab3c30e..cbfe6c9ec5b 100644
--- a/chromium/cc/tiles/image_controller.cc
+++ b/chromium/cc/tiles/image_controller.cc
@@ -7,6 +7,7 @@
#include <utility>
#include "base/bind.h"
+#include "base/callback_helpers.h"
#include "base/feature_list.h"
#include "base/task/task_traits.h"
#include "base/trace_event/trace_event.h"
@@ -15,16 +16,6 @@
namespace cc {
-namespace {
-
-// When this feature is enabled, StopWorkerTasks() skips waiting synchronously
-// if no task is running.
-BASE_FEATURE(kImageControllerWaitOnlyForRunningTask,
- "ImageControllerWaitOnlyForRunningTask",
- base::FEATURE_DISABLED_BY_DEFAULT);
-
-} // namespace
-
ImageController::ImageDecodeRequestId
ImageController::s_next_image_decode_queue_id_ = 1;
@@ -44,8 +35,7 @@ ImageController::~ImageController() {
// Delete `worker_state_` on `worker_task_runner_` (or elsewhere via the
// callback's destructor if `worker_task_runner_` stopped accepting tasks).
worker_task_runner_->PostTask(
- FROM_HERE, base::BindOnce([](std::unique_ptr<WorkerState>) {},
- std::move(worker_state_)));
+ FROM_HERE, base::DoNothingWithBoundArgs(std::move(worker_state_)));
}
}
@@ -62,12 +52,10 @@ void ImageController::StopWorkerTasks() {
return;
base::AutoLock hold(worker_state_->lock);
- worker_state_->abort_task = true;
- // If a worker task is running (or if the "wait only for running task" feature
- // is disabled), post a task and wait for its completion to "flush" the queue.
- if (!base::FeatureList::IsEnabled(kImageControllerWaitOnlyForRunningTask) ||
- worker_state_->task_state == WorkerTaskState::kRunningTask) {
+ // If a worker task is running, post a task and wait for its completion to
+ // "flush" the queue.
+ if (worker_state_->task_state == WorkerTaskState::kRunningTask) {
base::AutoUnlock release(worker_state_->lock);
CompletionEvent completion_event;
worker_task_runner_->PostTask(
@@ -76,11 +64,6 @@ void ImageController::StopWorkerTasks() {
completion_event.Wait();
}
- DCHECK_EQ(worker_state_->task_state, WorkerTaskState::kNoTask);
-
- // Reset the abort flag so that new tasks can be scheduled.
- worker_state_->abort_task = false;
-
// Now, begin cleanup.
// Unlock all of the locked images (note that this vector would only be
@@ -151,11 +134,14 @@ void ImageController::SetImageDecodeCache(ImageDecodeCache* cache) {
ImageDecodeCache::TracingInfo());
StopWorkerTasks();
image_cache_max_limit_bytes_ = 0u;
+ image_cache_client_id_ = 0u;
}
cache_ = cache;
if (cache_) {
+ DCHECK_EQ(image_cache_client_id_, 0u);
+ image_cache_client_id_ = cache_->GenerateClientId();
image_cache_max_limit_bytes_ = cache_->GetMaximumMemoryLimitBytes();
GenerateTasksForOrphanedRequests();
}
@@ -178,8 +164,8 @@ void ImageController::ConvertImagesToTasks(
// been painted before raster and so do not need raster-time work.
DCHECK(!it->paint_image().IsPaintWorklet());
- ImageDecodeCache::TaskResult result =
- cache_->GetTaskForImageAndRef(*it, tracing_info);
+ ImageDecodeCache::TaskResult result = cache_->GetTaskForImageAndRef(
+ image_cache_client_id_, *it, tracing_info);
*has_at_raster_images |= result.is_at_raster_decode;
ImageType image_type =
@@ -249,7 +235,8 @@ ImageController::ImageDecodeRequestId ImageController::QueueImageDecode(
/*is_at_raster_decode=*/false,
/*can_do_hardware_accelerated_decode=*/false);
if (is_image_lazy)
- result = cache_->GetOutOfRasterDecodeTaskForImageAndRef(draw_image);
+ result = cache_->GetOutOfRasterDecodeTaskForImageAndRef(
+ image_cache_client_id_, draw_image);
// If we don't need to unref this, we don't actually have a task.
DCHECK(result.need_unref || !result.task);
@@ -283,7 +270,7 @@ void ImageController::ProcessNextImageDecodeOnWorkerThread(
worker_state->task_state = WorkerTaskState::kRunningTask;
// If we don't have any work, abort.
- if (worker_state->image_decode_queue.empty() || worker_state->abort_task) {
+ if (worker_state->image_decode_queue.empty()) {
worker_state->task_state = WorkerTaskState::kNoTask;
return;
}
@@ -389,7 +376,8 @@ void ImageController::GenerateTasksForOrphanedRequests() {
if (request.draw_image.paint_image().IsLazyGenerated()) {
// Get the task for this decode.
ImageDecodeCache::TaskResult result =
- cache_->GetOutOfRasterDecodeTaskForImageAndRef(request.draw_image);
+ cache_->GetOutOfRasterDecodeTaskForImageAndRef(image_cache_client_id_,
+ request.draw_image);
request.need_unref = result.need_unref;
request.task = result.task;
}
diff --git a/chromium/cc/tiles/image_controller.h b/chromium/cc/tiles/image_controller.h
index 96c9450a147..d10ca932e3e 100644
--- a/chromium/cc/tiles/image_controller.h
+++ b/chromium/cc/tiles/image_controller.h
@@ -127,7 +127,6 @@ class CC_EXPORT ImageController {
std::map<ImageDecodeRequestId, ImageDecodeRequest>
requests_needing_completion GUARDED_BY(lock);
WorkerTaskState task_state GUARDED_BY(lock) = WorkerTaskState::kNoTask;
- bool abort_task GUARDED_BY(lock) = false;
const scoped_refptr<base::SequencedTaskRunner> origin_task_runner;
const base::WeakPtr<ImageController> weak_ptr;
@@ -159,6 +158,10 @@ class CC_EXPORT ImageController {
// from generating new tasks, this vector should be empty.
std::vector<ImageDecodeRequest> orphaned_decode_requests_;
+ // The id generated by ImageDecodeCache instance to identify this client
+ // instance when requesting image tasks.
+ ImageDecodeCache::ClientId image_cache_client_id_ = 0;
+
base::WeakPtrFactory<ImageController> weak_ptr_factory_{this};
};
diff --git a/chromium/cc/tiles/image_controller_unittest.cc b/chromium/cc/tiles/image_controller_unittest.cc
index deb3b6d3e6d..b5ceb5a4f5c 100644
--- a/chromium/cc/tiles/image_controller_unittest.cc
+++ b/chromium/cc/tiles/image_controller_unittest.cc
@@ -11,8 +11,8 @@
#include "base/callback_helpers.h"
#include "base/run_loop.h"
#include "base/synchronization/condition_variable.h"
+#include "base/task/sequenced_task_runner.h"
#include "base/task/thread_pool.h"
-#include "base/threading/sequenced_task_runner_handle.h"
#include "base/threading/simple_thread.h"
#include "base/threading/thread_checker_impl.h"
#include "base/threading/thread_restrictions.h"
@@ -33,7 +33,8 @@ class TestableCache : public StubDecodeCache {
public:
~TestableCache() override { EXPECT_EQ(number_of_refs_, 0); }
- TaskResult GetTaskForImageAndRef(const DrawImage& image,
+ TaskResult GetTaskForImageAndRef(uint32_t client_id,
+ const DrawImage& image,
const TracingInfo& tracing_info) override {
// Return false for large images to mimic "won't fit in memory"
// behavior.
@@ -52,8 +53,9 @@ class TestableCache : public StubDecodeCache {
/*can_do_hardware_accelerated_decode=*/false);
}
TaskResult GetOutOfRasterDecodeTaskForImageAndRef(
+ uint32_t client_id,
const DrawImage& image) override {
- return GetTaskForImageAndRef(image, TracingInfo());
+ return GetTaskForImageAndRef(client_id, image, TracingInfo());
}
void UnrefImage(const DrawImage& image) override {
@@ -188,7 +190,8 @@ DrawImage CreateBitmapDrawImage(gfx::Size size) {
class ImageControllerTest : public testing::Test {
public:
- ImageControllerTest() : task_runner_(base::SequencedTaskRunnerHandle::Get()) {
+ ImageControllerTest()
+ : task_runner_(base::SequencedTaskRunner::GetCurrentDefault()) {
image_ = CreateDiscardableDrawImage(gfx::Size(1, 1));
}
~ImageControllerTest() override = default;
@@ -197,7 +200,6 @@ class ImageControllerTest : public testing::Test {
controller_ = std::make_unique<ImageController>(
task_runner_,
base::ThreadPool::CreateSequencedTaskRunner(base::TaskTraits()));
- cache_ = TestableCache();
controller_->SetImageDecodeCache(&cache_);
}
diff --git a/chromium/cc/tiles/image_decode_cache.cc b/chromium/cc/tiles/image_decode_cache.cc
index e34e395931a..6448980de26 100644
--- a/chromium/cc/tiles/image_decode_cache.cc
+++ b/chromium/cc/tiles/image_decode_cache.cc
@@ -4,10 +4,16 @@
#include "cc/tiles/image_decode_cache.h"
+#include <limits>
+#include <utility>
+
+#include "base/check_op.h"
#include "cc/raster/tile_task.h"
namespace cc {
+const ImageDecodeCache::ClientId ImageDecodeCache::kDefaultClientId = 1;
+
ImageDecodeCache::TaskResult::TaskResult(
bool need_unref,
bool is_at_raster_decode,
@@ -30,4 +36,9 @@ ImageDecodeCache::TaskResult::TaskResult(const TaskResult& result) = default;
ImageDecodeCache::TaskResult::~TaskResult() = default;
+ImageDecodeCache::ClientId ImageDecodeCache::GenerateClientId() {
+ DCHECK_LT(next_available_id_, std::numeric_limits<uint32_t>::max());
+ return ++next_available_id_;
+}
+
} // namespace cc
diff --git a/chromium/cc/tiles/image_decode_cache.h b/chromium/cc/tiles/image_decode_cache.h
index 0b5aee55e3a..82fdd5436cf 100644
--- a/chromium/cc/tiles/image_decode_cache.h
+++ b/chromium/cc/tiles/image_decode_cache.h
@@ -5,6 +5,8 @@
#ifndef CC_TILES_IMAGE_DECODE_CACHE_H_
#define CC_TILES_IMAGE_DECODE_CACHE_H_
+#include <atomic>
+
#include "base/memory/ref_counted.h"
#include "base/notreached.h"
#include "cc/base/devtools_instrumentation.h"
@@ -39,6 +41,9 @@ class CC_EXPORT ImageDecodeCache {
public:
enum class TaskType { kInRaster, kOutOfRaster };
+ // See GenerateClientId.
+ using ClientId = uint32_t;
+
// This information should be used strictly in tracing, UMA, and any other
// reporting systems.
struct TracingInfo {
@@ -79,8 +84,6 @@ class CC_EXPORT ImageDecodeCache {
using ScopedImageType =
devtools_instrumentation::ScopedImageDecodeTask::ImageType;
switch (image_type) {
- case ImageType::kJXL:
- return ScopedImageType::kJxl;
case ImageType::kAVIF:
return ScopedImageType::kAvif;
case ImageType::kBMP:
@@ -118,18 +121,27 @@ class CC_EXPORT ImageDecodeCache {
};
// Fill in an TileTask which will decode the given image when run. In
// case the image is already cached, fills in nullptr. Returns true if the
- // image needs to be unreffed when the caller is finished with it.
+ // image needs to be unreffed when the caller is finished with it. |client_id|
+ // helps to identify a client that requests a task if the cache is shared
+ // between multiple clients. Returns the same task iff an image task for the
+ // the |client_id| already exists. The way multiple image tasks for the same
+ // image from different clients are managed is an implementation detail of the
+ // cache instance. The clients shouldn't worry about the ordering between
+ // these tasks. The |client_id| is an id that must be generated by calling
+ // |GenerateClientId| to avoid any collisions.
//
// This is called by the tile manager (on the compositor thread) when creating
// a raster task.
- virtual TaskResult GetTaskForImageAndRef(const DrawImage& image,
+ virtual TaskResult GetTaskForImageAndRef(ClientId client_id,
+ const DrawImage& image,
const TracingInfo& tracing_info) = 0;
- // Similar to GetTaskForImageAndRef, except that it returns tasks that are not
- // meant to be run as part of raster. That is, this is part of a predecode
- // API. Note that this should only return a task responsible for decoding (and
- // not uploading), since it will be run on a worker thread which may not have
- // the right GPU context for upload.
+ // Similar to GetTaskForImageAndRef (including the |client_id|), except that
+ // it returns tasks that are not meant to be run as part of raster. That is,
+ // this is part of a predecode API. Note that this should only return a task
+ // responsible for decoding (and not uploading), since it will be run on a
+ // worker thread which may not have the right GPU context for upload.
virtual TaskResult GetOutOfRasterDecodeTaskForImageAndRef(
+ ClientId client_id,
const DrawImage& image) = 0;
// Unrefs an image. When the tile is finished, this should be called for every
@@ -156,9 +168,11 @@ class CC_EXPORT ImageDecodeCache {
virtual void ReduceCacheUsage() = 0;
// This function informs the cache that we are hidden and should not be
- // retaining cached resources longer than needed.
+ // retaining cached resources longer than needed. If |context_lock_acquired|
+ // is true, the caller has already acquired the context lock.
virtual void SetShouldAggressivelyFreeResources(
- bool aggressively_free_resources) = 0;
+ bool aggressively_free_resources,
+ bool context_lock_acquired) = 0;
// Clears all elements from the cache.
virtual void ClearCache() = 0;
@@ -177,6 +191,20 @@ class CC_EXPORT ImageDecodeCache {
// Should be called periodically to record statistics about cache use and
// performance.
virtual void RecordStats() = 0;
+
+ // Returns a unique id that can be used to request upload/decode tasks for
+ // images' uploading/decoding. This can be optionally used by ImageDecodeCache
+ // instance to manage decode/upload tasks. Implementations may override this
+ // to add additional logic. However, they should eventually use this to have a
+ // new client id generated.
+ virtual ClientId GenerateClientId();
+
+ protected:
+ static const ClientId kDefaultClientId;
+
+ private:
+ // A next available id for a client identification.
+ std::atomic<ClientId> next_available_id_ = 0;
};
} // namespace cc
diff --git a/chromium/cc/tiles/picture_layer_tiling_set.cc b/chromium/cc/tiles/picture_layer_tiling_set.cc
index f4c26d69a57..7154d91ad38 100644
--- a/chromium/cc/tiles/picture_layer_tiling_set.cc
+++ b/chromium/cc/tiles/picture_layer_tiling_set.cc
@@ -301,10 +301,8 @@ PictureLayerTiling* PictureLayerTilingSet::AddTiling(
}
int PictureLayerTilingSet::NumHighResTilings() const {
- return std::count_if(tilings_.begin(), tilings_.end(),
- [](const std::unique_ptr<PictureLayerTiling>& tiling) {
- return tiling->resolution() == HIGH_RESOLUTION;
- });
+ return base::ranges::count(tilings_, HIGH_RESOLUTION,
+ &PictureLayerTiling::resolution);
}
PictureLayerTiling* PictureLayerTilingSet::FindTilingWithScaleKey(
diff --git a/chromium/cc/tiles/picture_layer_tiling_set_unittest.cc b/chromium/cc/tiles/picture_layer_tiling_set_unittest.cc
index f35bc39c165..46214615e69 100644
--- a/chromium/cc/tiles/picture_layer_tiling_set_unittest.cc
+++ b/chromium/cc/tiles/picture_layer_tiling_set_unittest.cc
@@ -244,7 +244,7 @@ class PictureLayerTilingSetTestWithResources : public testing::Test {
float expected_scale) {
scoped_refptr<viz::TestContextProvider> context_provider =
viz::TestContextProvider::Create();
- ASSERT_EQ(context_provider->BindToCurrentThread(),
+ ASSERT_EQ(context_provider->BindToCurrentSequence(),
gpu::ContextResult::kSuccess);
std::unique_ptr<viz::ClientResourceProvider> resource_provider =
std::make_unique<viz::ClientResourceProvider>();
diff --git a/chromium/cc/tiles/raster_tile_priority_queue_all.cc b/chromium/cc/tiles/raster_tile_priority_queue_all.cc
index 020a4e34061..8e93fe663cd 100644
--- a/chromium/cc/tiles/raster_tile_priority_queue_all.cc
+++ b/chromium/cc/tiles/raster_tile_priority_queue_all.cc
@@ -4,7 +4,10 @@
#include "cc/tiles/raster_tile_priority_queue_all.h"
+#include <memory>
+
#include "base/notreached.h"
+#include "cc/base/features.h"
#include "cc/tiles/tiling_set_raster_queue_all.h"
namespace cc {
@@ -83,7 +86,9 @@ void CreateTilingSetRasterQueues(
} // namespace
-RasterTilePriorityQueueAll::RasterTilePriorityQueueAll() = default;
+RasterTilePriorityQueueAll::RasterTilePriorityQueueAll()
+ : fix_raster_tile_priority_queue_for_smoothness_(
+ base::FeatureList::IsEnabled(features::kRasterTilePriorityQueue)) {}
RasterTilePriorityQueueAll::~RasterTilePriorityQueueAll() = default;
@@ -149,39 +154,69 @@ RasterTilePriorityQueueAll::GetNextQueues() const {
const TilePriority& active_priority = active_tile.priority();
const TilePriority& pending_priority = pending_tile.priority();
- switch (tree_priority_) {
- case SMOOTHNESS_TAKES_PRIORITY: {
- // If we're down to soon bin tiles on the active tree and there
- // is a pending tree, process the now tiles in the pending tree to allow
- // tiles required for activation to be initialized when memory policy only
- // allows prepaint. The soon/eventually bin tiles on the active tree are
- // lowest priority since that work is likely to be thrown away when we
- // activate.
- if (active_priority.priority_bin >= TilePriority::SOON &&
- pending_priority.priority_bin == TilePriority::NOW) {
+ if (fix_raster_tile_priority_queue_for_smoothness_) {
+ // Priority rule:
+ // - SMOOTHNESS_TAKES_PRIORITY: Active NOW before pending NOW; same as all
+ // mode for other bins.
+ // - NEW_CONTENT_TAKES_PRIORITY: Pending NOW before active NOW; same as all
+ // mode for other bins.
+ // - SAME_PRIORITY_FOR_BOTH_TREES (All): Calling IsHigherPriorityThan().
+ // Notes: This priority rule should not break
+ // TileManager::TilePriorityViolatesMemoryPolicy().
+
+ // Prioritize the highest priority_bin NOW out of either one of active or
+ // pending for smoothness and new content modes.
+ if (pending_priority.priority_bin == TilePriority::NOW &&
+ active_priority.priority_bin == TilePriority::NOW) {
+ if (tree_priority_ == SMOOTHNESS_TAKES_PRIORITY)
+ return active_queues_;
+ if (tree_priority_ == NEW_CONTENT_TAKES_PRIORITY)
return pending_queues_;
- }
- return active_queues_;
}
- case NEW_CONTENT_TAKES_PRIORITY: {
- // If we're down to soon bin tiles on the pending tree, process the
- // active tree to allow tiles required for activation to be initialized
- // when memory policy only allows prepaint. Note that active required for
- // activation tiles might come from either now or soon bins.
- if (pending_priority.priority_bin >= TilePriority::SOON &&
- active_priority.priority_bin <= TilePriority::SOON) {
+
+ // Then, use the IsHigherPriorityThan condition for
+ // SAME_PRIORITY_FOR_BOTH_TREES and the rest of the priority bins.
+ // TODO(crbug.com/1380831): For SAME_PRIORITY_FOR_BOTH_TREES mode and both
+ // being NOW, should we give the priority to Active NOW instead?
+ if (active_priority.IsHigherPriorityThan(pending_priority))
+ return active_queues_;
+ return pending_queues_;
+
+ } else {
+ switch (tree_priority_) {
+ case SMOOTHNESS_TAKES_PRIORITY: {
+ // If we're down to soon bin tiles on the active tree and there
+ // is a pending tree, process the now tiles in the pending tree to allow
+ // tiles required for activation to be initialized when memory policy
+ // only allows prepaint. The soon/eventually bin tiles on the active
+ // tree are lowest priority since that work is likely to be thrown away
+ // when we activate.
+ if (active_priority.priority_bin >= TilePriority::SOON &&
+ pending_priority.priority_bin == TilePriority::NOW) {
+ return pending_queues_;
+ }
return active_queues_;
}
- return pending_queues_;
- }
- case SAME_PRIORITY_FOR_BOTH_TREES: {
- if (active_priority.IsHigherPriorityThan(pending_priority))
+ case NEW_CONTENT_TAKES_PRIORITY: {
+ // If we're down to soon bin tiles on the pending tree, process the
+ // active tree to allow tiles required for activation to be initialized
+ // when memory policy only allows prepaint. Note that active required
+ // for activation tiles might come from either now or soon bins.
+ if (pending_priority.priority_bin >= TilePriority::SOON &&
+ active_priority.priority_bin <= TilePriority::SOON) {
+ return active_queues_;
+ }
+ return pending_queues_;
+ }
+ case SAME_PRIORITY_FOR_BOTH_TREES: {
+ if (active_priority.IsHigherPriorityThan(pending_priority))
+ return active_queues_;
+ return pending_queues_;
+ }
+ default:
+ NOTREACHED();
return active_queues_;
- return pending_queues_;
}
- default:
- NOTREACHED();
- return active_queues_;
}
}
diff --git a/chromium/cc/tiles/raster_tile_priority_queue_all.h b/chromium/cc/tiles/raster_tile_priority_queue_all.h
index 40f93abb0f2..4be8edd45f5 100644
--- a/chromium/cc/tiles/raster_tile_priority_queue_all.h
+++ b/chromium/cc/tiles/raster_tile_priority_queue_all.h
@@ -5,6 +5,7 @@
#ifndef CC_TILES_RASTER_TILE_PRIORITY_QUEUE_ALL_H_
#define CC_TILES_RASTER_TILE_PRIORITY_QUEUE_ALL_H_
+#include <memory>
#include <set>
#include <utility>
#include <vector>
@@ -44,6 +45,7 @@ class CC_EXPORT RasterTilePriorityQueueAll : public RasterTilePriorityQueue {
std::vector<std::unique_ptr<TilingSetRasterQueueAll>> active_queues_;
std::vector<std::unique_ptr<TilingSetRasterQueueAll>> pending_queues_;
TreePriority tree_priority_;
+ const bool fix_raster_tile_priority_queue_for_smoothness_;
};
} // namespace cc
diff --git a/chromium/cc/tiles/software_image_decode_cache.cc b/chromium/cc/tiles/software_image_decode_cache.cc
index 8188595e8ea..2aaaf24701b 100644
--- a/chromium/cc/tiles/software_image_decode_cache.cc
+++ b/chromium/cc/tiles/software_image_decode_cache.cc
@@ -14,11 +14,12 @@
#include "base/debug/stack_trace.h"
#include "base/format_macros.h"
#include "base/memory/raw_ptr.h"
+#include "base/memory/raw_ref.h"
#include "base/metrics/histogram_macros.h"
#include "base/numerics/ostream_operators.h"
#include "base/ranges/algorithm.h"
#include "base/strings/stringprintf.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/task/single_thread_task_runner.h"
#include "base/trace_event/memory_dump_manager.h"
#include "cc/base/devtools_instrumentation.h"
#include "cc/base/features.h"
@@ -48,14 +49,14 @@ class AutoRemoveKeyFromTaskMap {
SoftwareImageDecodeCache::CacheKeyHash>* task_map,
const SoftwareImageDecodeCache::CacheKey& key)
: task_map_(task_map), key_(key) {}
- ~AutoRemoveKeyFromTaskMap() { task_map_->erase(key_); }
+ ~AutoRemoveKeyFromTaskMap() { task_map_->erase(*key_); }
private:
raw_ptr<std::unordered_map<SoftwareImageDecodeCache::CacheKey,
scoped_refptr<TileTask>,
SoftwareImageDecodeCache::CacheKeyHash>>
task_map_;
- const SoftwareImageDecodeCache::CacheKey& key_;
+ const raw_ref<const SoftwareImageDecodeCache::CacheKey> key_;
};
class SoftwareImageDecodeTaskImpl : public TileTask {
@@ -119,7 +120,7 @@ class SoftwareImageDecodeTaskImpl : public TileTask {
~SoftwareImageDecodeTaskImpl() override = default;
private:
- raw_ptr<SoftwareImageDecodeCache> cache_;
+ raw_ptr<SoftwareImageDecodeCache, DanglingUntriaged> cache_;
SoftwareImageDecodeCache::CacheKey image_key_;
PaintImage paint_image_;
SoftwareImageDecodeCache::DecodeTaskType task_type_;
@@ -163,10 +164,10 @@ SoftwareImageDecodeCache::SoftwareImageDecodeCache(
DCHECK_NE(generator_client_id_, PaintImage::kDefaultGeneratorClientId);
// In certain cases, ThreadTaskRunnerHandle isn't set (Android Webview).
// Don't register a dump provider in these cases.
- if (base::ThreadTaskRunnerHandle::IsSet()) {
+ if (base::SingleThreadTaskRunner::HasCurrentDefault()) {
base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
this, "cc::SoftwareImageDecodeCache",
- base::ThreadTaskRunnerHandle::Get());
+ base::SingleThreadTaskRunner::GetCurrentDefault());
}
}
@@ -177,16 +178,22 @@ SoftwareImageDecodeCache::~SoftwareImageDecodeCache() {
}
ImageDecodeCache::TaskResult SoftwareImageDecodeCache::GetTaskForImageAndRef(
+ ClientId client_id,
const DrawImage& image,
const TracingInfo& tracing_info) {
DCHECK_EQ(tracing_info.task_type, TaskType::kInRaster);
+ DCHECK_EQ(client_id, ImageDecodeCache::kDefaultClientId)
+ << "SoftwareImageDecodeCache cannot be shared between multiple clients.";
return GetTaskForImageAndRefInternal(image, tracing_info,
DecodeTaskType::USE_IN_RASTER_TASKS);
}
ImageDecodeCache::TaskResult
SoftwareImageDecodeCache::GetOutOfRasterDecodeTaskForImageAndRef(
+ ClientId client_id,
const DrawImage& image) {
+ DCHECK_EQ(client_id, ImageDecodeCache::kDefaultClientId)
+ << "SoftwareImageDecodeCache cannot be shared between multiple clients.";
return GetTaskForImageAndRefInternal(
image, TracingInfo(0, TilePriority::NOW, TaskType::kOutOfRaster),
DecodeTaskType::USE_OUT_OF_RASTER_TASKS);
@@ -545,6 +552,15 @@ bool SoftwareImageDecodeCache::UseCacheForDrawImage(
return false;
}
+ImageDecodeCache::ClientId SoftwareImageDecodeCache::GenerateClientId() {
+ ClientId next_client_id = ImageDecodeCache::GenerateClientId();
+ // The software decode cache cannot be shared between multiple clients. Thus,
+ // this DCHECK helps us to verify the software cache has only a single client
+ // that generated a client id for itself only oce.
+ DCHECK_EQ(ImageDecodeCache::kDefaultClientId, next_client_id);
+ return next_client_id;
+}
+
DecodedDrawImage SoftwareImageDecodeCache::GetDecodedImageForDraw(
const DrawImage& draw_image) {
DCHECK(UseCacheForDrawImage(draw_image));
diff --git a/chromium/cc/tiles/software_image_decode_cache.h b/chromium/cc/tiles/software_image_decode_cache.h
index 68c8b0d35ad..9161808fcb6 100644
--- a/chromium/cc/tiles/software_image_decode_cache.h
+++ b/chromium/cc/tiles/software_image_decode_cache.h
@@ -12,7 +12,6 @@
#include <vector>
#include "base/containers/lru_cache.h"
-#include "base/memory/ref_counted.h"
#include "base/numerics/safe_math.h"
#include "base/thread_annotations.h"
#include "base/trace_event/memory_dump_provider.h"
@@ -42,9 +41,13 @@ class CC_EXPORT SoftwareImageDecodeCache
~SoftwareImageDecodeCache() override;
// ImageDecodeCache overrides.
- TaskResult GetTaskForImageAndRef(const DrawImage& image,
+ // |client_id| is not used by the SoftwareImageDecodeCache for both of these
+ // tasks.
+ TaskResult GetTaskForImageAndRef(ClientId client_id,
+ const DrawImage& image,
const TracingInfo& tracing_info) override;
TaskResult GetOutOfRasterDecodeTaskForImageAndRef(
+ ClientId client_id,
const DrawImage& image) override;
void UnrefImage(const DrawImage& image) override;
DecodedDrawImage GetDecodedImageForDraw(const DrawImage& image) override;
@@ -52,12 +55,14 @@ class CC_EXPORT SoftwareImageDecodeCache
const DecodedDrawImage& decoded_image) override;
void ReduceCacheUsage() override;
// Software doesn't keep outstanding images pinned, so this is a no-op.
- void SetShouldAggressivelyFreeResources(
- bool aggressively_free_resources) override {}
+ void SetShouldAggressivelyFreeResources(bool aggressively_free_resources,
+ bool context_lock_acquired) override {
+ }
void ClearCache() override;
size_t GetMaximumMemoryLimitBytes() const override;
bool UseCacheForDrawImage(const DrawImage& image) const override;
void RecordStats() override {}
+ ClientId GenerateClientId() override;
// Decode the given image and store it in the cache. This is only called by an
// image decode task from a worker thread.
diff --git a/chromium/cc/tiles/software_image_decode_cache_unittest.cc b/chromium/cc/tiles/software_image_decode_cache_unittest.cc
index 0511d0ed841..319835327d0 100644
--- a/chromium/cc/tiles/software_image_decode_cache_unittest.cc
+++ b/chromium/cc/tiles/software_image_decode_cache_unittest.cc
@@ -54,7 +54,17 @@ PaintImage CreatePaintImage(int width,
target_color_params.color_space.ToSkColorSpace());
}
-TEST(SoftwareImageDecodeCacheTest, ImageKeyNoneQuality) {
+class SoftwareImageDecodeCacheTest : public testing::Test {
+ public:
+ SoftwareImageDecodeCacheTest()
+ : cache_client_id_(cache_.GenerateClientId()) {}
+
+ protected:
+ TestSoftwareImageDecodeCache cache_;
+ const ImageDecodeCache::ClientId cache_client_id_;
+};
+
+TEST_F(SoftwareImageDecodeCacheTest, ImageKeyNoneQuality) {
PaintImage paint_image = CreatePaintImage(100, 100);
bool is_decomposable = true;
DrawImage draw_image(
@@ -76,8 +86,8 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyNoneQuality) {
EXPECT_EQ(100u * 100u * 4u, key.locked_bytes());
}
-TEST(SoftwareImageDecodeCacheTest,
- ImageKeyLowQualityIncreasedToMediumIfDownscale) {
+TEST_F(SoftwareImageDecodeCacheTest,
+ ImageKeyLowQualityIncreasedToMediumIfDownscale) {
PaintImage paint_image = CreatePaintImage(100, 100);
bool is_decomposable = true;
DrawImage draw_image(
@@ -96,7 +106,8 @@ TEST(SoftwareImageDecodeCacheTest,
EXPECT_EQ(50u * 50u * 4u, key.locked_bytes());
}
-TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityDropsToLowIfMipLevel0) {
+TEST_F(SoftwareImageDecodeCacheTest,
+ ImageKeyMediumQualityDropsToLowIfMipLevel0) {
PaintImage paint_image = CreatePaintImage(100, 100);
bool is_decomposable = true;
DrawImage draw_image(
@@ -116,7 +127,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityDropsToLowIfMipLevel0) {
EXPECT_EQ(100u * 100u * 4u, key.locked_bytes());
}
-TEST(SoftwareImageDecodeCacheTest, LowUnscalableFormatStaysLow) {
+TEST_F(SoftwareImageDecodeCacheTest, LowUnscalableFormatStaysLow) {
PaintImage paint_image = CreatePaintImage(100, 100);
bool is_decomposable = true;
DrawImage draw_image(
@@ -136,7 +147,7 @@ TEST(SoftwareImageDecodeCacheTest, LowUnscalableFormatStaysLow) {
EXPECT_EQ(100u * 100u * 4u, key.locked_bytes());
}
-TEST(SoftwareImageDecodeCacheTest, HighUnscalableFormatBecomesLow) {
+TEST_F(SoftwareImageDecodeCacheTest, HighUnscalableFormatBecomesLow) {
PaintImage paint_image = CreatePaintImage(100, 100);
bool is_decomposable = true;
DrawImage draw_image(
@@ -156,7 +167,7 @@ TEST(SoftwareImageDecodeCacheTest, HighUnscalableFormatBecomesLow) {
EXPECT_EQ(100u * 100u * 4u, key.locked_bytes());
}
-TEST(SoftwareImageDecodeCacheTest, ImageKeyLowQualityKeptLowIfUpscale) {
+TEST_F(SoftwareImageDecodeCacheTest, ImageKeyLowQualityKeptLowIfUpscale) {
PaintImage paint_image = CreatePaintImage(100, 100);
bool is_decomposable = true;
DrawImage draw_image(
@@ -176,7 +187,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyLowQualityKeptLowIfUpscale) {
EXPECT_EQ(100u * 100u * 4u, key.locked_bytes());
}
-TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQuality) {
+TEST_F(SoftwareImageDecodeCacheTest, ImageKeyMediumQuality) {
PaintImage paint_image = CreatePaintImage(100, 100);
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kMedium;
@@ -196,7 +207,8 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQuality) {
EXPECT_EQ(50u * 50u * 4u, key.locked_bytes());
}
-TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityDropToLowIfEnlarging) {
+TEST_F(SoftwareImageDecodeCacheTest,
+ ImageKeyMediumQualityDropToLowIfEnlarging) {
PaintImage paint_image = CreatePaintImage(100, 100);
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kMedium;
@@ -217,7 +229,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityDropToLowIfEnlarging) {
EXPECT_EQ(100u * 100u * 4u, key.locked_bytes());
}
-TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityDropToLowIfIdentity) {
+TEST_F(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityDropToLowIfIdentity) {
PaintImage paint_image = CreatePaintImage(100, 100);
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kMedium;
@@ -238,8 +250,8 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityDropToLowIfIdentity) {
EXPECT_EQ(100u * 100u * 4u, key.locked_bytes());
}
-TEST(SoftwareImageDecodeCacheTest,
- ImageKeyMediumQualityDropToLowIfNearlyIdentity) {
+TEST_F(SoftwareImageDecodeCacheTest,
+ ImageKeyMediumQualityDropToLowIfNearlyIdentity) {
PaintImage paint_image = CreatePaintImage(100, 100);
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kMedium;
@@ -260,8 +272,8 @@ TEST(SoftwareImageDecodeCacheTest,
EXPECT_EQ(100u * 100u * 4u, key.locked_bytes());
}
-TEST(SoftwareImageDecodeCacheTest,
- ImageKeyMediumQualityDropToLowIfNearlyIdentity2) {
+TEST_F(SoftwareImageDecodeCacheTest,
+ ImageKeyMediumQualityDropToLowIfNearlyIdentity2) {
PaintImage paint_image = CreatePaintImage(100, 100);
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kMedium;
@@ -282,8 +294,8 @@ TEST(SoftwareImageDecodeCacheTest,
EXPECT_EQ(100u * 100u * 4u, key.locked_bytes());
}
-TEST(SoftwareImageDecodeCacheTest,
- ImageKeyMediumQualityDropToLowIfNotDecomposable) {
+TEST_F(SoftwareImageDecodeCacheTest,
+ ImageKeyMediumQualityDropToLowIfNotDecomposable) {
PaintImage paint_image = CreatePaintImage(100, 100);
bool is_decomposable = false;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kMedium;
@@ -305,7 +317,7 @@ TEST(SoftwareImageDecodeCacheTest,
EXPECT_EQ(100u * 100u * 4u, key.locked_bytes());
}
-TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt1_5Scale) {
+TEST_F(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt1_5Scale) {
PaintImage paint_image = CreatePaintImage(500, 200);
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kMedium;
@@ -326,7 +338,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt1_5Scale) {
EXPECT_EQ(500u * 200u * 4u, key.locked_bytes());
}
-TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt1_0cale) {
+TEST_F(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt1_0cale) {
PaintImage paint_image = CreatePaintImage(500, 200);
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kMedium;
@@ -347,7 +359,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt1_0cale) {
EXPECT_EQ(500u * 200u * 4u, key.locked_bytes());
}
-TEST(SoftwareImageDecodeCacheTest, ImageKeyLowQualityAt0_75Scale) {
+TEST_F(SoftwareImageDecodeCacheTest, ImageKeyLowQualityAt0_75Scale) {
PaintImage paint_image = CreatePaintImage(500, 200);
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kMedium;
@@ -368,7 +380,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyLowQualityAt0_75Scale) {
EXPECT_EQ(500u * 200u * 4u, key.locked_bytes());
}
-TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt0_5Scale) {
+TEST_F(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt0_5Scale) {
PaintImage paint_image = CreatePaintImage(500, 200);
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kMedium;
@@ -388,7 +400,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt0_5Scale) {
EXPECT_EQ(250u * 100u * 4u, key.locked_bytes());
}
-TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt0_49Scale) {
+TEST_F(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt0_49Scale) {
PaintImage paint_image = CreatePaintImage(500, 200);
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kMedium;
@@ -408,7 +420,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt0_49Scale) {
EXPECT_EQ(250u * 100u * 4u, key.locked_bytes());
}
-TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt0_1Scale) {
+TEST_F(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt0_1Scale) {
PaintImage paint_image = CreatePaintImage(500, 200);
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kMedium;
@@ -428,7 +440,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt0_1Scale) {
EXPECT_EQ(63u * 25u * 4u, key.locked_bytes());
}
-TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt0_01Scale) {
+TEST_F(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt0_01Scale) {
PaintImage paint_image = CreatePaintImage(500, 200);
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kMedium;
@@ -448,8 +460,8 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt0_01Scale) {
EXPECT_EQ(8u * 4u * 4u, key.locked_bytes());
}
-TEST(SoftwareImageDecodeCacheTest,
- ImageKeyFullDowscalesDropsHighQualityToMedium) {
+TEST_F(SoftwareImageDecodeCacheTest,
+ ImageKeyFullDowscalesDropsHighQualityToMedium) {
PaintImage paint_image = CreatePaintImage(100, 100);
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kHigh;
@@ -469,7 +481,7 @@ TEST(SoftwareImageDecodeCacheTest,
EXPECT_EQ(50u * 50u * 4u, key.locked_bytes());
}
-TEST(SoftwareImageDecodeCacheTest, ImageKeyUpscaleIsLowQuality) {
+TEST_F(SoftwareImageDecodeCacheTest, ImageKeyUpscaleIsLowQuality) {
PaintImage paint_image = CreatePaintImage(100, 100);
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kHigh;
@@ -490,7 +502,8 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyUpscaleIsLowQuality) {
EXPECT_EQ(100u * 100u * 4u, key.locked_bytes());
}
-TEST(SoftwareImageDecodeCacheTest, ImageKeyHighQualityDropToMediumIfTooLarge) {
+TEST_F(SoftwareImageDecodeCacheTest,
+ ImageKeyHighQualityDropToMediumIfTooLarge) {
// Just over 64MB when scaled.
PaintImage paint_image = CreatePaintImage(4555, 2048);
bool is_decomposable = true;
@@ -513,8 +526,8 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyHighQualityDropToMediumIfTooLarge) {
EXPECT_EQ(2278u * 1024u * 4u, key.locked_bytes());
}
-TEST(SoftwareImageDecodeCacheTest,
- ImageKeyHighQualityDropToLowIfNotDecomposable) {
+TEST_F(SoftwareImageDecodeCacheTest,
+ ImageKeyHighQualityDropToLowIfNotDecomposable) {
PaintImage paint_image = CreatePaintImage(100, 100);
bool is_decomposable = false;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kHigh;
@@ -535,7 +548,7 @@ TEST(SoftwareImageDecodeCacheTest,
EXPECT_EQ(100u * 100u * 4u, key.locked_bytes());
}
-TEST(SoftwareImageDecodeCacheTest, ImageKeyHighQualityDropToLowIfIdentity) {
+TEST_F(SoftwareImageDecodeCacheTest, ImageKeyHighQualityDropToLowIfIdentity) {
PaintImage paint_image = CreatePaintImage(100, 100);
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kHigh;
@@ -556,8 +569,8 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyHighQualityDropToLowIfIdentity) {
EXPECT_EQ(100u * 100u * 4u, key.locked_bytes());
}
-TEST(SoftwareImageDecodeCacheTest,
- ImageKeyHighQualityDropToLowIfNearlyIdentity) {
+TEST_F(SoftwareImageDecodeCacheTest,
+ ImageKeyHighQualityDropToLowIfNearlyIdentity) {
PaintImage paint_image = CreatePaintImage(100, 100);
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kHigh;
@@ -578,8 +591,8 @@ TEST(SoftwareImageDecodeCacheTest,
EXPECT_EQ(100u * 100u * 4u, key.locked_bytes());
}
-TEST(SoftwareImageDecodeCacheTest,
- ImageKeyHighQualityDropToLowIfNearlyIdentity2) {
+TEST_F(SoftwareImageDecodeCacheTest,
+ ImageKeyHighQualityDropToLowIfNearlyIdentity2) {
PaintImage paint_image = CreatePaintImage(100, 100);
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kHigh;
@@ -600,7 +613,7 @@ TEST(SoftwareImageDecodeCacheTest,
EXPECT_EQ(100u * 100u * 4u, key.locked_bytes());
}
-TEST(SoftwareImageDecodeCacheTest, ImageKeyDownscaleMipLevelWithRounding) {
+TEST_F(SoftwareImageDecodeCacheTest, ImageKeyDownscaleMipLevelWithRounding) {
// Tests that, when using a non-zero mip level, the final target size (which
// is the size of the chosen mip level) is as expected if rounding is
// required.
@@ -636,7 +649,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyDownscaleMipLevelWithRounding) {
EXPECT_EQ(25u * 16u * 4u, key.locked_bytes());
}
-TEST(SoftwareImageDecodeCacheTest, OriginalDecodesAreEqual) {
+TEST_F(SoftwareImageDecodeCacheTest, OriginalDecodesAreEqual) {
PaintImage paint_image = CreatePaintImage(100, 100);
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kNone;
@@ -674,7 +687,7 @@ TEST(SoftwareImageDecodeCacheTest, OriginalDecodesAreEqual) {
EXPECT_TRUE(key == another_key);
}
-TEST(SoftwareImageDecodeCacheTest, ImageRectDoesNotContainSrcRect) {
+TEST_F(SoftwareImageDecodeCacheTest, ImageRectDoesNotContainSrcRect) {
PaintImage paint_image = CreatePaintImage(100, 100);
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kHigh;
@@ -695,7 +708,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageRectDoesNotContainSrcRect) {
EXPECT_EQ(100u * 100u * 4u, key.locked_bytes());
}
-TEST(SoftwareImageDecodeCacheTest, ImageRectDoesNotContainSrcRectWithScale) {
+TEST_F(SoftwareImageDecodeCacheTest, ImageRectDoesNotContainSrcRectWithScale) {
PaintImage paint_image = CreatePaintImage(100, 100);
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kHigh;
@@ -716,8 +729,7 @@ TEST(SoftwareImageDecodeCacheTest, ImageRectDoesNotContainSrcRectWithScale) {
EXPECT_EQ(40u * 35u * 4u, key.locked_bytes());
}
-TEST(SoftwareImageDecodeCacheTest, GetTaskForImageSameImage) {
- TestSoftwareImageDecodeCache cache;
+TEST_F(SoftwareImageDecodeCacheTest, GetTaskForImageSameImage) {
PaintImage paint_image = CreatePaintImage(100, 100);
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kHigh;
@@ -727,8 +739,8 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageSameImage) {
SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality,
CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
- ImageDecodeCache::TaskResult result =
- cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
@@ -737,19 +749,18 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageSameImage) {
SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality,
CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
- ImageDecodeCache::TaskResult another_result = cache.GetTaskForImageAndRef(
- another_draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult another_result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, another_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(another_result.need_unref);
EXPECT_TRUE(result.task.get() == another_result.task.get());
TestTileTaskRunner::ProcessTask(result.task.get());
- cache.UnrefImage(draw_image);
- cache.UnrefImage(draw_image);
+ cache_.UnrefImage(draw_image);
+ cache_.UnrefImage(draw_image);
}
-TEST(SoftwareImageDecodeCacheTest, GetTaskForImageProcessUnrefCancel) {
- TestSoftwareImageDecodeCache cache;
+TEST_F(SoftwareImageDecodeCacheTest, GetTaskForImageProcessUnrefCancel) {
PaintImage paint_image = CreatePaintImage(100, 100);
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kHigh;
@@ -759,16 +770,16 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageProcessUnrefCancel) {
SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality,
CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
- ImageDecodeCache::TaskResult result =
- cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
TestTileTaskRunner::ProcessTask(result.task.get());
- cache.UnrefImage(draw_image);
+ cache_.UnrefImage(draw_image);
- result =
- cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ result = cache_.GetTaskForImageAndRef(cache_client_id_, draw_image,
+ ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
@@ -776,11 +787,10 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageProcessUnrefCancel) {
TestTileTaskRunner::CompleteTask(result.task.get());
// This is expected to pass instead of DCHECKing since we're reducing the ref
// for an image which isn't locked to begin with.
- cache.UnrefImage(draw_image);
+ cache_.UnrefImage(draw_image);
}
-TEST(SoftwareImageDecodeCacheTest, GetTaskForImageSameImageDifferentQuality) {
- TestSoftwareImageDecodeCache cache;
+TEST_F(SoftwareImageDecodeCacheTest, GetTaskForImageSameImageDifferentQuality) {
PaintImage paint_image = CreatePaintImage(100, 100);
bool is_decomposable = true;
@@ -791,8 +801,8 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageSameImageDifferentQuality) {
CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
ImageDecodeCache::TaskResult high_quality_result =
- cache.GetTaskForImageAndRef(high_quality_draw_image,
- ImageDecodeCache::TracingInfo());
+ cache_.GetTaskForImageAndRef(cache_client_id_, high_quality_draw_image,
+ ImageDecodeCache::TracingInfo());
EXPECT_TRUE(high_quality_result.need_unref);
EXPECT_TRUE(high_quality_result.task);
@@ -803,8 +813,8 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageSameImageDifferentQuality) {
CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
ImageDecodeCache::TaskResult none_quality_result =
- cache.GetTaskForImageAndRef(none_quality_draw_image,
- ImageDecodeCache::TracingInfo());
+ cache_.GetTaskForImageAndRef(cache_client_id_, none_quality_draw_image,
+ ImageDecodeCache::TracingInfo());
EXPECT_TRUE(none_quality_result.need_unref);
EXPECT_TRUE(none_quality_result.task);
EXPECT_TRUE(high_quality_result.task.get() != none_quality_result.task.get());
@@ -812,12 +822,11 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageSameImageDifferentQuality) {
TestTileTaskRunner::ProcessTask(high_quality_result.task.get());
TestTileTaskRunner::ProcessTask(none_quality_result.task.get());
- cache.UnrefImage(high_quality_draw_image);
- cache.UnrefImage(none_quality_draw_image);
+ cache_.UnrefImage(high_quality_draw_image);
+ cache_.UnrefImage(none_quality_draw_image);
}
-TEST(SoftwareImageDecodeCacheTest, GetTaskForImageSameImageDifferentSize) {
- TestSoftwareImageDecodeCache cache;
+TEST_F(SoftwareImageDecodeCacheTest, GetTaskForImageSameImageDifferentSize) {
PaintImage paint_image = CreatePaintImage(100, 100);
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kHigh;
@@ -827,8 +836,8 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageSameImageDifferentSize) {
SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality,
CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
- ImageDecodeCache::TaskResult half_size_result = cache.GetTaskForImageAndRef(
- half_size_draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult half_size_result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, half_size_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(half_size_result.need_unref);
EXPECT_TRUE(half_size_result.task);
@@ -838,8 +847,8 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageSameImageDifferentSize) {
CreateMatrix(SkSize::Make(0.25f, 0.25f), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
ImageDecodeCache::TaskResult quarter_size_result =
- cache.GetTaskForImageAndRef(quarter_size_draw_image,
- ImageDecodeCache::TracingInfo());
+ cache_.GetTaskForImageAndRef(cache_client_id_, quarter_size_draw_image,
+ ImageDecodeCache::TracingInfo());
EXPECT_TRUE(quarter_size_result.need_unref);
EXPECT_TRUE(quarter_size_result.task);
EXPECT_TRUE(half_size_result.task.get() != quarter_size_result.task.get());
@@ -847,12 +856,11 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageSameImageDifferentSize) {
TestTileTaskRunner::ProcessTask(half_size_result.task.get());
TestTileTaskRunner::ProcessTask(quarter_size_result.task.get());
- cache.UnrefImage(half_size_draw_image);
- cache.UnrefImage(quarter_size_draw_image);
+ cache_.UnrefImage(half_size_draw_image);
+ cache_.UnrefImage(quarter_size_draw_image);
}
-TEST(SoftwareImageDecodeCacheTest, GetTaskForImageDifferentImage) {
- TestSoftwareImageDecodeCache cache;
+TEST_F(SoftwareImageDecodeCacheTest, GetTaskForImageDifferentImage) {
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kHigh;
@@ -862,8 +870,8 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageDifferentImage) {
SkIRect::MakeWH(first_paint_image.width(), first_paint_image.height()),
quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
- ImageDecodeCache::TaskResult first_result = cache.GetTaskForImageAndRef(
- first_draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult first_result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, first_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(first_result.need_unref);
EXPECT_TRUE(first_result.task);
@@ -873,8 +881,8 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageDifferentImage) {
SkIRect::MakeWH(second_paint_image.width(), second_paint_image.height()),
quality, CreateMatrix(SkSize::Make(0.25f, 0.25f), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
- ImageDecodeCache::TaskResult second_result = cache.GetTaskForImageAndRef(
- second_draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult second_result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, second_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(second_result.need_unref);
EXPECT_TRUE(second_result.task);
EXPECT_TRUE(first_result.task.get() != second_result.task.get());
@@ -882,8 +890,8 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageDifferentImage) {
TestTileTaskRunner::ProcessTask(first_result.task.get());
TestTileTaskRunner::ProcessTask(second_result.task.get());
- cache.UnrefImage(first_draw_image);
- cache.UnrefImage(second_draw_image);
+ cache_.UnrefImage(first_draw_image);
+ cache_.UnrefImage(second_draw_image);
}
// crbug.com/709341
@@ -894,8 +902,7 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageDifferentImage) {
#define MAYBE_GetTaskForImageDifferentColorSpace \
GetTaskForImageDifferentColorSpace
#endif
-TEST(SoftwareImageDecodeCacheTest, MAYBE_GetTaskForImageDifferentColorSpace) {
- TestSoftwareImageDecodeCache cache;
+TEST_F(SoftwareImageDecodeCacheTest, MAYBE_GetTaskForImageDifferentColorSpace) {
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kHigh;
@@ -914,8 +921,8 @@ TEST(SoftwareImageDecodeCacheTest, MAYBE_GetTaskForImageDifferentColorSpace) {
SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality,
CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
PaintImage::kDefaultFrameIndex, target_color_params_b);
- ImageDecodeCache::TaskResult first_result = cache.GetTaskForImageAndRef(
- first_draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult first_result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, first_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(first_result.need_unref);
EXPECT_TRUE(first_result.task);
@@ -924,8 +931,8 @@ TEST(SoftwareImageDecodeCacheTest, MAYBE_GetTaskForImageDifferentColorSpace) {
SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality,
CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
PaintImage::kDefaultFrameIndex, target_color_params_c);
- ImageDecodeCache::TaskResult second_result = cache.GetTaskForImageAndRef(
- second_draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult second_result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, second_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(second_result.need_unref);
EXPECT_TRUE(second_result.task);
EXPECT_TRUE(first_result.task.get() != second_result.task.get());
@@ -935,8 +942,8 @@ TEST(SoftwareImageDecodeCacheTest, MAYBE_GetTaskForImageDifferentColorSpace) {
SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality,
CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
PaintImage::kDefaultFrameIndex, target_color_params_b);
- ImageDecodeCache::TaskResult third_result = cache.GetTaskForImageAndRef(
- third_draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult third_result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, third_draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(third_result.need_unref);
EXPECT_TRUE(third_result.task);
EXPECT_TRUE(first_result.task.get() == third_result.task.get());
@@ -944,13 +951,12 @@ TEST(SoftwareImageDecodeCacheTest, MAYBE_GetTaskForImageDifferentColorSpace) {
TestTileTaskRunner::ProcessTask(first_result.task.get());
TestTileTaskRunner::ProcessTask(second_result.task.get());
- cache.UnrefImage(first_draw_image);
- cache.UnrefImage(second_draw_image);
- cache.UnrefImage(third_draw_image);
+ cache_.UnrefImage(first_draw_image);
+ cache_.UnrefImage(second_draw_image);
+ cache_.UnrefImage(third_draw_image);
}
-TEST(SoftwareImageDecodeCacheTest, GetTaskForImageAlreadyDecoded) {
- TestSoftwareImageDecodeCache cache;
+TEST_F(SoftwareImageDecodeCacheTest, GetTaskForImageAlreadyDecoded) {
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kHigh;
@@ -960,27 +966,26 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageAlreadyDecoded) {
SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality,
CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
- ImageDecodeCache::TaskResult result =
- cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
TestTileTaskRunner::ScheduleTask(result.task.get());
TestTileTaskRunner::RunTask(result.task.get());
- ImageDecodeCache::TaskResult another_result =
- cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult another_result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(another_result.need_unref);
EXPECT_FALSE(another_result.task);
TestTileTaskRunner::CompleteTask(result.task.get());
- cache.UnrefImage(draw_image);
- cache.UnrefImage(draw_image);
+ cache_.UnrefImage(draw_image);
+ cache_.UnrefImage(draw_image);
}
-TEST(SoftwareImageDecodeCacheTest, GetTaskForImageAlreadyPrerolled) {
- TestSoftwareImageDecodeCache cache;
+TEST_F(SoftwareImageDecodeCacheTest, GetTaskForImageAlreadyPrerolled) {
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kLow;
@@ -990,33 +995,32 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageAlreadyPrerolled) {
SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality,
CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
- ImageDecodeCache::TaskResult result =
- cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
TestTileTaskRunner::ScheduleTask(result.task.get());
TestTileTaskRunner::RunTask(result.task.get());
- ImageDecodeCache::TaskResult another_result =
- cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult another_result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(another_result.need_unref);
EXPECT_FALSE(another_result.task);
TestTileTaskRunner::CompleteTask(result.task.get());
- ImageDecodeCache::TaskResult third_result =
- cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult third_result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(third_result.need_unref);
EXPECT_FALSE(third_result.task);
- cache.UnrefImage(draw_image);
- cache.UnrefImage(draw_image);
- cache.UnrefImage(draw_image);
+ cache_.UnrefImage(draw_image);
+ cache_.UnrefImage(draw_image);
+ cache_.UnrefImage(draw_image);
}
-TEST(SoftwareImageDecodeCacheTest, GetTaskForImageCanceledGetsNewTask) {
- TestSoftwareImageDecodeCache cache;
+TEST_F(SoftwareImageDecodeCacheTest, GetTaskForImageCanceledGetsNewTask) {
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kHigh;
@@ -1026,13 +1030,13 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageCanceledGetsNewTask) {
SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality,
CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
- ImageDecodeCache::TaskResult result =
- cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
- ImageDecodeCache::TaskResult another_result =
- cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult another_result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(another_result.need_unref);
EXPECT_TRUE(another_result.task.get() == result.task.get());
@@ -1041,24 +1045,23 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageCanceledGetsNewTask) {
TestTileTaskRunner::CompleteTask(result.task.get());
// Fully cancel everything (so the raster would unref things).
- cache.UnrefImage(draw_image);
- cache.UnrefImage(draw_image);
+ cache_.UnrefImage(draw_image);
+ cache_.UnrefImage(draw_image);
// Here a new task is created.
- ImageDecodeCache::TaskResult third_result =
- cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult third_result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(third_result.need_unref);
EXPECT_TRUE(third_result.task);
EXPECT_FALSE(third_result.task.get() == result.task.get());
TestTileTaskRunner::ProcessTask(third_result.task.get());
- cache.UnrefImage(draw_image);
+ cache_.UnrefImage(draw_image);
}
-TEST(SoftwareImageDecodeCacheTest,
- GetTaskForImageCanceledWhileReffedGetsNewTask) {
- TestSoftwareImageDecodeCache cache;
+TEST_F(SoftwareImageDecodeCacheTest,
+ GetTaskForImageCanceledWhileReffedGetsNewTask) {
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kHigh;
@@ -1068,13 +1071,13 @@ TEST(SoftwareImageDecodeCacheTest,
SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality,
CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
- ImageDecodeCache::TaskResult result =
- cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
- ImageDecodeCache::TaskResult another_result =
- cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult another_result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(another_result.need_unref);
EXPECT_TRUE(another_result.task.get() == result.task.get());
@@ -1084,8 +1087,8 @@ TEST(SoftwareImageDecodeCacheTest,
// Note that here, everything is reffed, but a new task is created. This is
// possible with repeated schedule/cancel operations.
- ImageDecodeCache::TaskResult third_result =
- cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult third_result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(third_result.need_unref);
EXPECT_TRUE(third_result.task);
EXPECT_FALSE(third_result.task.get() == result.task.get());
@@ -1093,13 +1096,12 @@ TEST(SoftwareImageDecodeCacheTest,
TestTileTaskRunner::ProcessTask(third_result.task.get());
// 3 Unrefs!!!
- cache.UnrefImage(draw_image);
- cache.UnrefImage(draw_image);
- cache.UnrefImage(draw_image);
+ cache_.UnrefImage(draw_image);
+ cache_.UnrefImage(draw_image);
+ cache_.UnrefImage(draw_image);
}
-TEST(SoftwareImageDecodeCacheTest, GetDecodedImageForDraw) {
- TestSoftwareImageDecodeCache cache;
+TEST_F(SoftwareImageDecodeCacheTest, GetDecodedImageForDraw) {
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kHigh;
@@ -1109,15 +1111,15 @@ TEST(SoftwareImageDecodeCacheTest, GetDecodedImageForDraw) {
SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality,
CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
- ImageDecodeCache::TaskResult result =
- cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
TestTileTaskRunner::ProcessTask(result.task.get());
DecodedDrawImage decoded_draw_image =
- cache.GetDecodedImageForDraw(draw_image);
+ cache_.GetDecodedImageForDraw(draw_image);
EXPECT_TRUE(decoded_draw_image.image());
EXPECT_EQ(50, decoded_draw_image.image()->width());
EXPECT_EQ(50, decoded_draw_image.image()->height());
@@ -1127,13 +1129,12 @@ TEST(SoftwareImageDecodeCacheTest, GetDecodedImageForDraw) {
decoded_draw_image.filter_quality());
EXPECT_FALSE(decoded_draw_image.is_scale_adjustment_identity());
- cache.DrawWithImageFinished(draw_image, decoded_draw_image);
- cache.UnrefImage(draw_image);
+ cache_.DrawWithImageFinished(draw_image, decoded_draw_image);
+ cache_.UnrefImage(draw_image);
}
-TEST(SoftwareImageDecodeCacheTest,
- GetDecodedImageForDrawWithNonContainedSrcRect) {
- TestSoftwareImageDecodeCache cache;
+TEST_F(SoftwareImageDecodeCacheTest,
+ GetDecodedImageForDrawWithNonContainedSrcRect) {
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kHigh;
@@ -1143,15 +1144,15 @@ TEST(SoftwareImageDecodeCacheTest,
SkIRect::MakeXYWH(20, 30, paint_image.width(), paint_image.height()),
quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
- ImageDecodeCache::TaskResult result =
- cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
TestTileTaskRunner::ProcessTask(result.task.get());
DecodedDrawImage decoded_draw_image =
- cache.GetDecodedImageForDraw(draw_image);
+ cache_.GetDecodedImageForDraw(draw_image);
EXPECT_TRUE(decoded_draw_image.image());
EXPECT_EQ(40, decoded_draw_image.image()->width());
EXPECT_EQ(35, decoded_draw_image.image()->height());
@@ -1161,12 +1162,11 @@ TEST(SoftwareImageDecodeCacheTest,
decoded_draw_image.filter_quality());
EXPECT_FALSE(decoded_draw_image.is_scale_adjustment_identity());
- cache.DrawWithImageFinished(draw_image, decoded_draw_image);
- cache.UnrefImage(draw_image);
+ cache_.DrawWithImageFinished(draw_image, decoded_draw_image);
+ cache_.UnrefImage(draw_image);
}
-TEST(SoftwareImageDecodeCacheTest, GetDecodedImageForDrawAtRasterDecode) {
- TestSoftwareImageDecodeCache cache;
+TEST_F(SoftwareImageDecodeCacheTest, GetDecodedImageForDrawAtRasterDecode) {
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kHigh;
@@ -1178,7 +1178,7 @@ TEST(SoftwareImageDecodeCacheTest, GetDecodedImageForDrawAtRasterDecode) {
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
DecodedDrawImage decoded_draw_image =
- cache.GetDecodedImageForDraw(draw_image);
+ cache_.GetDecodedImageForDraw(draw_image);
EXPECT_TRUE(decoded_draw_image.image());
EXPECT_EQ(50, decoded_draw_image.image()->width());
EXPECT_EQ(50, decoded_draw_image.image()->height());
@@ -1188,12 +1188,11 @@ TEST(SoftwareImageDecodeCacheTest, GetDecodedImageForDrawAtRasterDecode) {
decoded_draw_image.filter_quality());
EXPECT_FALSE(decoded_draw_image.is_scale_adjustment_identity());
- cache.DrawWithImageFinished(draw_image, decoded_draw_image);
+ cache_.DrawWithImageFinished(draw_image, decoded_draw_image);
}
-TEST(SoftwareImageDecodeCacheTest,
- GetDecodedImageForDrawAtRasterDecodeMultipleTimes) {
- TestSoftwareImageDecodeCache cache;
+TEST_F(SoftwareImageDecodeCacheTest,
+ GetDecodedImageForDrawAtRasterDecodeMultipleTimes) {
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kHigh;
@@ -1205,7 +1204,7 @@ TEST(SoftwareImageDecodeCacheTest,
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
DecodedDrawImage decoded_draw_image =
- cache.GetDecodedImageForDraw(draw_image);
+ cache_.GetDecodedImageForDraw(draw_image);
ASSERT_TRUE(decoded_draw_image.image());
EXPECT_EQ(50, decoded_draw_image.image()->width());
EXPECT_EQ(50, decoded_draw_image.image()->height());
@@ -1216,16 +1215,15 @@ TEST(SoftwareImageDecodeCacheTest,
EXPECT_FALSE(decoded_draw_image.is_scale_adjustment_identity());
DecodedDrawImage another_decoded_draw_image =
- cache.GetDecodedImageForDraw(draw_image);
+ cache_.GetDecodedImageForDraw(draw_image);
EXPECT_EQ(decoded_draw_image.image()->uniqueID(),
another_decoded_draw_image.image()->uniqueID());
- cache.DrawWithImageFinished(draw_image, decoded_draw_image);
- cache.DrawWithImageFinished(draw_image, another_decoded_draw_image);
+ cache_.DrawWithImageFinished(draw_image, decoded_draw_image);
+ cache_.DrawWithImageFinished(draw_image, another_decoded_draw_image);
}
-TEST(SoftwareImageDecodeCacheTest, ZeroSizedImagesAreSkipped) {
- TestSoftwareImageDecodeCache cache;
+TEST_F(SoftwareImageDecodeCacheTest, ZeroSizedImagesAreSkipped) {
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kHigh;
@@ -1236,20 +1234,19 @@ TEST(SoftwareImageDecodeCacheTest, ZeroSizedImagesAreSkipped) {
CreateMatrix(SkSize::Make(0.f, 0.f), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
- ImageDecodeCache::TaskResult result =
- cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_FALSE(result.task);
EXPECT_FALSE(result.need_unref);
DecodedDrawImage decoded_draw_image =
- cache.GetDecodedImageForDraw(draw_image);
+ cache_.GetDecodedImageForDraw(draw_image);
EXPECT_FALSE(decoded_draw_image.image());
- cache.DrawWithImageFinished(draw_image, decoded_draw_image);
+ cache_.DrawWithImageFinished(draw_image, decoded_draw_image);
}
-TEST(SoftwareImageDecodeCacheTest, NonOverlappingSrcRectImagesAreSkipped) {
- TestSoftwareImageDecodeCache cache;
+TEST_F(SoftwareImageDecodeCacheTest, NonOverlappingSrcRectImagesAreSkipped) {
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kHigh;
@@ -1260,20 +1257,19 @@ TEST(SoftwareImageDecodeCacheTest, NonOverlappingSrcRectImagesAreSkipped) {
quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
- ImageDecodeCache::TaskResult result =
- cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_FALSE(result.task);
EXPECT_FALSE(result.need_unref);
DecodedDrawImage decoded_draw_image =
- cache.GetDecodedImageForDraw(draw_image);
+ cache_.GetDecodedImageForDraw(draw_image);
EXPECT_FALSE(decoded_draw_image.image());
- cache.DrawWithImageFinished(draw_image, decoded_draw_image);
+ cache_.DrawWithImageFinished(draw_image, decoded_draw_image);
}
-TEST(SoftwareImageDecodeCacheTest, LowQualityFilterIsHandled) {
- TestSoftwareImageDecodeCache cache;
+TEST_F(SoftwareImageDecodeCacheTest, LowQualityFilterIsHandled) {
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kLow;
@@ -1284,26 +1280,25 @@ TEST(SoftwareImageDecodeCacheTest, LowQualityFilterIsHandled) {
CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
- ImageDecodeCache::TaskResult result =
- cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.task);
EXPECT_TRUE(result.need_unref);
TestTileTaskRunner::ProcessTask(result.task.get());
DecodedDrawImage decoded_draw_image =
- cache.GetDecodedImageForDraw(draw_image);
+ cache_.GetDecodedImageForDraw(draw_image);
EXPECT_TRUE(decoded_draw_image.image());
// If we decoded the image and cached it, it would be stored in a different
// SkImage object.
EXPECT_FALSE(decoded_draw_image.image()->isLazyGenerated());
- cache.DrawWithImageFinished(draw_image, decoded_draw_image);
- cache.UnrefImage(draw_image);
+ cache_.DrawWithImageFinished(draw_image, decoded_draw_image);
+ cache_.UnrefImage(draw_image);
}
-TEST(SoftwareImageDecodeCacheTest, LowQualityScaledSubrectIsHandled) {
- TestSoftwareImageDecodeCache cache;
+TEST_F(SoftwareImageDecodeCacheTest, LowQualityScaledSubrectIsHandled) {
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kLow;
@@ -1313,15 +1308,15 @@ TEST(SoftwareImageDecodeCacheTest, LowQualityScaledSubrectIsHandled) {
CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
- ImageDecodeCache::TaskResult result =
- cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.task);
EXPECT_TRUE(result.need_unref);
TestTileTaskRunner::ProcessTask(result.task.get());
DecodedDrawImage decoded_draw_image =
- cache.GetDecodedImageForDraw(draw_image);
+ cache_.GetDecodedImageForDraw(draw_image);
EXPECT_TRUE(decoded_draw_image.image());
// If we decoded the image and cached it, it would be stored in a different
// SkImage object.
@@ -1333,12 +1328,11 @@ TEST(SoftwareImageDecodeCacheTest, LowQualityScaledSubrectIsHandled) {
EXPECT_EQ(0.5f, decoded_draw_image.scale_adjustment().width());
EXPECT_EQ(0.5f, decoded_draw_image.scale_adjustment().height());
- cache.DrawWithImageFinished(draw_image, decoded_draw_image);
- cache.UnrefImage(draw_image);
+ cache_.DrawWithImageFinished(draw_image, decoded_draw_image);
+ cache_.UnrefImage(draw_image);
}
-TEST(SoftwareImageDecodeCacheTest, NoneQualityScaledSubrectIsHandled) {
- TestSoftwareImageDecodeCache cache;
+TEST_F(SoftwareImageDecodeCacheTest, NoneQualityScaledSubrectIsHandled) {
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kNone;
@@ -1348,15 +1342,15 @@ TEST(SoftwareImageDecodeCacheTest, NoneQualityScaledSubrectIsHandled) {
CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
- ImageDecodeCache::TaskResult result =
- cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.task);
EXPECT_TRUE(result.need_unref);
TestTileTaskRunner::ProcessTask(result.task.get());
DecodedDrawImage decoded_draw_image =
- cache.GetDecodedImageForDraw(draw_image);
+ cache_.GetDecodedImageForDraw(draw_image);
EXPECT_TRUE(decoded_draw_image.image());
// If we decoded the image and cached it, it would be stored in a different
// SkImage object.
@@ -1365,12 +1359,11 @@ TEST(SoftwareImageDecodeCacheTest, NoneQualityScaledSubrectIsHandled) {
decoded_draw_image.filter_quality());
EXPECT_TRUE(decoded_draw_image.is_scale_adjustment_identity());
- cache.DrawWithImageFinished(draw_image, decoded_draw_image);
- cache.UnrefImage(draw_image);
+ cache_.DrawWithImageFinished(draw_image, decoded_draw_image);
+ cache_.UnrefImage(draw_image);
}
-TEST(SoftwareImageDecodeCacheTest, MediumQualityAt01_5ScaleIsHandled) {
- TestSoftwareImageDecodeCache cache;
+TEST_F(SoftwareImageDecodeCacheTest, MediumQualityAt01_5ScaleIsHandled) {
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kMedium;
@@ -1381,15 +1374,15 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt01_5ScaleIsHandled) {
CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
- ImageDecodeCache::TaskResult result =
- cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.task);
EXPECT_TRUE(result.need_unref);
TestTileTaskRunner::ProcessTask(result.task.get());
DecodedDrawImage decoded_draw_image =
- cache.GetDecodedImageForDraw(draw_image);
+ cache_.GetDecodedImageForDraw(draw_image);
EXPECT_TRUE(decoded_draw_image.image());
// Decoded image should not be lazy generated.
EXPECT_FALSE(decoded_draw_image.image()->isLazyGenerated());
@@ -1398,12 +1391,11 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt01_5ScaleIsHandled) {
EXPECT_EQ(500, decoded_draw_image.image()->width());
EXPECT_EQ(200, decoded_draw_image.image()->height());
- cache.DrawWithImageFinished(draw_image, decoded_draw_image);
- cache.UnrefImage(draw_image);
+ cache_.DrawWithImageFinished(draw_image, decoded_draw_image);
+ cache_.UnrefImage(draw_image);
}
-TEST(SoftwareImageDecodeCacheTest, MediumQualityAt1_0ScaleIsHandled) {
- TestSoftwareImageDecodeCache cache;
+TEST_F(SoftwareImageDecodeCacheTest, MediumQualityAt1_0ScaleIsHandled) {
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kMedium;
@@ -1414,15 +1406,15 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt1_0ScaleIsHandled) {
CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
- ImageDecodeCache::TaskResult result =
- cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.task);
EXPECT_TRUE(result.need_unref);
TestTileTaskRunner::ProcessTask(result.task.get());
DecodedDrawImage decoded_draw_image =
- cache.GetDecodedImageForDraw(draw_image);
+ cache_.GetDecodedImageForDraw(draw_image);
EXPECT_TRUE(decoded_draw_image.image());
// Decoded image should not be lazy generated.
EXPECT_FALSE(decoded_draw_image.image()->isLazyGenerated());
@@ -1431,12 +1423,11 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt1_0ScaleIsHandled) {
EXPECT_EQ(500, decoded_draw_image.image()->width());
EXPECT_EQ(200, decoded_draw_image.image()->height());
- cache.DrawWithImageFinished(draw_image, decoded_draw_image);
- cache.UnrefImage(draw_image);
+ cache_.DrawWithImageFinished(draw_image, decoded_draw_image);
+ cache_.UnrefImage(draw_image);
}
-TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_75ScaleIsHandled) {
- TestSoftwareImageDecodeCache cache;
+TEST_F(SoftwareImageDecodeCacheTest, MediumQualityAt0_75ScaleIsHandled) {
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kMedium;
@@ -1447,15 +1438,15 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_75ScaleIsHandled) {
CreateMatrix(SkSize::Make(0.75f, 0.75f), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
- ImageDecodeCache::TaskResult result =
- cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.task);
EXPECT_TRUE(result.need_unref);
TestTileTaskRunner::ProcessTask(result.task.get());
DecodedDrawImage decoded_draw_image =
- cache.GetDecodedImageForDraw(draw_image);
+ cache_.GetDecodedImageForDraw(draw_image);
EXPECT_TRUE(decoded_draw_image.image());
// Decoded image should not be lazy generated.
EXPECT_FALSE(decoded_draw_image.image()->isLazyGenerated());
@@ -1464,12 +1455,11 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_75ScaleIsHandled) {
EXPECT_EQ(500, decoded_draw_image.image()->width());
EXPECT_EQ(200, decoded_draw_image.image()->height());
- cache.DrawWithImageFinished(draw_image, decoded_draw_image);
- cache.UnrefImage(draw_image);
+ cache_.DrawWithImageFinished(draw_image, decoded_draw_image);
+ cache_.UnrefImage(draw_image);
}
-TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_5ScaleIsHandled) {
- TestSoftwareImageDecodeCache cache;
+TEST_F(SoftwareImageDecodeCacheTest, MediumQualityAt0_5ScaleIsHandled) {
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kMedium;
@@ -1480,15 +1470,15 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_5ScaleIsHandled) {
CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
- ImageDecodeCache::TaskResult result =
- cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.task);
EXPECT_TRUE(result.need_unref);
TestTileTaskRunner::ProcessTask(result.task.get());
DecodedDrawImage decoded_draw_image =
- cache.GetDecodedImageForDraw(draw_image);
+ cache_.GetDecodedImageForDraw(draw_image);
EXPECT_TRUE(decoded_draw_image.image());
// Decoded image should not be lazy generated.
EXPECT_FALSE(decoded_draw_image.image()->isLazyGenerated());
@@ -1497,12 +1487,11 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_5ScaleIsHandled) {
EXPECT_EQ(250, decoded_draw_image.image()->width());
EXPECT_EQ(100, decoded_draw_image.image()->height());
- cache.DrawWithImageFinished(draw_image, decoded_draw_image);
- cache.UnrefImage(draw_image);
+ cache_.DrawWithImageFinished(draw_image, decoded_draw_image);
+ cache_.UnrefImage(draw_image);
}
-TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_49ScaleIsHandled) {
- TestSoftwareImageDecodeCache cache;
+TEST_F(SoftwareImageDecodeCacheTest, MediumQualityAt0_49ScaleIsHandled) {
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kMedium;
@@ -1513,15 +1502,15 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_49ScaleIsHandled) {
CreateMatrix(SkSize::Make(0.49f, 0.49f), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
- ImageDecodeCache::TaskResult result =
- cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.task);
EXPECT_TRUE(result.need_unref);
TestTileTaskRunner::ProcessTask(result.task.get());
DecodedDrawImage decoded_draw_image =
- cache.GetDecodedImageForDraw(draw_image);
+ cache_.GetDecodedImageForDraw(draw_image);
EXPECT_TRUE(decoded_draw_image.image());
// Decoded image should not be lazy generated.
EXPECT_FALSE(decoded_draw_image.image()->isLazyGenerated());
@@ -1530,12 +1519,11 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_49ScaleIsHandled) {
EXPECT_EQ(250, decoded_draw_image.image()->width());
EXPECT_EQ(100, decoded_draw_image.image()->height());
- cache.DrawWithImageFinished(draw_image, decoded_draw_image);
- cache.UnrefImage(draw_image);
+ cache_.DrawWithImageFinished(draw_image, decoded_draw_image);
+ cache_.UnrefImage(draw_image);
}
-TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_1ScaleIsHandled) {
- TestSoftwareImageDecodeCache cache;
+TEST_F(SoftwareImageDecodeCacheTest, MediumQualityAt0_1ScaleIsHandled) {
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kMedium;
@@ -1546,15 +1534,15 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_1ScaleIsHandled) {
CreateMatrix(SkSize::Make(0.1f, 0.1f), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
- ImageDecodeCache::TaskResult result =
- cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.task);
EXPECT_TRUE(result.need_unref);
TestTileTaskRunner::ProcessTask(result.task.get());
DecodedDrawImage decoded_draw_image =
- cache.GetDecodedImageForDraw(draw_image);
+ cache_.GetDecodedImageForDraw(draw_image);
EXPECT_TRUE(decoded_draw_image.image());
// Decoded image should not be lazy generated.
EXPECT_FALSE(decoded_draw_image.image()->isLazyGenerated());
@@ -1563,12 +1551,11 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_1ScaleIsHandled) {
EXPECT_EQ(63, decoded_draw_image.image()->width());
EXPECT_EQ(25, decoded_draw_image.image()->height());
- cache.DrawWithImageFinished(draw_image, decoded_draw_image);
- cache.UnrefImage(draw_image);
+ cache_.DrawWithImageFinished(draw_image, decoded_draw_image);
+ cache_.UnrefImage(draw_image);
}
-TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_01ScaleIsHandled) {
- TestSoftwareImageDecodeCache cache;
+TEST_F(SoftwareImageDecodeCacheTest, MediumQualityAt0_01ScaleIsHandled) {
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kMedium;
@@ -1579,15 +1566,15 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_01ScaleIsHandled) {
CreateMatrix(SkSize::Make(0.01f, 0.01f), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
- ImageDecodeCache::TaskResult result =
- cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.task);
EXPECT_TRUE(result.need_unref);
TestTileTaskRunner::ProcessTask(result.task.get());
DecodedDrawImage decoded_draw_image =
- cache.GetDecodedImageForDraw(draw_image);
+ cache_.GetDecodedImageForDraw(draw_image);
EXPECT_TRUE(decoded_draw_image.image());
// Decoded image should not be lazy generated.
EXPECT_FALSE(decoded_draw_image.image()->isLazyGenerated());
@@ -1596,12 +1583,11 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_01ScaleIsHandled) {
EXPECT_EQ(8, decoded_draw_image.image()->width());
EXPECT_EQ(4, decoded_draw_image.image()->height());
- cache.DrawWithImageFinished(draw_image, decoded_draw_image);
- cache.UnrefImage(draw_image);
+ cache_.DrawWithImageFinished(draw_image, decoded_draw_image);
+ cache_.UnrefImage(draw_image);
}
-TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_001ScaleIsHandled) {
- TestSoftwareImageDecodeCache cache;
+TEST_F(SoftwareImageDecodeCacheTest, MediumQualityAt0_001ScaleIsHandled) {
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kMedium;
@@ -1612,21 +1598,20 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_001ScaleIsHandled) {
CreateMatrix(SkSize::Make(0.001f, 0.001f), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
- ImageDecodeCache::TaskResult result =
- cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_FALSE(result.task);
EXPECT_FALSE(result.need_unref);
DecodedDrawImage decoded_draw_image =
- cache.GetDecodedImageForDraw(draw_image);
+ cache_.GetDecodedImageForDraw(draw_image);
EXPECT_FALSE(decoded_draw_image.image());
- cache.DrawWithImageFinished(draw_image, decoded_draw_image);
+ cache_.DrawWithImageFinished(draw_image, decoded_draw_image);
}
-TEST(SoftwareImageDecodeCacheTest,
- MediumQualityImagesAreTheSameAt0_5And0_49Scale) {
- TestSoftwareImageDecodeCache cache;
+TEST_F(SoftwareImageDecodeCacheTest,
+ MediumQualityImagesAreTheSameAt0_5And0_49Scale) {
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kMedium;
@@ -1642,22 +1627,22 @@ TEST(SoftwareImageDecodeCacheTest,
CreateMatrix(SkSize::Make(0.49f, 0.49f), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
- ImageDecodeCache::TaskResult result_50 = cache.GetTaskForImageAndRef(
- draw_image_50, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result_50 = cache_.GetTaskForImageAndRef(
+ cache_client_id_, draw_image_50, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result_50.task);
EXPECT_TRUE(result_50.need_unref);
- ImageDecodeCache::TaskResult result_49 = cache.GetTaskForImageAndRef(
- draw_image_49, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result_49 = cache_.GetTaskForImageAndRef(
+ cache_client_id_, draw_image_49, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result_49.task);
EXPECT_TRUE(result_49.need_unref);
TestTileTaskRunner::ProcessTask(result_49.task.get());
DecodedDrawImage decoded_draw_image_50 =
- cache.GetDecodedImageForDraw(draw_image_50);
+ cache_.GetDecodedImageForDraw(draw_image_50);
EXPECT_TRUE(decoded_draw_image_50.image());
DecodedDrawImage decoded_draw_image_49 =
- cache.GetDecodedImageForDraw(draw_image_49);
+ cache_.GetDecodedImageForDraw(draw_image_49);
EXPECT_TRUE(decoded_draw_image_49.image());
// Decoded image should not be lazy generated.
EXPECT_FALSE(decoded_draw_image_50.image()->isLazyGenerated());
@@ -1673,14 +1658,13 @@ TEST(SoftwareImageDecodeCacheTest,
EXPECT_EQ(decoded_draw_image_50.image(), decoded_draw_image_49.image());
- cache.DrawWithImageFinished(draw_image_50, decoded_draw_image_50);
- cache.UnrefImage(draw_image_50);
- cache.DrawWithImageFinished(draw_image_49, decoded_draw_image_49);
- cache.UnrefImage(draw_image_49);
+ cache_.DrawWithImageFinished(draw_image_50, decoded_draw_image_50);
+ cache_.UnrefImage(draw_image_50);
+ cache_.DrawWithImageFinished(draw_image_49, decoded_draw_image_49);
+ cache_.UnrefImage(draw_image_49);
}
-TEST(SoftwareImageDecodeCacheTest, ClearCache) {
- TestSoftwareImageDecodeCache cache;
+TEST_F(SoftwareImageDecodeCacheTest, ClearCache) {
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kHigh;
@@ -1691,24 +1675,23 @@ TEST(SoftwareImageDecodeCacheTest, ClearCache) {
SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality,
CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
- ImageDecodeCache::TaskResult result = cache.GetTaskForImageAndRef(
- draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.need_unref);
EXPECT_TRUE(result.task);
TestTileTaskRunner::ProcessTask(result.task.get());
- cache.UnrefImage(draw_image);
+ cache_.UnrefImage(draw_image);
}
- EXPECT_EQ(10u, cache.GetNumCacheEntriesForTesting());
+ EXPECT_EQ(10u, cache_.GetNumCacheEntriesForTesting());
// Tell our cache to clear resources.
- cache.ClearCache();
+ cache_.ClearCache();
- EXPECT_EQ(0u, cache.GetNumCacheEntriesForTesting());
+ EXPECT_EQ(0u, cache_.GetNumCacheEntriesForTesting());
}
-TEST(SoftwareImageDecodeCacheTest, CacheDecodesExpectedFrames) {
- TestSoftwareImageDecodeCache cache;
+TEST_F(SoftwareImageDecodeCacheTest, CacheDecodesExpectedFrames) {
std::vector<FrameMetadata> frames = {
FrameMetadata(true, base::Milliseconds(2)),
FrameMetadata(true, base::Milliseconds(3)),
@@ -1729,39 +1712,38 @@ TEST(SoftwareImageDecodeCacheTest, CacheDecodesExpectedFrames) {
SkIRect::MakeWH(image.width(), image.height()), quality,
CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
1u, DefaultTargetColorParams());
- auto decoded_image = cache.GetDecodedImageForDraw(draw_image);
+ auto decoded_image = cache_.GetDecodedImageForDraw(draw_image);
ASSERT_TRUE(decoded_image.image());
ASSERT_EQ(generator->frames_decoded().size(), 1u);
EXPECT_EQ(generator->frames_decoded().count(1u), 1u);
generator->reset_frames_decoded();
- cache.DrawWithImageFinished(draw_image, decoded_image);
+ cache_.DrawWithImageFinished(draw_image, decoded_image);
// Scaled.
DrawImage scaled_draw_image(draw_image, 0.5f, 2u,
draw_image.target_color_params());
- decoded_image = cache.GetDecodedImageForDraw(scaled_draw_image);
+ decoded_image = cache_.GetDecodedImageForDraw(scaled_draw_image);
ASSERT_TRUE(decoded_image.image());
ASSERT_EQ(generator->frames_decoded().size(), 1u);
EXPECT_EQ(generator->frames_decoded().count(2u), 1u);
generator->reset_frames_decoded();
- cache.DrawWithImageFinished(scaled_draw_image, decoded_image);
+ cache_.DrawWithImageFinished(scaled_draw_image, decoded_image);
// Subset.
DrawImage subset_draw_image(
image, false, SkIRect::MakeWH(5, 5), quality,
CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), 3u,
DefaultTargetColorParams());
- decoded_image = cache.GetDecodedImageForDraw(subset_draw_image);
+ decoded_image = cache_.GetDecodedImageForDraw(subset_draw_image);
ASSERT_TRUE(decoded_image.image());
ASSERT_EQ(generator->frames_decoded().size(), 1u);
EXPECT_EQ(generator->frames_decoded().count(3u), 1u);
generator->reset_frames_decoded();
- cache.DrawWithImageFinished(subset_draw_image, decoded_image);
+ cache_.DrawWithImageFinished(subset_draw_image, decoded_image);
}
-TEST(SoftwareImageDecodeCacheTest, SizeSubrectingIsHandled) {
+TEST_F(SoftwareImageDecodeCacheTest, SizeSubrectingIsHandled) {
const int min_dimension = 4 * 1024 + 2;
- TestSoftwareImageDecodeCache cache;
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kLow;
@@ -1772,29 +1754,28 @@ TEST(SoftwareImageDecodeCacheTest, SizeSubrectingIsHandled) {
CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
- ImageDecodeCache::TaskResult result =
- cache.GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+ ImageDecodeCache::TaskResult result = cache_.GetTaskForImageAndRef(
+ cache_client_id_, draw_image, ImageDecodeCache::TracingInfo());
EXPECT_TRUE(result.task);
EXPECT_TRUE(result.need_unref);
TestTileTaskRunner::ProcessTask(result.task.get());
DecodedDrawImage decoded_draw_image =
- cache.GetDecodedImageForDraw(draw_image);
+ cache_.GetDecodedImageForDraw(draw_image);
// Since we didn't allocate any backing for the memory, we expect this to be
// false. This test is here to ensure that we at least got to the point where
// we tried to decode something instead of recursing infinitely.
EXPECT_FALSE(decoded_draw_image.image());
- cache.DrawWithImageFinished(draw_image, decoded_draw_image);
- cache.UnrefImage(draw_image);
+ cache_.DrawWithImageFinished(draw_image, decoded_draw_image);
+ cache_.UnrefImage(draw_image);
}
-TEST(SoftwareImageDecodeCacheTest, EmptyTargetSizeDecode) {
+TEST_F(SoftwareImageDecodeCacheTest, EmptyTargetSizeDecode) {
// Tests that requesting an empty sized decode followed by an original sized
// decode returns no decoded images. This is a regression test. See
// crbug.com/802976.
- TestSoftwareImageDecodeCache cache;
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kLow;
@@ -1806,9 +1787,9 @@ TEST(SoftwareImageDecodeCacheTest, EmptyTargetSizeDecode) {
PaintImage::kDefaultFrameIndex,
DefaultTargetColorParams());
DecodedDrawImage decoded_draw_image =
- cache.GetDecodedImageForDraw(draw_image);
+ cache_.GetDecodedImageForDraw(draw_image);
EXPECT_TRUE(decoded_draw_image.image());
- cache.DrawWithImageFinished(draw_image, decoded_draw_image);
+ cache_.DrawWithImageFinished(draw_image, decoded_draw_image);
// Ask for another decode, this time with an empty subrect.
DrawImage empty_draw_image(
@@ -1816,13 +1797,12 @@ TEST(SoftwareImageDecodeCacheTest, EmptyTargetSizeDecode) {
CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
DecodedDrawImage empty_decoded_draw_image =
- cache.GetDecodedImageForDraw(empty_draw_image);
+ cache_.GetDecodedImageForDraw(empty_draw_image);
EXPECT_FALSE(empty_decoded_draw_image.image());
- cache.DrawWithImageFinished(empty_draw_image, empty_decoded_draw_image);
+ cache_.DrawWithImageFinished(empty_draw_image, empty_decoded_draw_image);
}
-TEST(SoftwareImageDecodeCacheTest, BitmapImageColorConverted) {
- TestSoftwareImageDecodeCache cache;
+TEST_F(SoftwareImageDecodeCacheTest, BitmapImageColorConverted) {
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kHigh;
const TargetColorParams target_color_params(
@@ -1836,7 +1816,7 @@ TEST(SoftwareImageDecodeCacheTest, BitmapImageColorConverted) {
PaintImage::kDefaultFrameIndex, target_color_params);
DecodedDrawImage decoded_draw_image =
- cache.GetDecodedImageForDraw(draw_image);
+ cache_.GetDecodedImageForDraw(draw_image);
EXPECT_TRUE(decoded_draw_image.image());
// Expect that we allocated a new image.
EXPECT_NE(decoded_draw_image.image().get(), paint_image.GetSwSkImage().get());
@@ -1846,11 +1826,10 @@ TEST(SoftwareImageDecodeCacheTest, BitmapImageColorConverted) {
decoded_draw_image.image()->colorSpace(),
target_color_params.color_space.ToSkColorSpace().get()));
- cache.DrawWithImageFinished(draw_image, decoded_draw_image);
+ cache_.DrawWithImageFinished(draw_image, decoded_draw_image);
}
-TEST(SoftwareImageDecodeCacheTest, BitmapImageNotColorConverted) {
- TestSoftwareImageDecodeCache cache;
+TEST_F(SoftwareImageDecodeCacheTest, BitmapImageNotColorConverted) {
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kHigh;
@@ -1862,13 +1841,12 @@ TEST(SoftwareImageDecodeCacheTest, BitmapImageNotColorConverted) {
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
// The cache should not support this image.
- EXPECT_FALSE(cache.UseCacheForDrawImage(draw_image));
+ EXPECT_FALSE(cache_.UseCacheForDrawImage(draw_image));
}
// TODO(ccameron): Re-enable this when the root cause of crashes is discovered.
// https://crbug.com/791828
-TEST(SoftwareImageDecodeCacheTest, DISABLED_ContentIdCaching) {
- TestSoftwareImageDecodeCache cache;
+TEST_F(SoftwareImageDecodeCacheTest, DISABLED_ContentIdCaching) {
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kHigh;
PaintImage::Id stable_id = 1001;
@@ -1887,21 +1865,20 @@ TEST(SoftwareImageDecodeCacheTest, DISABLED_ContentIdCaching) {
CreateMatrix(SkSize::Make(scale, scale), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
DecodedDrawImage decoded_draw_image =
- cache.GetDecodedImageForDraw(draw_image);
+ cache_.GetDecodedImageForDraw(draw_image);
EXPECT_TRUE(decoded_draw_image.image());
- cache.DrawWithImageFinished(draw_image, decoded_draw_image);
+ cache_.DrawWithImageFinished(draw_image, decoded_draw_image);
}
// After the first two entries come in, we start evicting old content ids.
if (i == 0)
- EXPECT_LE(cache.GetNumCacheEntriesForTesting(), 2u);
+ EXPECT_LE(cache_.GetNumCacheEntriesForTesting(), 2u);
else
- EXPECT_LE(cache.GetNumCacheEntriesForTesting(), 4u);
+ EXPECT_LE(cache_.GetNumCacheEntriesForTesting(), 4u);
}
}
-TEST(SoftwareImageDecodeCacheTest, DecodeToScale) {
- TestSoftwareImageDecodeCache cache;
+TEST_F(SoftwareImageDecodeCacheTest, DecodeToScale) {
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kMedium;
@@ -1926,11 +1903,11 @@ TEST(SoftwareImageDecodeCacheTest, DecodeToScale) {
SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality,
CreateMatrix(SkSize::Make(0.5, 0.5), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
- DecodedDrawImage decoded_image1 = cache.GetDecodedImageForDraw(draw_image1);
+ DecodedDrawImage decoded_image1 = cache_.GetDecodedImageForDraw(draw_image1);
ASSERT_TRUE(decoded_image1.image());
EXPECT_EQ(decoded_image1.image()->width(), 50);
EXPECT_EQ(decoded_image1.image()->height(), 50);
- EXPECT_EQ(cache.GetNumCacheEntriesForTesting(), 1u);
+ EXPECT_EQ(cache_.GetNumCacheEntriesForTesting(), 1u);
// We should have requested a scaled decode from the generator.
ASSERT_EQ(generator->decode_infos().size(), 1u);
@@ -1944,11 +1921,11 @@ TEST(SoftwareImageDecodeCacheTest, DecodeToScale) {
SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality,
CreateMatrix(SkSize::Make(0.25, 0.25), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
- DecodedDrawImage decoded_image2 = cache.GetDecodedImageForDraw(draw_image2);
+ DecodedDrawImage decoded_image2 = cache_.GetDecodedImageForDraw(draw_image2);
ASSERT_TRUE(decoded_image2.image());
EXPECT_EQ(decoded_image2.image()->width(), 25);
EXPECT_EQ(decoded_image2.image()->height(), 25);
- EXPECT_EQ(cache.GetNumCacheEntriesForTesting(), 2u);
+ EXPECT_EQ(cache_.GetNumCacheEntriesForTesting(), 2u);
// Since we scaled from the existing entry, no new decodes should be
// requested from the generator.
@@ -1956,12 +1933,11 @@ TEST(SoftwareImageDecodeCacheTest, DecodeToScale) {
EXPECT_EQ(generator->decode_infos().at(0).width(), 50);
EXPECT_EQ(generator->decode_infos().at(0).height(), 50);
- cache.DrawWithImageFinished(draw_image1, decoded_image1);
- cache.DrawWithImageFinished(draw_image2, decoded_image2);
+ cache_.DrawWithImageFinished(draw_image1, decoded_image1);
+ cache_.DrawWithImageFinished(draw_image2, decoded_image2);
}
-TEST(SoftwareImageDecodeCacheTest, DecodeToScaleSubrect) {
- TestSoftwareImageDecodeCache cache;
+TEST_F(SoftwareImageDecodeCacheTest, DecodeToScaleSubrect) {
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kMedium;
@@ -1985,21 +1961,20 @@ TEST(SoftwareImageDecodeCacheTest, DecodeToScaleSubrect) {
CreateMatrix(SkSize::Make(0.5, 0.5), is_decomposable),
PaintImage::kDefaultFrameIndex,
DefaultTargetColorParams());
- DecodedDrawImage decoded_image = cache.GetDecodedImageForDraw(draw_image);
+ DecodedDrawImage decoded_image = cache_.GetDecodedImageForDraw(draw_image);
ASSERT_TRUE(decoded_image.image());
EXPECT_EQ(decoded_image.image()->width(), 25);
EXPECT_EQ(decoded_image.image()->height(), 25);
- EXPECT_EQ(cache.GetNumCacheEntriesForTesting(), 2u);
+ EXPECT_EQ(cache_.GetNumCacheEntriesForTesting(), 2u);
// We should have requested the original decode from the generator.
ASSERT_EQ(generator->decode_infos().size(), 1u);
EXPECT_EQ(generator->decode_infos().at(0).width(), 100);
EXPECT_EQ(generator->decode_infos().at(0).height(), 100);
- cache.DrawWithImageFinished(draw_image, decoded_image);
+ cache_.DrawWithImageFinished(draw_image, decoded_image);
}
-TEST(SoftwareImageDecodeCacheTest, DecodeToScaleNoneQuality) {
- TestSoftwareImageDecodeCache cache;
+TEST_F(SoftwareImageDecodeCacheTest, DecodeToScaleNoneQuality) {
bool is_decomposable = true;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kNone;
@@ -2022,7 +1997,7 @@ TEST(SoftwareImageDecodeCacheTest, DecodeToScaleNoneQuality) {
SkIRect::MakeWH(paint_image.width(), paint_image.height()), quality,
CreateMatrix(SkSize::Make(0.5, 0.5), is_decomposable),
PaintImage::kDefaultFrameIndex, DefaultTargetColorParams());
- DecodedDrawImage decoded_image = cache.GetDecodedImageForDraw(draw_image);
+ DecodedDrawImage decoded_image = cache_.GetDecodedImageForDraw(draw_image);
ASSERT_TRUE(decoded_image.image());
EXPECT_EQ(decoded_image.image()->width(), 100);
EXPECT_EQ(decoded_image.image()->height(), 100);
@@ -2031,12 +2006,10 @@ TEST(SoftwareImageDecodeCacheTest, DecodeToScaleNoneQuality) {
ASSERT_EQ(generator->decode_infos().size(), 1u);
EXPECT_EQ(generator->decode_infos().at(0).width(), 100);
EXPECT_EQ(generator->decode_infos().at(0).height(), 100);
- cache.DrawWithImageFinished(draw_image, decoded_image);
+ cache_.DrawWithImageFinished(draw_image, decoded_image);
}
-TEST(SoftwareImageDecodeCacheTest, HdrDecodeToHdr) {
- TestSoftwareImageDecodeCache cache;
-
+TEST_F(SoftwareImageDecodeCacheTest, HdrDecodeToHdr) {
const TargetColorParams target_color_params(gfx::ColorSpace::CreateHDR10());
auto size = SkISize::Make(100, 100);
auto info = SkImageInfo::Make(
@@ -2057,14 +2030,12 @@ TEST(SoftwareImageDecodeCacheTest, HdrDecodeToHdr) {
CreateMatrix(SkSize::Make(0.5, 0.5), true),
PaintImage::kDefaultFrameIndex, target_color_params);
- DecodedDrawImage decoded_image = cache.GetDecodedImageForDraw(draw_image);
+ DecodedDrawImage decoded_image = cache_.GetDecodedImageForDraw(draw_image);
EXPECT_EQ(decoded_image.image()->colorType(), kRGBA_F16_SkColorType);
- cache.DrawWithImageFinished(draw_image, decoded_image);
+ cache_.DrawWithImageFinished(draw_image, decoded_image);
}
-TEST(SoftwareImageDecodeCacheTest, HdrDecodeToSdr) {
- TestSoftwareImageDecodeCache cache;
-
+TEST_F(SoftwareImageDecodeCacheTest, HdrDecodeToSdr) {
auto image_color_space = gfx::ColorSpace::CreateHDR10();
auto size = SkISize::Make(100, 100);
auto info = SkImageInfo::Make(size.width(), size.height(),
@@ -2088,9 +2059,9 @@ TEST(SoftwareImageDecodeCacheTest, HdrDecodeToSdr) {
CreateMatrix(SkSize::Make(0.5, 0.5), true),
PaintImage::kDefaultFrameIndex, TargetColorParams(raster_color_space));
- DecodedDrawImage decoded_image = cache.GetDecodedImageForDraw(draw_image);
+ DecodedDrawImage decoded_image = cache_.GetDecodedImageForDraw(draw_image);
EXPECT_NE(decoded_image.image()->colorType(), kRGBA_F16_SkColorType);
- cache.DrawWithImageFinished(draw_image, decoded_image);
+ cache_.DrawWithImageFinished(draw_image, decoded_image);
}
} // namespace
diff --git a/chromium/cc/tiles/software_image_decode_cache_unittest_combinations.cc b/chromium/cc/tiles/software_image_decode_cache_unittest_combinations.cc
index 87c9902a0e5..f256fa70714 100644
--- a/chromium/cc/tiles/software_image_decode_cache_unittest_combinations.cc
+++ b/chromium/cc/tiles/software_image_decode_cache_unittest_combinations.cc
@@ -32,6 +32,9 @@ class BaseTest : public testing::Test {
public:
void SetUp() override {
cache_ = CreateCache();
+ *const_cast<ImageDecodeCache::ClientId*>(&image_cache_client_id_) =
+ cache_->GenerateClientId();
+ ASSERT_GT(image_cache_client_id_, 0u);
paint_image_ = CreatePaintImage(gfx::Size(512, 512));
}
@@ -54,6 +57,9 @@ class BaseTest : public testing::Test {
}
SoftwareImageDecodeCache& cache() { return *cache_; }
+ ImageDecodeCache::ClientId cache_client_id() const {
+ return image_cache_client_id_;
+ }
PaintImage& paint_image() { return paint_image_; }
protected:
@@ -75,6 +81,9 @@ class BaseTest : public testing::Test {
private:
std::unique_ptr<SoftwareImageDecodeCache> cache_;
+ // The id generated by ImageDecodeCache instance to identify this client
+ // instance when requesting image tasks.
+ const ImageDecodeCache::ClientId image_cache_client_id_ = 0;
PaintImage paint_image_;
};
@@ -122,8 +131,8 @@ class AtRaster : public virtual BaseTest {
class Predecode : public virtual BaseTest {
protected:
CacheEntryResult GenerateCacheEntry(const DrawImage& image) override {
- auto task_result =
- cache().GetTaskForImageAndRef(image, ImageDecodeCache::TracingInfo());
+ auto task_result = cache().GetTaskForImageAndRef(
+ cache_client_id(), image, ImageDecodeCache::TracingInfo());
CacheEntryResult result = {!!task_result.task, task_result.need_unref};
if (task_result.task)
diff --git a/chromium/cc/tiles/tile_manager_unittest.cc b/chromium/cc/tiles/tile_manager_unittest.cc
index e1b33629931..577bc42b261 100644
--- a/chromium/cc/tiles/tile_manager_unittest.cc
+++ b/chromium/cc/tiles/tile_manager_unittest.cc
@@ -13,9 +13,11 @@
#include "base/containers/contains.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
+#include "base/test/scoped_feature_list.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/process_memory_dump.h"
+#include "cc/base/features.h"
#include "cc/layers/recording_source.h"
#include "cc/raster/raster_buffer.h"
#include "cc/raster/raster_source.h"
@@ -378,6 +380,151 @@ TEST_F(TileManagerTilePriorityQueueTest, RasterTilePriorityQueue) {
}
TEST_F(TileManagerTilePriorityQueueTest,
+ RasterTilePriorityQueueAll_GetNextQueues) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(features::kRasterTilePriorityQueue);
+
+ host_impl()->AdvanceToNextFrame(base::Milliseconds(1));
+ gfx::Size layer_bounds(1000, 1000);
+ SetupDefaultTrees(layer_bounds);
+
+ // Create a pending child layer.
+ scoped_refptr<FakeRasterSource> pending_raster_source =
+ FakeRasterSource::CreateFilled(layer_bounds);
+ auto* pending_child = AddLayer<FakePictureLayerImpl>(
+ host_impl()->pending_tree(), pending_raster_source);
+ pending_child->SetDrawsContent(true);
+ CopyProperties(pending_layer(), pending_child);
+
+ // Set a small viewport, so we have soon and eventually tiles.
+ host_impl()->active_tree()->SetDeviceViewportRect(
+ gfx::Rect(100, 100, 200, 200));
+ host_impl()->AdvanceToNextFrame(base::Milliseconds(1));
+ UpdateDrawProperties(host_impl()->active_tree());
+ UpdateDrawProperties(host_impl()->pending_tree());
+ host_impl()->SetRequiresHighResToDraw();
+
+ // (1) SMOOTHNESS_TAKES_PRIORITY
+ {
+ std::unique_ptr<RasterTilePriorityQueue> queue(
+ host_impl()->BuildRasterQueue(SMOOTHNESS_TAKES_PRIORITY,
+ RasterTilePriorityQueue::Type::ALL));
+ EXPECT_FALSE(queue->IsEmpty());
+
+ TilePriority::PriorityBin last_bin = TilePriority::NOW;
+ WhichTree las_tree = WhichTree::ACTIVE_TREE;
+ float last_distance = 0.f;
+ while (!queue->IsEmpty()) {
+ PrioritizedTile prioritized_tile = queue->Top();
+ WhichTree tree = prioritized_tile.source_tiling()->tree();
+ TilePriority::PriorityBin priority_bin =
+ prioritized_tile.priority().priority_bin;
+ float distance_to_visible =
+ prioritized_tile.priority().distance_to_visible;
+
+ // Higher priority bin should come before lower priority bin regardless
+ // of the tree.
+ EXPECT_LE(last_bin, priority_bin);
+
+ // If SMOOTHNESS_TAKES_PRIORITY, ACTIVE_TREE comes before PENDING_TREE for
+ // NOW bin. The rest bins use the IsHigherPriorityThan condition.
+ if (priority_bin == TilePriority::NOW) {
+ EXPECT_LE(las_tree, tree);
+ } else {
+ // Reset the distance if it's in a different bin.
+ if (last_bin != priority_bin)
+ last_distance = 0;
+ if (las_tree != tree)
+ EXPECT_LE(last_distance, distance_to_visible);
+ }
+
+ last_bin = priority_bin;
+ las_tree = tree;
+ last_distance = distance_to_visible;
+ queue->Pop();
+ }
+ }
+
+ // (2) NEW_CONTENT_TAKES_PRIORITY
+ {
+ std::unique_ptr<RasterTilePriorityQueue> queue(
+ host_impl()->BuildRasterQueue(NEW_CONTENT_TAKES_PRIORITY,
+ RasterTilePriorityQueue::Type::ALL));
+ EXPECT_FALSE(queue->IsEmpty());
+
+ TilePriority::PriorityBin last_bin = TilePriority::NOW;
+ WhichTree las_tree = WhichTree::PENDING_TREE;
+ float last_distance = 0.f;
+ while (!queue->IsEmpty()) {
+ PrioritizedTile prioritized_tile = queue->Top();
+ WhichTree tree = prioritized_tile.source_tiling()->tree();
+ TilePriority::PriorityBin priority_bin =
+ prioritized_tile.priority().priority_bin;
+ float distance_to_visible =
+ prioritized_tile.priority().distance_to_visible;
+
+ // Higher priority bin should come before lower priority bin regardless
+ // of the tree.
+ EXPECT_LE(last_bin, priority_bin);
+
+ // If SMOOTHNESS_TAKES_PRIORITY, PENDING_TREE comes before ACTIVE_TREE for
+ // NOW bin. The rest bins use the IsHigherPriorityThan condition.
+ if (priority_bin == TilePriority::NOW) {
+ EXPECT_GE(las_tree, tree);
+ } else {
+ // Reset the distance if it's in a different bin.
+ if (last_bin != priority_bin)
+ last_distance = 0;
+ if (las_tree != tree)
+ EXPECT_LE(last_distance, distance_to_visible);
+ }
+
+ last_bin = priority_bin;
+ las_tree = tree;
+ last_distance = distance_to_visible;
+ queue->Pop();
+ }
+ }
+
+ // (3) SAME_PRIORITY_FOR_BOTH_TREES
+ {
+ std::unique_ptr<RasterTilePriorityQueue> queue(
+ host_impl()->BuildRasterQueue(SAME_PRIORITY_FOR_BOTH_TREES,
+ RasterTilePriorityQueue::Type::ALL));
+ EXPECT_FALSE(queue->IsEmpty());
+
+ TilePriority::PriorityBin last_bin = TilePriority::NOW;
+ WhichTree las_tree = WhichTree::PENDING_TREE;
+ float last_distance = 0.f;
+ while (!queue->IsEmpty()) {
+ PrioritizedTile prioritized_tile = queue->Top();
+ WhichTree tree = prioritized_tile.source_tiling()->tree();
+ TilePriority::PriorityBin priority_bin =
+ prioritized_tile.priority().priority_bin;
+ float distance_to_visible =
+ prioritized_tile.priority().distance_to_visible;
+
+ // Higher priority bin should come before lower priority bin regardless
+ // of the tree.
+ EXPECT_LE(last_bin, priority_bin);
+
+ // Reset the distance if it's in a different bin.
+ if (last_bin != priority_bin)
+ last_distance = 0;
+
+ // Use the IsHigherPriorityThan() condition.
+ if (las_tree != tree)
+ EXPECT_LE(last_distance, distance_to_visible);
+
+ last_bin = priority_bin;
+ las_tree = tree;
+ last_distance = distance_to_visible;
+ queue->Pop();
+ }
+ }
+}
+
+TEST_F(TileManagerTilePriorityQueueTest,
RasterTilePriorityQueueHighNonIdealTilings) {
const gfx::Size layer_bounds(1000, 1000);
const gfx::Size viewport(800, 800);
diff --git a/chromium/cc/trees/commit_state.h b/chromium/cc/trees/commit_state.h
index f0299dbd60b..b854dedb905 100644
--- a/chromium/cc/trees/commit_state.h
+++ b/chromium/cc/trees/commit_state.h
@@ -17,7 +17,6 @@
#include "cc/benchmarks/micro_benchmark_impl.h"
#include "cc/cc_export.h"
#include "cc/debug/layer_tree_debug_state.h"
-#include "cc/document_transition/document_transition_request.h"
#include "cc/input/event_listener_properties.h"
#include "cc/input/layer_selection_bound.h"
#include "cc/input/overscroll_behavior.h"
@@ -32,6 +31,7 @@
#include "cc/trees/presentation_time_callback_buffer.h"
#include "cc/trees/swap_promise.h"
#include "cc/trees/viewport_property_ids.h"
+#include "cc/view_transition/view_transition_request.h"
#include "components/viz/common/surfaces/local_surface_id.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/delegated_ink_metadata.h"
@@ -125,27 +125,35 @@ struct CC_EXPORT CommitState {
bool next_commit_forces_redraw = false;
uint64_t trace_id = 0;
EventMetrics::List event_metrics;
+
// Latency information for work done in ProxyMain::BeginMainFrame. The
// unique_ptr is allocated in RequestMainFrameUpdate, and passed to Blink's
// LocalFrameView that fills in the fields. This object adds the timing for
// UpdateLayers. CC reads the data during commit, and clears the unique_ptr.
std::unique_ptr<BeginMainFrameMetrics> begin_main_frame_metrics;
+
// Metadata required for drawing a delegated ink trail onto the end of a
// stroke. std::unique_ptr was specifically chosen so that it would be
// cleared as it is forwarded along the pipeline to avoid old information
// incorrectly sticking around and potentially being reused.
std::unique_ptr<gfx::DelegatedInkMetadata> delegated_ink_metadata;
+
std::unique_ptr<PendingPageScaleAnimation> pending_page_scale_animation;
std::vector<std::pair<int, std::unique_ptr<PaintImage>>> queued_image_decodes;
+
// Presentation time callbacks requested for the next frame are initially
// added here.
- std::vector<PresentationTimeCallbackBuffer::MainCallback>
- pending_presentation_time_callbacks;
+ std::vector<PresentationTimeCallbackBuffer::Callback>
+ pending_presentation_callbacks;
+ std::vector<PresentationTimeCallbackBuffer::SuccessfulCallback>
+ pending_successful_presentation_callbacks;
+
std::vector<std::unique_ptr<MicroBenchmarkImpl>> benchmarks;
- // A list of document transitions that need to be transported from Blink to
+
+ // A list of view transitions that need to be transported from Blink to
// Viz, as a CompositorFrameTransitionDirective.
- std::vector<std::unique_ptr<DocumentTransitionRequest>>
- document_transition_requests;
+ std::vector<std::unique_ptr<ViewTransitionRequest>> view_transition_requests;
+
std::vector<std::unique_ptr<SwapPromise>> swap_promises;
std::vector<UIResourceRequest> ui_resource_request_queue;
base::flat_map<UIResourceId, gfx::Size> ui_resource_sizes;
diff --git a/chromium/cc/trees/de_jelly_state.cc b/chromium/cc/trees/de_jelly_state.cc
deleted file mode 100644
index b9fe89494f5..00000000000
--- a/chromium/cc/trees/de_jelly_state.cc
+++ /dev/null
@@ -1,187 +0,0 @@
-// Copyright 2019 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/trees/de_jelly_state.h"
-
-#include <algorithm>
-#include <utility>
-
-#include "cc/trees/layer_tree_impl.h"
-#include "cc/trees/scroll_node.h"
-#include "cc/trees/transform_node.h"
-#include "components/viz/common/display/de_jelly.h"
-
-namespace cc {
-
-DeJellyState::DeJellyState() = default;
-DeJellyState::~DeJellyState() = default;
-
-void DeJellyState::AdvanceFrame(LayerTreeImpl* layer_tree_impl) {
- if (!layer_tree_impl->settings().allow_de_jelly_effect)
- return;
-
- should_de_jelly_ = false;
-
- // Move the |new_transforms_| from the previous draw into
- // |previous_transforms_|.
- std::swap(previous_transforms_, new_transforms_);
- new_transforms_.clear();
-
- // Make sure we have an active scroll node. Otherwise we won't perform any
- // de-jelly.
- const ScrollNode* current_scroll =
- layer_tree_impl->property_trees()->scroll_tree().Node(
- layer_tree_impl->property_trees()
- ->scroll_tree()
- .currently_scrolling_node());
- if (!current_scroll) {
- new_scroll_node_transform_.reset();
- return;
- }
-
- scroll_transform_node_ = current_scroll->transform_id;
-
- // Check to make sure the ToScreen transform of our scroll node is not a
- // complex transform (doesn't work well with de-jelly). Also make sure the
- // scale is not changing.
- absl::optional<gfx::Transform> previous_scroll_transform =
- new_scroll_node_transform_;
- new_scroll_node_transform_ =
- layer_tree_impl->property_trees()->transform_tree().ToScreen(
- current_scroll->transform_id);
- if (!previous_scroll_transform ||
- !previous_scroll_transform->IsScaleOrTranslation() ||
- !new_scroll_node_transform_->IsScaleOrTranslation() ||
- new_scroll_node_transform_->To2dScale() !=
- previous_scroll_transform->To2dScale()) {
- return;
- }
-
- // Compute the fallback movement of a scrolling element based purely on the
- // scroll offset of the currently scrolling node.
- float previous_scroll_offset = scroll_offset_;
- scroll_offset_ = layer_tree_impl->property_trees()
- ->transform_tree()
- .Node(scroll_transform_node_)
- ->scroll_offset.y();
- float scroll_delta = scroll_offset_ - previous_scroll_offset;
- fallback_delta_y_ =
- new_scroll_node_transform_->MapVector(gfx::Vector3dF(0, scroll_delta, 0))
- .y();
-
- // Don't attempt de-jelly while the omnibox is transitioning in or out. There
- // is no correct way to handle this.
- float top_controls_shown_ratio =
- layer_tree_impl->top_controls_shown_ratio()->Current(
- true /* is_active_tree */);
- if (top_controls_shown_ratio != 0.0f && top_controls_shown_ratio != 1.0f)
- return;
-
- // We've passed our initial checks, allow de-jelly in UpdateSharedQuadState.
- should_de_jelly_ = true;
-}
-
-void DeJellyState::UpdateSharedQuadState(
- LayerTreeImpl* layer_tree_impl,
- int transform_id,
- viz::CompositorRenderPass* target_render_pass) {
- if (!should_de_jelly_)
- return;
- DCHECK(layer_tree_impl->settings().allow_de_jelly_effect);
-
- viz::SharedQuadState* state =
- target_render_pass->shared_quad_state_list.back();
- state->de_jelly_delta_y = 0.0f;
-
- // Check if |transform_id| is a child of our |scroll_transform_node_|
- // and if it scrolls (is not sticky or fixed).
- bool does_not_scroll = false;
- auto node_id = transform_id;
- while (node_id != scroll_transform_node_ && node_id != kInvalidNodeId) {
- const auto* current_node =
- layer_tree_impl->property_trees()->transform_tree().Node(node_id);
-
- // Position fixed.
- if (current_node->moved_by_outer_viewport_bounds_delta_y) {
- does_not_scroll = true;
- break;
- }
- // Position sticky.
- if (current_node->sticky_position_constraint_id > -1) {
- const StickyPositionNodeData* sticky_data =
- layer_tree_impl->property_trees()
- ->transform_tree()
- .GetStickyPositionData(node_id);
- if (sticky_data &&
- sticky_data->total_containing_block_sticky_offset.y() > 0.0f) {
- does_not_scroll = true;
- break;
- }
- }
-
- node_id = current_node->parent_id;
- }
- does_not_scroll |= node_id == kInvalidNodeId;
- if (does_not_scroll)
- return;
-
- // Get the current node's ToScreen transform.
- gfx::Transform transform =
- layer_tree_impl->property_trees()->transform_tree().ToScreen(
- transform_id);
- new_transforms_[transform_id] = transform;
-
- // Get the previous transform (if any).
- const auto& found = previous_transforms_.find(transform_id);
-
- float delta_y = 0.0f;
- if (found == previous_transforms_.end()) {
- delta_y = fallback_delta_y_;
- } else {
- // Calculate the delta of point (0, 0) from the previous frame.
- gfx::Transform previous_transform = found->second;
- gfx::PointF new_point = transform.MapPoint(gfx::PointF(0, 0));
- gfx::PointF old_point = previous_transform.MapPoint(gfx::PointF(0, 0));
- delta_y = old_point.y() - new_point.y();
- }
-
- if (delta_y == 0.0f) {
- return;
- }
-
- // To minimize jarring visible effects, we de-jelly differently at
- // different magnitudes of |delta_y|. This is controlled by three variables:
- // kLinearDeJellyStart, kFixedDeJellyStart, kZeroDeJellyStart.
- // _____________
- // | | _/| |
- // de_jelly_delta_y | | _/ | |
- // |_____|_/ | |_______________
- // +----------------------------------------
- // kLinear kFixed kZero
- //
- const float kLinearDeJellyStart = 2.0f;
- const float kFixedDeJellyStart =
- viz::MaxDeJellyHeight() + kLinearDeJellyStart;
- const float kZeroDeJellyStart = 100.0f + kLinearDeJellyStart;
- float sign = std::abs(delta_y) / delta_y;
- float de_jelly_delta_y = std::abs(delta_y);
- if (de_jelly_delta_y > kZeroDeJellyStart) {
- de_jelly_delta_y = 0.0f;
- } else if (de_jelly_delta_y > kFixedDeJellyStart) {
- de_jelly_delta_y = kFixedDeJellyStart - kLinearDeJellyStart;
- } else if (de_jelly_delta_y > kLinearDeJellyStart) {
- de_jelly_delta_y = std::max(0.0f, de_jelly_delta_y - kLinearDeJellyStart);
- } else {
- de_jelly_delta_y = 0.0f;
- }
- // Re-apply the sign.
- de_jelly_delta_y *= sign;
- if (de_jelly_delta_y == 0.0f) {
- return;
- }
-
- state->de_jelly_delta_y = de_jelly_delta_y;
-}
-
-} // namespace cc
diff --git a/chromium/cc/trees/de_jelly_state.h b/chromium/cc/trees/de_jelly_state.h
deleted file mode 100644
index 934b019066f..00000000000
--- a/chromium/cc/trees/de_jelly_state.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2019 The Chromium Authors
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_TREES_DE_JELLY_STATE_H_
-#define CC_TREES_DE_JELLY_STATE_H_
-
-#include <map>
-
-#include "cc/cc_export.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
-#include "ui/gfx/geometry/transform.h"
-
-namespace viz {
-class SharedQuadState;
-class CompositorRenderPass;
-} // namespace viz
-
-namespace cc {
-class LayerTreeImpl;
-
-// Helper class which tracks the movement of layers and renderpasses
-// and computes the |de_jelly_delta_y| for their SharedQuadState.
-class CC_EXPORT DeJellyState {
- public:
- DeJellyState();
- ~DeJellyState();
-
- // Called once per frame to move tracking structure to the next frame and
- // determine if we should apply de-jelly at all.
- void AdvanceFrame(LayerTreeImpl* layer_tree_impl);
-
- // Populates |de_jelly_delta_y| for the most recent SharedQuadState on
- // |target_render_pass|.
- void UpdateSharedQuadState(LayerTreeImpl* layer_tree_impl,
- int transform_id,
- viz::CompositorRenderPass* target_render_pass);
-
- private:
- bool should_de_jelly_ = false;
- int scroll_transform_node_ = 0;
- float scroll_offset_ = 0;
- float fallback_delta_y_ = 0;
-
- absl::optional<gfx::Transform> new_scroll_node_transform_;
- std::map<int, gfx::Transform> previous_transforms_;
- std::map<int, gfx::Transform> new_transforms_;
-};
-
-} // namespace cc
-
-#endif // CC_TREES_DE_JELLY_STATE_H_
diff --git a/chromium/cc/trees/draw_properties_unittest.cc b/chromium/cc/trees/draw_properties_unittest.cc
index 6317fba7a8b..fd3b0d49a41 100644
--- a/chromium/cc/trees/draw_properties_unittest.cc
+++ b/chromium/cc/trees/draw_properties_unittest.cc
@@ -286,7 +286,7 @@ TEST_F(DrawPropertiesTest, TransformsForSingleLayer) {
gfx::Transform translation_to_anchor;
translation_to_anchor.Translate(5.0, 0.0);
gfx::Transform expected_result = translation_to_anchor * layer_transform *
- gfx::InvertAndCheck(translation_to_anchor);
+ translation_to_anchor.GetCheckedInverse();
SetTransformOrigin(layer, gfx::Point3F(5.f, 0.f, 0.f));
UpdateActiveTreeDrawProperties();
EXPECT_TRANSFORM_EQ(expected_result, draw_property_utils::DrawTransform(
@@ -299,8 +299,7 @@ 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 *
- gfx::InvertAndCheck(translation_to_anchor);
+ layer_transform * translation_to_anchor.GetCheckedInverse();
SetPostTranslation(layer, gfx::Vector2dF(0.f, 1.2f));
UpdateActiveTreeDrawProperties();
EXPECT_TRANSFORM_EQ(expected_result, draw_property_utils::DrawTransform(
@@ -454,7 +453,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 *
- gfx::InvertAndCheck(parent_translation_to_anchor);
+ parent_translation_to_anchor.GetCheckedInverse();
SetTransform(parent, parent_layer_transform);
SetPostTranslation(parent, gfx::Vector2dF());
UpdateActiveTreeDrawProperties();
@@ -485,7 +484,7 @@ TEST_F(DrawPropertiesTest, TransformsForSingleRenderSurface) {
gfx::Transform parent_composite_transform =
parent_translation_to_anchor * parent_layer_transform *
- gfx::InvertAndCheck(parent_translation_to_anchor);
+ parent_translation_to_anchor.GetCheckedInverse();
gfx::Vector2dF parent_composite_scale =
gfx::ComputeTransform2dScaleComponents(parent_composite_transform, 1.f);
gfx::Transform surface_sublayer_transform;
@@ -493,7 +492,7 @@ TEST_F(DrawPropertiesTest, TransformsForSingleRenderSurface) {
parent_composite_scale.y());
gfx::Transform surface_sublayer_composite_transform =
parent_composite_transform *
- gfx::InvertAndCheck(surface_sublayer_transform);
+ surface_sublayer_transform.GetCheckedInverse();
root->SetBounds(gfx::Size(1, 2));
parent->SetBounds(gfx::Size(100, 120));
@@ -573,7 +572,7 @@ TEST_F(DrawPropertiesTest, TransformsForRenderSurfaceHierarchy) {
layer_transform.Translate(1.0, 1.0);
gfx::Transform A = translation_to_anchor * layer_transform *
- gfx::InvertAndCheck(translation_to_anchor);
+ translation_to_anchor.GetCheckedInverse();
gfx::Vector2dF surface1_parent_transform_scale =
gfx::ComputeTransform2dScaleComponents(A, 1.f);
@@ -585,7 +584,7 @@ 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 = gfx::InvertAndCheck(surface1_sublayer_transform);
+ gfx::Transform S1 = surface1_sublayer_transform.GetCheckedInverse();
gfx::Vector2dF surface2_parent_transform_scale =
gfx::ComputeTransform2dScaleComponents(SS1 * A, 1.f);
@@ -597,7 +596,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 = gfx::InvertAndCheck(surface2_sublayer_transform);
+ gfx::Transform S2 = surface2_sublayer_transform.GetCheckedInverse();
root->SetBounds(gfx::Size(1, 2));
parent->SetBounds(gfx::Size(10, 10));
@@ -783,14 +782,9 @@ TEST_F(DrawPropertiesTest, LayerFullyContainedWithinClipInTargetSpace) {
UpdateActiveTreeDrawProperties();
- // Mapping grand_child's bounds to screen space produces an empty rect, but
- // only because it is turned sideways. The entire rect is contained inside
- // the clip, and is only empty so long as the numerical precision of the
- // transform is effectively perfect. Currently we do the calculation the
- // other way around, and the Projection of the screen space clip into layer
- // space includes the entire bounds.
- EXPECT_EQ(gfx::Rect(grand_child->bounds()),
- grand_child->visible_layer_rect());
+ // Mapping grand_child's bounds to screen space produces an empty rect
+ // because it is turned sideways.
+ EXPECT_EQ(gfx::Rect(), grand_child->visible_layer_rect());
}
TEST_F(DrawPropertiesTest, TransformsForDegenerateIntermediateLayer) {
@@ -2039,7 +2033,7 @@ TEST_F(DrawPropertiesDrawRectsTest, DrawRectsFor3dPerspectiveWhenClippedByW) {
static bool ProjectionClips(const gfx::Transform& map_transform,
const gfx::RectF& mapped_rect) {
- gfx::Transform inverse(gfx::InvertAndCheck(map_transform));
+ gfx::Transform inverse = map_transform.GetCheckedInverse();
bool clipped = false;
if (!clipped)
MathUtil::ProjectPoint(inverse, mapped_rect.top_right(), &clipped);
@@ -2416,11 +2410,9 @@ TEST_F(DrawPropertiesTest,
LayerImpl* child = AddLayer<LayerImpl>();
LayerImpl* grand_child = AddLayer<LayerImpl>();
- gfx::Transform perspective;
- perspective.ApplyPerspectiveDepth(SkDoubleToScalar(1e-12));
-
- gfx::Transform rotation;
- rotation.RotateAboutYAxis(45.0);
+ gfx::Transform scale = gfx::Transform::MakeScale(1e-15);
+ EXPECT_TRUE(scale.IsInvertible());
+ EXPECT_FALSE((scale * scale).IsInvertible());
root->SetBounds(gfx::Size(100, 100));
child->SetBounds(gfx::Size(100, 100));
@@ -2433,12 +2425,12 @@ TEST_F(DrawPropertiesTest,
child_transform_node.flattens_inherited_transform = false;
child_transform_node.post_translation = gfx::Vector2dF(10.f, 10.f);
child_transform_node.sorting_context_id = 1;
- child_transform_node.local = perspective;
+ child_transform_node.local = scale;
CopyProperties(child, grand_child);
auto& grand_child_transform_node = CreateTransformNode(grand_child);
grand_child_transform_node.flattens_inherited_transform = false;
grand_child_transform_node.sorting_context_id = 1;
- grand_child_transform_node.local = rotation;
+ grand_child_transform_node.local = scale;
UpdateActiveTreeDrawProperties();
@@ -2544,11 +2536,9 @@ TEST_F(DrawPropertiesTest, OcclusionForLayerWithUninvertibleDrawTransform) {
LayerImpl* grand_child = AddLayer<LayerImpl>();
LayerImpl* occluding_child = AddLayer<LayerImpl>();
- gfx::Transform perspective;
- perspective.ApplyPerspectiveDepth(SkDoubleToScalar(1e-12));
-
- gfx::Transform rotation;
- rotation.RotateAboutYAxis(45.0);
+ gfx::Transform scale = gfx::Transform::MakeScale(1e-15);
+ EXPECT_TRUE(scale.IsInvertible());
+ EXPECT_FALSE((scale * scale).IsInvertible());
root->SetBounds(gfx::Size(1000, 1000));
child->SetBounds(gfx::Size(300, 300));
@@ -2565,12 +2555,12 @@ TEST_F(DrawPropertiesTest, OcclusionForLayerWithUninvertibleDrawTransform) {
child_transform_node.flattens_inherited_transform = false;
child_transform_node.post_translation = gfx::Vector2dF(10.f, 10.f);
child_transform_node.sorting_context_id = 1;
- child_transform_node.local = perspective;
+ child_transform_node.local = scale;
CopyProperties(child, grand_child);
auto& grand_child_transform_node = CreateTransformNode(grand_child);
grand_child_transform_node.flattens_inherited_transform = false;
grand_child_transform_node.sorting_context_id = 1;
- grand_child_transform_node.local = rotation;
+ grand_child_transform_node.local = scale;
CopyProperties(root, occluding_child);
CreateTransformNode(occluding_child).flattens_inherited_transform = false;
@@ -3357,14 +3347,16 @@ TEST_F(DrawPropertiesScalingTest, SmallIdealScale) {
float expected_ideal_scale =
device_scale_factor * page_scale_factor * initial_parent_scale;
EXPECT_LT(expected_ideal_scale, 1.f);
- EXPECT_EQ(gfx::Vector2dF(expected_ideal_scale, expected_ideal_scale),
- parent->GetIdealContentsScale());
+ EXPECT_VECTOR2DF_EQ(
+ gfx::Vector2dF(expected_ideal_scale, expected_ideal_scale),
+ parent->GetIdealContentsScale());
expected_ideal_scale = device_scale_factor * page_scale_factor *
initial_parent_scale * initial_child_scale;
EXPECT_LT(expected_ideal_scale, 1.f);
- EXPECT_EQ(gfx::Vector2dF(expected_ideal_scale, expected_ideal_scale),
- child_scale->GetIdealContentsScale());
+ EXPECT_VECTOR2DF_EQ(
+ gfx::Vector2dF(expected_ideal_scale, expected_ideal_scale),
+ child_scale->GetIdealContentsScale());
}
TEST_F(DrawPropertiesScalingTest, IdealScaleForAnimatingLayer) {
diff --git a/chromium/cc/trees/draw_property_utils.cc b/chromium/cc/trees/draw_property_utils.cc
index f446d274017..f2baa453b99 100644
--- a/chromium/cc/trees/draw_property_utils.cc
+++ b/chromium/cc/trees/draw_property_utils.cc
@@ -32,8 +32,7 @@
#include "cc/trees/scroll_node.h"
#include "cc/trees/transform_node.h"
#include "cc/trees/viewport_property_ids.h"
-#include "components/viz/common/display/de_jelly.h"
-#include "components/viz/common/shared_element_resource_id.h"
+#include "components/viz/common/view_transition_element_resource_id.h"
#include "ui/gfx/geometry/rect_conversions.h"
namespace cc {
@@ -711,13 +710,6 @@ gfx::Rect LayerVisibleRect(PropertyTrees* property_trees, LayerImpl* layer) {
clip_in_layer_space.Offset(-layer->offset_to_transform_parent());
gfx::Rect visible_rect = ToEnclosingClipRect(clip_in_layer_space);
- if (layer->layer_tree_impl()->settings().allow_de_jelly_effect) {
- float padding_amount = viz::MaxDeJellyHeight();
- if (layer->IsAffectedByPageScale()) {
- padding_amount /= layer->layer_tree_impl()->current_page_scale_factor();
- }
- visible_rect.Inset(gfx::Insets::VH(-padding_amount, 0.0f));
- }
visible_rect.Intersect(layer_content_rect);
return visible_rect;
}
@@ -1161,39 +1153,23 @@ void RecordRenderSurfaceReasonsForTracing(
void UpdateElasticOverscroll(
PropertyTrees* property_trees,
TransformNode* overscroll_elasticity_transform_node,
- ElementId overscroll_elasticity_effect_element_id,
const gfx::Vector2dF& elastic_overscroll,
const ScrollNode* inner_viewport) {
-#if BUILDFLAG(IS_ANDROID)
- // On android, elastic overscroll is implemented by stretching the content
- // from the overscrolled edge.
- if (!overscroll_elasticity_effect_element_id &&
- !overscroll_elasticity_transform_node) {
+ if (!overscroll_elasticity_transform_node) {
DCHECK(elastic_overscroll.IsZero());
return;
}
- if (overscroll_elasticity_effect_element_id) {
- if (elastic_overscroll.IsZero() || !inner_viewport) {
- property_trees->effect_tree_mutable().OnFilterAnimated(
- overscroll_elasticity_effect_element_id, FilterOperations());
- return;
- }
- // The inner viewport container size takes into account the size change as a
- // result of the top controls, see ScrollTree::container_bounds.
- gfx::Size scroller_size =
- property_trees->scroll_tree().container_bounds(inner_viewport->id);
-
- property_trees->effect_tree_mutable().OnFilterAnimated(
- overscroll_elasticity_effect_element_id,
- FilterOperations(
- std::vector<FilterOperation>({FilterOperation::CreateStretchFilter(
- -elastic_overscroll.x() / scroller_size.width(),
- -elastic_overscroll.y() / scroller_size.height())})));
+#if BUILDFLAG(IS_ANDROID)
+ if (inner_viewport && property_trees->scroll_tree()
+ .container_bounds(inner_viewport->id)
+ .IsEmpty()) {
+ // Avoid divide by 0. Animation should not be visible for an empty viewport
+ // anyway.
return;
}
- // If there is no overscroll elasticity effect node, we apply a stretch
- // transform.
+ // On android, elastic overscroll is implemented by stretching the content
+ // from the overscrolled edge by applying a stretch transform
overscroll_elasticity_transform_node->local.MakeIdentity();
overscroll_elasticity_transform_node->origin.SetPoint(0.f, 0.f, 0.f);
if (base::FeatureList::IsEnabled(
@@ -1228,11 +1204,8 @@ void UpdateElasticOverscroll(
}
overscroll_elasticity_transform_node->needs_local_transform_update = true;
property_trees->transform_tree_mutable().set_needs_update(true);
+
#else // BUILDFLAG(IS_ANDROID)
- if (!overscroll_elasticity_transform_node) {
- DCHECK(elastic_overscroll.IsZero());
- return;
- }
// On other platforms, we modify the translation offset to match the
// overscroll amount.
@@ -1255,7 +1228,6 @@ void ComputeDrawPropertiesOfVisibleLayers(const LayerImplList* layer_list,
for (LayerImpl* layer : *layer_list) {
const TransformNode* transform_node =
property_trees->transform_tree().Node(layer->transform_tree_index());
-
layer->draw_properties().screen_space_transform =
ScreenSpaceTransformInternal(layer, property_trees->transform_tree());
layer->draw_properties().target_space_transform = DrawTransform(
@@ -1275,6 +1247,7 @@ void ComputeDrawPropertiesOfVisibleLayers(const LayerImplList* layer_list,
for (LayerImpl* layer : *layer_list) {
layer->draw_properties().opacity =
LayerDrawOpacity(layer, property_trees->effect_tree());
+
RenderSurfaceImpl* render_target = layer->render_target();
int lca_clip_id = LowestCommonAncestor(layer->clip_tree_index(),
render_target->ClipTreeIndex(),
@@ -1313,6 +1286,13 @@ void ComputeDrawPropertiesOfVisibleLayers(const LayerImplList* layer_list,
LayerDrawableContentRect(layer, visible_bounds_in_target_space,
layer->draw_properties().clip_rect);
}
+
+ // Make sure that the layers push their properties. This isn't necessary for
+ // picture layers that always push their properties, but is important for
+ // other layers to invalidate the active tree.
+ for (LayerImpl* layer : *layer_list) {
+ layer->SetNeedsPushProperties();
+ }
}
#if DCHECK_IS_ON()
@@ -1565,11 +1545,10 @@ void CalculateDrawProperties(
UpdatePageScaleFactor(property_trees,
layer_tree_impl->PageScaleTransformNode(),
layer_tree_impl->current_page_scale_factor());
- UpdateElasticOverscroll(
- property_trees, layer_tree_impl->OverscrollElasticityTransformNode(),
- layer_tree_impl->OverscrollElasticityEffectElementId(),
- layer_tree_impl->current_elastic_overscroll(),
- layer_tree_impl->InnerViewportScrollNode());
+ UpdateElasticOverscroll(property_trees,
+ layer_tree_impl->OverscrollElasticityTransformNode(),
+ layer_tree_impl->current_elastic_overscroll(),
+ layer_tree_impl->InnerViewportScrollNode());
// Similarly, the device viewport and device transform are shared
// by both trees.
property_trees->clip_tree_mutable().SetViewportClip(
diff --git a/chromium/cc/trees/effect_node.cc b/chromium/cc/trees/effect_node.cc
index e2e0dfb1aec..5a151b447d2 100644
--- a/chromium/cc/trees/effect_node.cc
+++ b/chromium/cc/trees/effect_node.cc
@@ -153,8 +153,8 @@ const char* RenderSurfaceReasonToString(RenderSurfaceReason reason) {
return "mirrored";
case RenderSurfaceReason::kSubtreeIsBeingCaptured:
return "subtree being captured";
- case RenderSurfaceReason::kDocumentTransitionParticipant:
- return "document transition participant";
+ case RenderSurfaceReason::kViewTransitionParticipant:
+ return "view transition participant";
case RenderSurfaceReason::kTest:
return "test";
default:
diff --git a/chromium/cc/trees/effect_node.h b/chromium/cc/trees/effect_node.h
index 77d3e52d398..4c305773c19 100644
--- a/chromium/cc/trees/effect_node.h
+++ b/chromium/cc/trees/effect_node.h
@@ -6,11 +6,11 @@
#define CC_TREES_EFFECT_NODE_H_
#include "cc/cc_export.h"
-#include "cc/document_transition/document_transition_shared_element_id.h"
#include "cc/paint/element_id.h"
#include "cc/paint/filter_operations.h"
-#include "components/viz/common/shared_element_resource_id.h"
+#include "cc/view_transition/view_transition_shared_element_id.h"
#include "components/viz/common/surfaces/subtree_capture_id.h"
+#include "components/viz/common/view_transition_element_resource_id.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/skia/include/core/SkBlendMode.h"
#include "ui/gfx/geometry/mask_filter_info.h"
@@ -50,7 +50,7 @@ enum class RenderSurfaceReason : uint8_t {
kCopyRequest,
kMirrored,
kSubtreeIsBeingCaptured,
- kDocumentTransitionParticipant,
+ kViewTransitionParticipant,
kGradientMask,
// This must be the last value because it's used in tracing code to know the
// number of reasons.
@@ -168,12 +168,12 @@ struct CC_EXPORT EffectNode {
int closest_ancestor_being_captured_id;
int closest_ancestor_with_shared_element_id;
- // Represents a shared element id for the document transition API.
- DocumentTransitionSharedElementId document_transition_shared_element_id;
+ // Represents a DOM element id for the view transition API.
+ ViewTransitionElementId view_transition_shared_element_id;
// Represents a resource id for a resource cached or generated in the Viz
// process.
- viz::SharedElementResourceId shared_element_resource_id;
+ viz::ViewTransitionElementResourceId view_transition_element_resource_id;
bool HasRenderSurface() const {
return render_surface_reason != RenderSurfaceReason::kNone;
diff --git a/chromium/cc/trees/image_animation_controller_unittest.cc b/chromium/cc/trees/image_animation_controller_unittest.cc
index c7cafdc7fbe..6403fb53580 100644
--- a/chromium/cc/trees/image_animation_controller_unittest.cc
+++ b/chromium/cc/trees/image_animation_controller_unittest.cc
@@ -5,12 +5,13 @@
#include "cc/trees/image_animation_controller.h"
#include <memory>
+#include <utility>
#include "base/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
+#include "base/task/single_thread_task_runner.h"
#include "base/test/gtest_util.h"
-#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -76,8 +77,8 @@ class ImageAnimationControllerTest : public testing::Test,
public ImageAnimationController::Client {
public:
void SetUp() override {
- task_runner_ =
- new DelayTrackingTaskRunner(base::ThreadTaskRunnerHandle::Get().get());
+ task_runner_ = new DelayTrackingTaskRunner(
+ base::SingleThreadTaskRunner::GetCurrentDefault().get());
controller_ = std::make_unique<ImageAnimationController>(
task_runner_.get(), this, GetEnableImageAnimationResync());
controller_->set_now_callback_for_testing(base::BindRepeating(
diff --git a/chromium/cc/trees/latency_info_swap_promise.cc b/chromium/cc/trees/latency_info_swap_promise.cc
index 6f0a408b1f6..e5ea05955aa 100644
--- a/chromium/cc/trees/latency_info_swap_promise.cc
+++ b/chromium/cc/trees/latency_info_swap_promise.cc
@@ -7,6 +7,7 @@
#include <stdint.h>
#include "base/check.h"
+#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "services/tracing/public/cpp/perfetto/flow_event_utils.h"
#include "services/tracing/public/cpp/perfetto/macros.h"
@@ -26,7 +27,8 @@ void LatencyInfoSwapPromise::WillSwap(viz::CompositorFrameMetadata* metadata) {
void LatencyInfoSwapPromise::DidSwap() {}
SwapPromise::DidNotSwapAction LatencyInfoSwapPromise::DidNotSwap(
- DidNotSwapReason reason) {
+ DidNotSwapReason reason,
+ base::TimeTicks ts) {
latency_.Terminate();
// TODO(miletus): Turn this back on once per-event LatencyInfo tracking
// is enabled in GPU side.
@@ -43,7 +45,7 @@ void LatencyInfoSwapPromise::OnCommit() {
using perfetto::protos::pbzero::ChromeLatencyInfo;
using perfetto::protos::pbzero::TrackEvent;
- TRACE_EVENT("input,benchmark", "LatencyInfo.Flow",
+ TRACE_EVENT("input,benchmark,latencyInfo", "LatencyInfo.Flow",
[this](perfetto::EventContext ctx) {
ChromeLatencyInfo* latency_info =
ctx.event()->set_chrome_latency_info();
diff --git a/chromium/cc/trees/latency_info_swap_promise.h b/chromium/cc/trees/latency_info_swap_promise.h
index feb0c49638f..5cc1d7c6941 100644
--- a/chromium/cc/trees/latency_info_swap_promise.h
+++ b/chromium/cc/trees/latency_info_swap_promise.h
@@ -8,6 +8,7 @@
#include <stdint.h>
#include "base/compiler_specific.h"
+#include "base/time/time.h"
#include "cc/trees/swap_promise.h"
#include "ui/latency/latency_info.h"
@@ -27,7 +28,8 @@ class CC_EXPORT LatencyInfoSwapPromise : public SwapPromise {
void DidActivate() override {}
void WillSwap(viz::CompositorFrameMetadata* metadata) override;
void DidSwap() override;
- DidNotSwapAction DidNotSwap(DidNotSwapReason reason) override;
+ DidNotSwapAction DidNotSwap(DidNotSwapReason reason,
+ base::TimeTicks ts) override;
void OnCommit() override;
int64_t GetTraceId() const override;
diff --git a/chromium/cc/trees/layer_tree_frame_sink.cc b/chromium/cc/trees/layer_tree_frame_sink.cc
index 698fe1cc74b..d3b76265a4c 100644
--- a/chromium/cc/trees/layer_tree_frame_sink.cc
+++ b/chromium/cc/trees/layer_tree_frame_sink.cc
@@ -76,7 +76,7 @@ bool LayerTreeFrameSink::BindToClient(LayerTreeFrameSinkClient* client) {
if (context_provider_) {
context_provider_->AddObserver(this);
- auto result = context_provider_->BindToCurrentThread();
+ auto result = context_provider_->BindToCurrentSequence();
if (result != gpu::ContextResult::kSuccess) {
context_provider_->RemoveObserver(this);
context_provider_ = nullptr;
diff --git a/chromium/cc/trees/layer_tree_frame_sink_client.h b/chromium/cc/trees/layer_tree_frame_sink_client.h
index 7d0ca42fd17..7c886a1201e 100644
--- a/chromium/cc/trees/layer_tree_frame_sink_client.h
+++ b/chromium/cc/trees/layer_tree_frame_sink_client.h
@@ -8,7 +8,6 @@
#include <vector>
#include "base/callback.h"
-#include "base/memory/ref_counted.h"
#include "cc/cc_export.h"
#include "components/viz/common/resources/returned_resource.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
diff --git a/chromium/cc/trees/layer_tree_host.cc b/chromium/cc/trees/layer_tree_host.cc
index 6432697d59b..55295cc3f1e 100644
--- a/chromium/cc/trees/layer_tree_host.cc
+++ b/chromium/cc/trees/layer_tree_host.cc
@@ -36,7 +36,6 @@
#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"
@@ -68,6 +67,7 @@
#include "cc/trees/transform_node.h"
#include "cc/trees/tree_synchronizer.h"
#include "cc/trees/ukm_manager.h"
+#include "cc/view_transition/view_transition_request.h"
#include "components/viz/common/features.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "services/metrics/public/cpp/ukm_recorder.h"
@@ -506,11 +506,11 @@ void LayerTreeHost::NotifyTransitionRequestsFinished(
// TODO(vmpstr): This might also be a good spot to expire long standing
// requests if they were not finished.
for (auto& sequence_id : sequence_ids) {
- auto it = document_transition_callbacks_.find(sequence_id);
- if (it == document_transition_callbacks_.end())
+ auto it = view_transition_callbacks_.find(sequence_id);
+ if (it == view_transition_callbacks_.end())
continue;
std::move(it->second).Run();
- document_transition_callbacks_.erase(it);
+ view_transition_callbacks_.erase(it);
}
}
@@ -724,6 +724,10 @@ void LayerTreeHost::SetNeedsCommit() {
events_metrics_manager_.SaveActiveEventMetrics();
}
+void LayerTreeHost::OnCommitRequested() {
+ client_->OnCommitRequested();
+}
+
void LayerTreeHost::SetTargetLocalSurfaceId(
const viz::LocalSurfaceId& target_local_surface_id) {
DCHECK(IsMainThread());
@@ -847,11 +851,16 @@ bool LayerTreeHost::UpdateLayers() {
void LayerTreeHost::DidPresentCompositorFrame(
uint32_t frame_token,
- std::vector<PresentationTimeCallbackBuffer::MainCallback> callbacks,
+ std::vector<PresentationTimeCallbackBuffer::Callback>
+ presentation_callbacks,
+ std::vector<PresentationTimeCallbackBuffer::SuccessfulCallback>
+ successful_presentation_callbacks,
const gfx::PresentationFeedback& feedback) {
DCHECK(IsMainThread());
- for (auto& callback : callbacks)
+ for (auto& callback : presentation_callbacks)
std::move(callback).Run(feedback);
+ for (auto& callback : successful_presentation_callbacks)
+ std::move(callback).Run(feedback.timestamp);
client_->DidPresentCompositorFrame(frame_token, feedback);
}
@@ -891,15 +900,15 @@ void LayerTreeHost::DidObserveFirstScrollDelay(
first_scroll_timestamp);
}
-void LayerTreeHost::AddDocumentTransitionRequest(
- std::unique_ptr<DocumentTransitionRequest> request) {
+void LayerTreeHost::AddViewTransitionRequest(
+ std::unique_ptr<ViewTransitionRequest> request) {
// Store the commit callback on LayerTreeHost, so that we can invoke them
// when the request is finished.
- DCHECK(
- !base::Contains(document_transition_callbacks_, request->sequence_id()));
- document_transition_callbacks_[request->sequence_id()] =
- request->TakeFinishedCallback();
- pending_commit_state()->document_transition_requests.push_back(
+ DCHECK(!base::Contains(view_transition_callbacks_, request->sequence_id()));
+ if (auto callback = request->TakeFinishedCallback()) {
+ view_transition_callbacks_[request->sequence_id()] = std::move(callback);
+ }
+ pending_commit_state()->view_transition_requests.push_back(
std::move(request));
SetNeedsCommit();
}
@@ -1157,11 +1166,6 @@ void LayerTreeHost::NotifyThroughputTrackerResults(
client_->NotifyThroughputTrackerResults(std::move(results));
}
-void LayerTreeHost::ReportEventLatency(
- std::vector<EventLatencyTracker::LatencyData> latencies) {
- client_->ReportEventLatency(std::move(latencies));
-}
-
const base::WeakPtr<CompositorDelegateForInput>&
LayerTreeHost::GetDelegateForInput() const {
DCHECK(IsMainThread());
@@ -1248,8 +1252,14 @@ bool LayerTreeHost::IsThreaded() const {
}
void LayerTreeHost::RequestPresentationTimeForNextFrame(
- PresentationTimeCallbackBuffer::MainCallback callback) {
- pending_commit_state()->pending_presentation_time_callbacks.push_back(
+ PresentationTimeCallbackBuffer::Callback callback) {
+ pending_commit_state()->pending_presentation_callbacks.push_back(
+ std::move(callback));
+}
+
+void LayerTreeHost::RequestSuccessfulPresentationTimeForNextFrame(
+ PresentationTimeCallbackBuffer::SuccessfulCallback callback) {
+ pending_commit_state()->pending_successful_presentation_callbacks.push_back(
std::move(callback));
}
@@ -2022,12 +2032,12 @@ void LayerTreeHost::SetDelegatedInkMetadata(
}
std::vector<base::OnceClosure>
-LayerTreeHost::TakeDocumentTransitionCallbacksForTesting() {
+LayerTreeHost::TakeViewTransitionCallbacksForTesting() {
DCHECK(IsMainThread());
std::vector<base::OnceClosure> result;
- for (auto& item : document_transition_callbacks_)
+ for (auto& item : view_transition_callbacks_)
result.push_back(std::move(item.second));
- document_transition_callbacks_.clear();
+ view_transition_callbacks_.clear();
return result;
}
diff --git a/chromium/cc/trees/layer_tree_host.h b/chromium/cc/trees/layer_tree_host.h
index fa05133349c..c26301594ab 100644
--- a/chromium/cc/trees/layer_tree_host.h
+++ b/chromium/cc/trees/layer_tree_host.h
@@ -74,7 +74,7 @@ struct PresentationFeedback;
namespace cc {
-class DocumentTransitionRequest;
+class ViewTransitionRequest;
class HeadsUpDisplayLayer;
class LayerTreeHostImpl;
class LayerTreeHostImplClient;
@@ -285,6 +285,9 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
// synchronization.
virtual void SetNeedsCommit();
+ // Invoked when a compositing update is first requested and scheduled.
+ void OnCommitRequested();
+
// Notifies that a new viz::LocalSurfaceId has been set, ahead of it becoming
// activated. Requests that the compositor thread does not produce new frames
// until it has activated.
@@ -401,11 +404,20 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
// remains blocked until the pending tree is activated.
void SetNextCommitWaitsForActivation();
+ // Registers a callback that is run when the presentation feedback for the
+ // next submitted frame is received (it's entirely possible some frames may be
+ // dropped between the time this is called and the callback is run).
+ // Note that since this might be called on failed presentations, it is
+ // deprecated in favor of `RequestSuccessfulPresentationTimeForNextFrame()`
+ // which will be called only after a successful presentation.
+ void RequestPresentationTimeForNextFrame(
+ PresentationTimeCallbackBuffer::Callback callback);
+
// Registers a callback that is run when the next frame successfully makes it
// to the screen (it's entirely possible some frames may be dropped between
// the time this is called and the callback is run).
- void RequestPresentationTimeForNextFrame(
- PresentationTimeCallbackBuffer::MainCallback callback);
+ void RequestSuccessfulPresentationTimeForNextFrame(
+ PresentationTimeCallbackBuffer::SuccessfulCallback callback);
// Registers a callback that is run when any ongoing scroll-animation ends. If
// there are no ongoing animations, then the callback is run immediately.
@@ -732,7 +744,10 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
bool UpdateLayers();
void DidPresentCompositorFrame(
uint32_t frame_token,
- std::vector<PresentationTimeCallbackBuffer::MainCallback> callbacks,
+ std::vector<PresentationTimeCallbackBuffer::Callback>
+ presentation_callbacks,
+ std::vector<PresentationTimeCallbackBuffer::SuccessfulCallback>
+ successful_presentation_callbacks,
const gfx::PresentationFeedback& feedback);
// Called when the compositor completed page scale animation.
void DidCompletePageScaleAnimation();
@@ -745,8 +760,6 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
void NotifyThroughputTrackerResults(CustomTrackerResults results);
void NotifyTransitionRequestsFinished(
const std::vector<uint32_t>& sequence_ids);
- void ReportEventLatency(
- std::vector<EventLatencyTracker::LatencyData> latencies);
LayerTreeHostClient* client() {
DCHECK(IsMainThread());
@@ -861,10 +874,9 @@ 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);
+ void AddViewTransitionRequest(std::unique_ptr<ViewTransitionRequest> request);
- std::vector<base::OnceClosure> TakeDocumentTransitionCallbacksForTesting();
+ std::vector<base::OnceClosure> TakeViewTransitionCallbacksForTesting();
// Returns a percentage of dropped frames of the last second.
double GetPercentDroppedFrames() const;
@@ -1064,7 +1076,7 @@ class CC_EXPORT LayerTreeHost : public MutatorHostClient {
EventsMetricsManager events_metrics_manager_;
// A list of callbacks that need to be invoked when they are processed.
- base::flat_map<uint32_t, base::OnceClosure> document_transition_callbacks_;
+ base::flat_map<uint32_t, base::OnceClosure> view_transition_callbacks_;
// Set if WaitForCommitCompletion() was called before commit completes. Used
// for histograms.
diff --git a/chromium/cc/trees/layer_tree_host_client.h b/chromium/cc/trees/layer_tree_host_client.h
index 17f7e90c2ac..2aae43818ec 100644
--- a/chromium/cc/trees/layer_tree_host_client.h
+++ b/chromium/cc/trees/layer_tree_host_client.h
@@ -6,12 +6,9 @@
#define CC_TREES_LAYER_TREE_HOST_CLIENT_H_
#include <memory>
-#include <vector>
-#include "base/memory/ref_counted.h"
#include "base/time/time.h"
#include "cc/input/browser_controls_state.h"
-#include "cc/metrics/event_latency_tracker.h"
#include "cc/metrics/frame_sequence_tracker_collection.h"
#include "cc/trees/paint_holding_commit_trigger.h"
#include "cc/trees/paint_holding_reason.h"
@@ -137,6 +134,9 @@ class LayerTreeHostClient {
// Notification that rendering has been paused or resumed.
virtual void OnPauseRenderingChanged(bool) = 0;
+ // Notification that a compositing update has been requested.
+ virtual void OnCommitRequested() = 0;
+
// Visual frame-based updates to the state of the LayerTreeHost are expected
// to happen only in calls to LayerTreeHostClient::UpdateLayerTreeHost, which
// should mutate/invalidate the layer tree or other page parameters as
@@ -198,8 +198,6 @@ class LayerTreeHostClient {
// RecordEndOfFrameMetrics.
virtual std::unique_ptr<BeginMainFrameMetrics> GetBeginMainFrameMetrics() = 0;
virtual void NotifyThroughputTrackerResults(CustomTrackerResults results) = 0;
- virtual void ReportEventLatency(
- std::vector<EventLatencyTracker::LatencyData> latencies) = 0;
// Should only be implemented by Blink.
virtual std::unique_ptr<WebVitalMetrics> GetWebVitalMetrics() = 0;
diff --git a/chromium/cc/trees/layer_tree_host_impl.cc b/chromium/cc/trees/layer_tree_host_impl.cc
index d129d26e2ee..2c1d4c127f4 100644
--- a/chromium/cc/trees/layer_tree_host_impl.cc
+++ b/chromium/cc/trees/layer_tree_host_impl.cc
@@ -34,6 +34,7 @@
#include "base/ranges/algorithm.h"
#include "base/strings/stringprintf.h"
#include "base/system/sys_info.h"
+#include "base/time/time.h"
#include "base/trace_event/traced_value.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
@@ -44,11 +45,9 @@
#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/page_scale_animation.h"
#include "cc/input/scrollbar_animation_controller.h"
-#include "cc/input/scroller_size_metrics.h"
#include "cc/layers/append_quads_data.h"
#include "cc/layers/effect_tree_layer_list_iterator.h"
#include "cc/layers/heads_up_display_layer_impl.h"
@@ -57,6 +56,7 @@
#include "cc/layers/surface_layer_impl.h"
#include "cc/layers/viewport.h"
#include "cc/metrics/compositor_frame_reporting_controller.h"
+#include "cc/metrics/custom_metrics_recorder.h"
#include "cc/metrics/frame_sequence_metrics.h"
#include "cc/metrics/lcd_text_metrics_reporter.h"
#include "cc/metrics/ukm_smoothness_data.h"
@@ -90,11 +90,13 @@
#include "cc/trees/mobile_optimized_viewport_util.h"
#include "cc/trees/mutator_host.h"
#include "cc/trees/presentation_time_callback_buffer.h"
+#include "cc/trees/raster_context_provider_wrapper.h"
#include "cc/trees/render_frame_metadata.h"
#include "cc/trees/render_frame_metadata_observer.h"
#include "cc/trees/scroll_node.h"
#include "cc/trees/single_thread_proxy.h"
#include "cc/trees/tree_synchronizer.h"
+#include "cc/view_transition/view_transition_request.h"
#include "components/viz/common/features.h"
#include "components/viz/common/frame_timing_details.h"
#include "components/viz/common/hit_test/hit_test_region_list.h"
@@ -199,41 +201,6 @@ void PopulateMetadataContentColorUsage(
}
}
-// Registers callbacks, as needed, to track First Scroll Latency.
-void ApplyFirstScrollTracking(const ui::LatencyInfo* latency,
- uint32_t frame_token,
- LayerTreeHostImpl* impl) {
- base::TimeTicks creation_timestamp;
- // If |latency| isn't tracking a scroll, we don't need to do extra
- // first-scroll tracking.
- auto scroll_update_started =
- ui::INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT;
- auto scroll_update_continued =
- ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT;
- if (!latency->FindLatency(scroll_update_started, &creation_timestamp) &&
- !latency->FindLatency(scroll_update_continued, &creation_timestamp)) {
- return;
- }
-
- // Construct a callback that, given a successful presentation timestamp, will
- // report the time span between the scroll input-event creation and the
- // presentation timestamp.
- PresentationTimeCallbackBuffer::CompositorCallback presentation_callback =
- base::BindOnce(
- [](base::TimeTicks event_creation,
- LayerTreeHostImpl* layer_tree_host_impl,
- base::TimeTicks presentation_timestamp) {
- layer_tree_host_impl->DidObserveScrollDelay(
- presentation_timestamp - event_creation, event_creation);
- },
- creation_timestamp, impl);
-
- // Tell the |LayerTreeHostImpl| to run our callback with the presentation
- // feedback corresponding to the given |frame_token|.
- impl->RegisterCompositorPresentationTimeCallback(
- frame_token, std::move(presentation_callback));
-}
-
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class SourceIdConsistency : int {
@@ -280,6 +247,76 @@ const char* ClientNameForVerboseLog() {
} // namespace
+// Holds either a created ImageDecodeCache or a ptr to a shared
+// GpuImageDecodeCache.
+class LayerTreeHostImpl::ImageDecodeCacheHolder {
+ public:
+ ImageDecodeCacheHolder(bool enable_shared_image_cache_for_gpu,
+ bool use_gpu_rasterization,
+ bool gpu_compositing,
+ scoped_refptr<RasterContextProviderWrapper>
+ worker_context_provider_wrapper,
+ viz::ResourceFormat tile_format,
+ size_t decoded_image_working_set_budget_bytes,
+ int max_texture_size,
+ RasterDarkModeFilter* dark_mode_filter) {
+ if (use_gpu_rasterization) {
+ auto color_type = viz::ResourceFormatToClosestSkColorType(
+ /*gpu_compositing=*/true, tile_format);
+ if (enable_shared_image_cache_for_gpu) {
+ image_decode_cache_ptr_ =
+ &worker_context_provider_wrapper->GetGpuImageDecodeCache(
+ color_type);
+ } else {
+ image_decode_cache_ = std::make_unique<GpuImageDecodeCache>(
+ worker_context_provider_wrapper->GetContext().get(),
+ /*use_transfer_cache=*/true, color_type,
+ decoded_image_working_set_budget_bytes, max_texture_size,
+ dark_mode_filter);
+ }
+ } else {
+ image_decode_cache_ = std::make_unique<SoftwareImageDecodeCache>(
+ viz::ResourceFormatToClosestSkColorType(gpu_compositing, tile_format),
+ decoded_image_working_set_budget_bytes);
+ }
+
+ if (image_decode_cache_) {
+ image_decode_cache_ptr_ = image_decode_cache_.get();
+ } else {
+ DCHECK(image_decode_cache_ptr_);
+ }
+ }
+
+ void SetShouldAggressivelyFreeResources(bool aggressively_free_resources) {
+ // This must only be called if the decode cache is not shared aka is not
+ // created via RasterContextProviderWrapper as the cache created via that
+ // gets this calls from ContextCacheController, which notifies only after
+ // ALL clients are invisible or at least one is visible.
+ if (image_decode_cache_) {
+ image_decode_cache_->SetShouldAggressivelyFreeResources(
+ aggressively_free_resources, /*context_lock_acquired=*/false);
+ }
+ }
+
+ ImageDecodeCache* image_decode_cache() const {
+ DCHECK(image_decode_cache_ptr_);
+ return image_decode_cache_ptr_;
+ }
+
+ ImageDecodeCacheHolder(const ImageDecodeCacheHolder&) = delete;
+ ImageDecodeCacheHolder& operator=(const ImageDecodeCacheHolder&) = delete;
+
+ ~ImageDecodeCacheHolder() {
+ image_decode_cache_ptr_ = nullptr;
+ image_decode_cache_.reset();
+ }
+
+ private:
+ raw_ptr<ImageDecodeCache, DanglingUntriaged> image_decode_cache_ptr_ =
+ nullptr;
+ std::unique_ptr<ImageDecodeCache> image_decode_cache_;
+};
+
void LayerTreeHostImpl::DidUpdateScrollAnimationCurve() {
// Because we updated the animation target, notify the
// `LatencyInfoSwapPromiseMonitor` to tell it that something happened that
@@ -516,7 +553,7 @@ LayerTreeHostImpl::~LayerTreeHostImpl() {
// all the resource and raster structures.
DCHECK(!layer_tree_frame_sink_);
DCHECK(!resource_pool_);
- DCHECK(!image_decode_cache_);
+ DCHECK(!image_decode_cache_holder_);
DCHECK(!single_thread_synchronous_task_graph_runner_);
if (input_delegate_)
@@ -593,9 +630,10 @@ void LayerTreeHostImpl::BeginMainFrameAborted(
if (pending_tree_) {
pending_tree_->AppendSwapPromises(std::move(swap_promises));
} else {
+ base::TimeTicks timestamp = base::TimeTicks::Now();
for (const auto& swap_promise : swap_promises) {
SwapPromise::DidNotSwapAction action =
- swap_promise->DidNotSwap(SwapPromise::COMMIT_NO_UPDATE);
+ swap_promise->DidNotSwap(SwapPromise::COMMIT_NO_UPDATE, timestamp);
DCHECK_EQ(action, SwapPromise::DidNotSwapAction::BREAK_PROMISE);
}
}
@@ -1072,6 +1110,11 @@ void LayerTreeHostImpl::StartPageScaleAnimation(const gfx::Point& target_offset,
gfx::SizeF viewport_size(
active_tree_->InnerViewportScrollNode()->container_bounds);
+ if (viewport_size.IsEmpty()) {
+ // Avoid divide by zero. Besides nothing should see the animation anyway.
+ return;
+ }
+
// TODO(miletus) : Pass in ScrollOffset.
page_scale_animation_ = PageScaleAnimation::Create(
scroll_total, active_tree_->current_page_scale_factor(), viewport_size,
@@ -1238,7 +1281,7 @@ bool LayerTreeHostImpl::HasDamage() const {
return root_surface_has_visible_damage ||
active_tree_->property_trees()->effect_tree().HasCopyRequests() ||
- hud_wants_to_draw_ || active_tree_->HasDocumentTransitionRequests();
+ hud_wants_to_draw_ || active_tree_->HasViewTransitionRequests();
}
DrawResult LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) {
@@ -1274,7 +1317,7 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) {
// crbug.com/805673.
active_tree_->ResetHandleVisibilityChanged();
- base::flat_set<viz::SharedElementResourceId> known_resource_ids;
+ base::flat_set<viz::ViewTransitionElementResourceId> known_resource_ids;
// Create the render passes in dependency order.
size_t render_surface_list_size = frame->render_surface_list->size();
for (size_t i = 0; i < render_surface_list_size; ++i) {
@@ -1290,9 +1333,9 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) {
if (should_draw_into_render_pass)
frame->render_passes.push_back(render_surface->CreateRenderPass());
if (render_surface->OwningEffectNode()
- ->shared_element_resource_id.IsValid()) {
- known_resource_ids.insert(
- render_surface->OwningEffectNode()->shared_element_resource_id);
+ ->view_transition_element_resource_id.IsValid()) {
+ known_resource_ids.insert(render_surface->OwningEffectNode()
+ ->view_transition_element_resource_id);
}
}
@@ -1340,9 +1383,6 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) {
bool have_missing_animated_tiles = false;
int num_of_layers_with_videos = 0;
- // 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());
@@ -1371,11 +1411,6 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) {
if (render_surface->contributes_to_drawn_surface()) {
render_surface->AppendQuads(draw_mode, target_render_pass,
&append_quads_data);
- if (settings_.allow_de_jelly_effect) {
- de_jelly_state_.UpdateSharedQuadState(
- active_tree_.get(), render_surface->TransformTreeIndex(),
- target_render_pass);
- }
}
} else if (it.state() == EffectTreeLayerListIterator::State::LAYER) {
LayerImpl* layer = it.current_layer();
@@ -1389,11 +1424,6 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) {
}
layer->NotifyKnownResourceIdsBeforeAppendQuads(known_resource_ids);
layer->AppendQuads(target_render_pass, &append_quads_data);
- if (settings_.allow_de_jelly_effect) {
- de_jelly_state_.UpdateSharedQuadState(active_tree_.get(),
- layer->transform_tree_index(),
- target_render_pass);
- }
} else {
if (settings_.enable_compositing_based_throttling)
throttle_decider_.ProcessLayerNotToDraw(layer);
@@ -1586,10 +1616,6 @@ DrawResult LayerTreeHostImpl::PrepareToDraw(FrameData* frame) {
// of the process, so the histogram names are runtime constant.
const char* client_name = GetClientNameForMetrics();
if (client_name) {
- size_t total_gpu_memory_for_tilings_in_bytes = 0;
- for (const PictureLayerImpl* layer : active_tree()->picture_layers())
- total_gpu_memory_for_tilings_in_bytes += layer->GPUMemoryUsageInBytes();
-
UMA_HISTOGRAM_CUSTOM_COUNTS(
base::StringPrintf("Compositing.%s.NumActiveLayers", client_name),
base::saturated_cast<int>(active_tree_->NumLayers()), 1, 1000, 20);
@@ -1599,19 +1625,6 @@ DrawResult LayerTreeHostImpl::PrepareToDraw(FrameData* frame) {
client_name),
base::saturated_cast<int>(active_tree_->picture_layers().size()), 1,
1000, 20);
-
- // TODO(pdr): Instead of skipping empty picture layers, maybe we should
- // accumulate layer->GetRasterSource()->GetMemoryUsage() above and skip
- // recording when the accumulated memory usage is 0.
- if (!active_tree()->picture_layers().empty()) {
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- base::StringPrintf("Compositing.%s.GPUMemoryForTilingsInKb",
- client_name),
- base::saturated_cast<int>(total_gpu_memory_for_tilings_in_bytes /
- 1024),
- 1, kGPUMemoryForTilingsLargestBucketKb,
- kGPUMemoryForTilingsBucketCount);
- }
}
}
@@ -1701,7 +1714,7 @@ void LayerTreeHostImpl::RemoveRenderPasses(FrameData* frame) {
pass->backdrop_filters.IsEmpty() &&
// TODO(khushalsagar) : Send information about no-op passes to viz to
// retain this optimization for shared elements. See crbug.com/1265178.
- !pass->shared_element_resource_id.IsValid()) {
+ !pass->view_transition_element_resource_id.IsValid()) {
// 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);
@@ -1721,7 +1734,7 @@ void LayerTreeHostImpl::RemoveRenderPasses(FrameData* frame) {
viz::CompositorRenderPass* pass =
frame->render_passes[frame->render_passes.size() - 2 - i].get();
if (!pass->copy_requests.empty() ||
- pass->shared_element_resource_id.IsValid()) {
+ pass->view_transition_element_resource_id.IsValid()) {
continue;
}
if (pass_references[pass->id])
@@ -1809,8 +1822,8 @@ void LayerTreeHostImpl::UpdateTileManagerMemoryPolicy(
// allow the image decode controller to retain resources. We handle the
// equal to 0 case in NotifyAllTileTasksComplete to avoid interrupting
// running work.
- if (image_decode_cache_)
- image_decode_cache_->SetShouldAggressivelyFreeResources(false);
+ if (image_decode_cache_holder_)
+ image_decode_cache_holder_->SetShouldAggressivelyFreeResources(false);
} else {
// When the memory policy is set to zero, its important to release any
// decoded images cached by the tracker. But we can not re-checker any
@@ -2023,8 +2036,8 @@ void LayerTreeHostImpl::NotifyAllTileTasksCompleted() {
// contexts of visibility change. This ensures that the imaged decode
// controller has released all Skia refs at the time Skia's cleanup
// executes (within worker context's cleanup).
- if (image_decode_cache_)
- image_decode_cache_->SetShouldAggressivelyFreeResources(true);
+ if (image_decode_cache_holder_)
+ image_decode_cache_holder_->SetShouldAggressivelyFreeResources(true);
SetContextVisibility(false);
}
}
@@ -2135,14 +2148,9 @@ void LayerTreeHostImpl::DidReceiveCompositorFrameAck() {
void LayerTreeHostImpl::DidPresentCompositorFrame(
uint32_t frame_token,
const viz::FrameTimingDetails& details) {
- // Presentation callbacks registered on the compositor thread are expected to
- // be called on the first successful presentation. So, if the presentation is
- // failed, we only pop main thread callbacks at this point and leave
- // compositor thread callbacks alone until a successful presentation.
- const bool main_callbacks_only = details.presentation_feedback.failed();
PresentationTimeCallbackBuffer::PendingCallbacks activated_callbacks =
- presentation_time_callbacks_.PopPendingCallbacks(frame_token,
- main_callbacks_only);
+ presentation_time_callbacks_.PopPendingCallbacks(
+ frame_token, details.presentation_feedback.failed());
// Send all tasks to the client so that it can decide which tasks
// should run on which thread.
@@ -2257,7 +2265,8 @@ void LayerTreeHostImpl::OnCompositorFrameTransitionDirectiveProcessed(
void LayerTreeHostImpl::ReportEventLatency(
std::vector<EventLatencyTracker::LatencyData> latencies) {
- client_->ReportEventLatency(std::move(latencies));
+ if (auto* recorder = CustomMetricRecorder::Get())
+ recorder->ReportEventLatency(std::move(latencies));
}
void LayerTreeHostImpl::OnCanDrawStateChangedForTree() {
@@ -2302,10 +2311,11 @@ viz::CompositorFrameMetadata LayerTreeHostImpl::MakeCompositorFrameMetadata() {
metadata.root_background_color = active_tree_->background_color();
metadata.may_throttle_if_undrawn_frames = may_throttle_if_undrawn_frames_;
- if (active_tree_->has_presentation_callbacks()) {
- presentation_time_callbacks_.RegisterMainThreadPresentationCallbacks(
- metadata.frame_token, active_tree_->TakePresentationCallbacks());
- }
+ presentation_time_callbacks_.RegisterMainThreadCallbacks(
+ metadata.frame_token, active_tree_->TakePresentationCallbacks());
+ presentation_time_callbacks_.RegisterMainThreadSuccessfulCallbacks(
+ metadata.frame_token,
+ active_tree_->TakeSuccessfulPresentationCallbacks());
if (GetDrawMode() == DRAW_MODE_RESOURCELESS_SOFTWARE) {
// TODO(savella) : Change to check for ActivelyScrollingType::kNone
@@ -2650,10 +2660,10 @@ viz::CompositorFrame LayerTreeHostImpl::GenerateCompositorFrame(
viz::CompositorFrameMetadata metadata = MakeCompositorFrameMetadata();
- DocumentTransitionRequest::SharedElementMap shared_element_render_pass_id_map;
+ ViewTransitionRequest::SharedElementMap shared_element_render_pass_id_map;
for (RenderSurfaceImpl* render_surface : *frame->render_surface_list) {
const auto& shared_element_id =
- render_surface->GetDocumentTransitionSharedElementId();
+ render_surface->GetViewTransitionElementId();
if (!shared_element_id.valid())
continue;
@@ -2668,10 +2678,10 @@ viz::CompositorFrame LayerTreeHostImpl::GenerateCompositorFrame(
shared_element_render_pass_id_map[shared_element_id].render_pass_id =
render_surface->render_pass_id();
shared_element_render_pass_id_map[shared_element_id].resource_id =
- render_surface->OwningEffectNode()->shared_element_resource_id;
+ render_surface->OwningEffectNode()->view_transition_element_resource_id;
}
- for (auto& request : active_tree_->TakeDocumentTransitionRequests()) {
+ for (auto& request : active_tree_->TakeViewTransitionRequests()) {
metadata.transition_directives.push_back(
request->ConstructDirective(shared_element_render_pass_id_map));
}
@@ -2745,9 +2755,9 @@ viz::CompositorFrame LayerTreeHostImpl::GenerateCompositorFrame(
if (!CommitToActiveTree() && !metadata.latency_info.empty()) {
base::TimeTicks draw_time = base::TimeTicks::Now();
+ ApplyFirstScrollTracking(metadata.latency_info.front(),
+ metadata.frame_token);
ukm::SourceId exemplar = metadata.latency_info.front().ukm_source_id();
- ApplyFirstScrollTracking(&metadata.latency_info.front(),
- metadata.frame_token, this);
bool all_valid = true;
bool all_unique = true;
for (auto& latency : metadata.latency_info) {
@@ -2938,21 +2948,38 @@ void LayerTreeHostImpl::UpdateTreeResourcesForGpuRasterizationIfNeeded() {
SetRequiresHighResToDraw();
}
+ImageDecodeCache* LayerTreeHostImpl::GetImageDecodeCache() const {
+ return image_decode_cache_holder_
+ ? image_decode_cache_holder_->image_decode_cache()
+ : nullptr;
+}
+
void LayerTreeHostImpl::RegisterMainThreadPresentationTimeCallbackForTesting(
uint32_t frame_token,
- PresentationTimeCallbackBuffer::MainCallback callback) {
- std::vector<PresentationTimeCallbackBuffer::MainCallback> as_vector;
+ PresentationTimeCallbackBuffer::Callback callback) {
+ std::vector<PresentationTimeCallbackBuffer::Callback> as_vector;
as_vector.push_back(std::move(callback));
- presentation_time_callbacks_.RegisterMainThreadPresentationCallbacks(
+ presentation_time_callbacks_.RegisterMainThreadCallbacks(
frame_token, std::move(as_vector));
}
-void LayerTreeHostImpl::RegisterCompositorPresentationTimeCallback(
- uint32_t frame_token,
- PresentationTimeCallbackBuffer::CompositorCallback callback) {
- std::vector<PresentationTimeCallbackBuffer::CompositorCallback> as_vector;
+void LayerTreeHostImpl::
+ RegisterMainThreadSuccessfulPresentationTimeCallbackForTesting(
+ uint32_t frame_token,
+ PresentationTimeCallbackBuffer::SuccessfulCallback callback) {
+ std::vector<PresentationTimeCallbackBuffer::SuccessfulCallback> as_vector;
+ as_vector.push_back(std::move(callback));
+ presentation_time_callbacks_.RegisterMainThreadSuccessfulCallbacks(
+ frame_token, std::move(as_vector));
+}
+
+void LayerTreeHostImpl::
+ RegisterCompositorThreadSuccessfulPresentationTimeCallbackForTesting(
+ uint32_t frame_token,
+ PresentationTimeCallbackBuffer::SuccessfulCallback callback) {
+ std::vector<PresentationTimeCallbackBuffer::SuccessfulCallback> as_vector;
as_vector.push_back(std::move(callback));
- presentation_time_callbacks_.RegisterCompositorPresentationCallbacks(
+ presentation_time_callbacks_.RegisterCompositorThreadSuccessfulCallbacks(
frame_token, std::move(as_vector));
}
@@ -3094,12 +3121,11 @@ static void PopulateHitTestRegion(viz::HitTestRegion* hit_test_region,
gfx::Transform surface_to_root_transform = layer->ScreenSpaceTransform();
surface_to_root_transform.Scale(SK_Scalar1 / device_scale_factor,
SK_Scalar1 / device_scale_factor);
- surface_to_root_transform.FlattenTo2d();
+ surface_to_root_transform.Flatten();
// TODO(sunxd): Avoid losing precision by not using inverse if possible.
- [[maybe_unused]] bool ok =
- surface_to_root_transform.GetInverse(&hit_test_region->transform);
- // Note: If |ok| is false, the |transform| is set to the identity before
- // returning, which is what we want.
+ // Note: |transform| is set to the identity if |surface_to_root_transform| is
+ // not invertible, which is what we want.
+ hit_test_region->transform = surface_to_root_transform.InverseOrIdentity();
}
absl::optional<viz::HitTestRegionList> LayerTreeHostImpl::BuildHitTestData() {
@@ -3587,23 +3613,17 @@ void LayerTreeHostImpl::CreateTileManagerResources() {
settings_, layer_tree_frame_sink_->context_provider(),
use_gpu_rasterization_);
- if (use_gpu_rasterization_) {
- image_decode_cache_ = std::make_unique<GpuImageDecodeCache>(
- layer_tree_frame_sink_->worker_context_provider(),
- /*use_transfer_cache=*/true,
- viz::ResourceFormatToClosestSkColorType(/*gpu_compositing=*/true,
- tile_format),
- settings_.decoded_image_working_set_budget_bytes, max_texture_size_,
- dark_mode_filter_);
+ const bool gpu_compositing = !!layer_tree_frame_sink_->context_provider();
+ image_decode_cache_holder_ = std::make_unique<ImageDecodeCacheHolder>(
+ settings_.enable_shared_image_cache_for_gpu, use_gpu_rasterization_,
+ gpu_compositing,
+ layer_tree_frame_sink_->worker_context_provider_wrapper(), tile_format,
+ settings_.decoded_image_working_set_budget_bytes, max_texture_size_,
+ dark_mode_filter_);
+ if (use_gpu_rasterization_) {
pending_raster_queries_ = std::make_unique<RasterQueryQueue>(
layer_tree_frame_sink_->worker_context_provider());
-
- } else {
- bool gpu_compositing = !!layer_tree_frame_sink_->context_provider();
- image_decode_cache_ = std::make_unique<SoftwareImageDecodeCache>(
- viz::ResourceFormatToClosestSkColorType(gpu_compositing, tile_format),
- settings_.decoded_image_working_set_budget_bytes);
}
raster_buffer_provider_ = CreateRasterBufferProvider();
@@ -3618,7 +3638,7 @@ void LayerTreeHostImpl::CreateTileManagerResources() {
task_graph_runner = single_thread_synchronous_task_graph_runner_.get();
}
- tile_manager_.SetResources(resource_pool_.get(), image_decode_cache_.get(),
+ tile_manager_.SetResources(resource_pool_.get(), GetImageDecodeCache(),
task_graph_runner, raster_buffer_provider_.get(),
use_gpu_rasterization_,
pending_raster_queries_.get());
@@ -3740,8 +3760,13 @@ void LayerTreeHostImpl::ClearCaches() {
// comes with an invalidation and the image ids are never re-used.
bool can_clear_decode_policy_tracking = true;
tile_manager_.ClearCheckerImageTracking(can_clear_decode_policy_tracking);
- if (image_decode_cache_)
- image_decode_cache_->ClearCache();
+ // TODO(crbug.com/1378247): add tracking for which clients have used an image
+ // and remove entries used by only one client when the URL on that client
+ // changes. This should be fixed to correctly clear caches for web contents.
+ // This is only a problem when
+ // LayerTreeSettings::enable_shared_image_cache_for_gpu is true.
+ if (GetImageDecodeCache())
+ GetImageDecodeCache()->ClearCache();
image_animation_controller_.set_did_navigate();
}
@@ -3755,7 +3780,7 @@ void LayerTreeHostImpl::DidChangeScrollbarVisibility() {
void LayerTreeHostImpl::CleanUpTileManagerResources() {
tile_manager_.FinishTasksAndCleanUp();
single_thread_synchronous_task_graph_runner_ = nullptr;
- image_decode_cache_ = nullptr;
+ image_decode_cache_holder_ = nullptr;
raster_buffer_provider_ = nullptr;
pending_raster_queries_ = nullptr;
// Any resources that were allocated previously should be considered not good
@@ -4056,7 +4081,7 @@ void LayerTreeHostImpl::UpdateImageDecodingHints(
void LayerTreeHostImpl::SetRenderFrameObserver(
std::unique_ptr<RenderFrameMetadataObserver> observer) {
render_frame_metadata_observer_ = std::move(observer);
- render_frame_metadata_observer_->BindToCurrentThread();
+ render_frame_metadata_observer_->BindToCurrentSequence();
}
void LayerTreeHostImpl::WillScrollContent(ElementId element_id) {
@@ -4144,8 +4169,7 @@ void LayerTreeHostImpl::CollectScrollbarUpdatesForCommit(
CompositorCommitData* commit_data) const {
commit_data->scrollbars.reserve(scrollbar_animation_controllers_.size());
for (auto& pair : scrollbar_animation_controllers_) {
- if (pair.second->visibility_changed() ||
- !settings_.enable_scroll_update_optimizations) {
+ if (pair.second->visibility_changed()) {
commit_data->scrollbars.push_back(
{pair.first, pair.second->ScrollbarsHidden()});
pair.second->ClearVisibilityChanged();
@@ -4609,7 +4633,7 @@ void LayerTreeHostImpl::CreateUIResource(UIResourceId uid,
const auto& caps = context_provider->ContextCapabilities();
overlay_candidate =
settings_.resource_settings.use_gpu_memory_buffer_resources &&
- caps.texture_storage_image &&
+ caps.supports_scanout_shared_images &&
viz::IsGpuMemoryBufferFormatSupported(format);
if (overlay_candidate) {
shared_image_usage |= gpu::SHARED_IMAGE_USAGE_SCANOUT;
@@ -5152,7 +5176,7 @@ void LayerTreeHostImpl::SetUkmSmoothnessDestination(
void LayerTreeHostImpl::NotifyDidPresentCompositorFrameOnImplThread(
uint32_t frame_token,
- std::vector<PresentationTimeCallbackBuffer::CompositorCallback> callbacks,
+ std::vector<PresentationTimeCallbackBuffer::SuccessfulCallback> callbacks,
const viz::FrameTimingDetails& details) {
frame_trackers_.NotifyFramePresented(frame_token,
details.presentation_feedback);
@@ -5190,4 +5214,38 @@ base::WeakPtr<LayerTreeHostImpl> LayerTreeHostImpl::AsWeakPtr() {
return weak_factory_.GetWeakPtr();
}
+void LayerTreeHostImpl::ApplyFirstScrollTracking(const ui::LatencyInfo& latency,
+ uint32_t frame_token) {
+ base::TimeTicks creation_timestamp;
+
+ // If `latency` isn't tracking a scroll, we don't need to do extra
+ // first-scroll tracking.
+ if (!latency.FindLatency(
+ ui::INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT,
+ &creation_timestamp) &&
+ !latency.FindLatency(
+ ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT,
+ &creation_timestamp)) {
+ return;
+ }
+
+ // Construct a callback that, given a successful presentation timestamp, will
+ // report the time span between the scroll input-event creation and the
+ // presentation timestamp.
+ std::vector<PresentationTimeCallbackBuffer::SuccessfulCallback> callbacks;
+ callbacks.push_back(base::BindOnce(
+ [](base::TimeTicks event_creation,
+ LayerTreeHostImpl* layer_tree_host_impl,
+ base::TimeTicks presentation_timestamp) {
+ layer_tree_host_impl->DidObserveScrollDelay(
+ presentation_timestamp - event_creation, event_creation);
+ },
+ creation_timestamp, this));
+
+ // Register the callback to run with the presentation timestamp corresponding
+ // to the given `frame_token`.
+ presentation_time_callbacks_.RegisterCompositorThreadSuccessfulCallbacks(
+ frame_token, std::move(callbacks));
+}
+
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_impl.h b/chromium/cc/trees/layer_tree_host_impl.h
index 87eebdeb9bb..568c2403852 100644
--- a/chromium/cc/trees/layer_tree_host_impl.h
+++ b/chromium/cc/trees/layer_tree_host_impl.h
@@ -45,7 +45,6 @@
#include "cc/scheduler/video_frame_controller.h"
#include "cc/tiles/tile_manager.h"
#include "cc/trees/animated_paint_worklet_tracker.h"
-#include "cc/trees/de_jelly_state.h"
#include "cc/trees/frame_rate_estimator.h"
#include "cc/trees/layer_tree_frame_sink_client.h"
#include "cc/trees/layer_tree_host.h"
@@ -184,9 +183,6 @@ class LayerTreeHostImplClient {
virtual size_t CommitDurationSampleCountForTesting() const = 0;
- virtual void ReportEventLatency(
- std::vector<EventLatencyTracker::LatencyData> latencies) = 0;
-
protected:
virtual ~LayerTreeHostImplClient() = default;
};
@@ -615,11 +611,12 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient,
return settings_.create_low_res_tiling && !use_gpu_rasterization_;
}
ResourcePool* resource_pool() { return resource_pool_.get(); }
- ImageDecodeCache* image_decode_cache() { return image_decode_cache_.get(); }
ImageAnimationController* image_animation_controller() {
return &image_animation_controller_;
}
+ ImageDecodeCache* GetImageDecodeCache() const;
+
uint32_t next_frame_token() const { return *next_frame_token_; }
// Buffers `callback` until a relevant presentation feedback arrives, at which
@@ -628,15 +625,23 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient,
// equal to `frame_token`.
void RegisterMainThreadPresentationTimeCallbackForTesting(
uint32_t frame_token,
- PresentationTimeCallbackBuffer::MainCallback callback);
+ PresentationTimeCallbackBuffer::Callback callback);
+
+ // Buffers `callback` until a relevant successful presentation occurs, at
+ // which point the callback will be posted to run on the main thread. A
+ // successful presentation is considered relevant if the presented frame's
+ // token is greater than or equal to `frame_token`.
+ void RegisterMainThreadSuccessfulPresentationTimeCallbackForTesting(
+ uint32_t frame_token,
+ PresentationTimeCallbackBuffer::SuccessfulCallback callback);
// Buffers `callback` until a relevant successful presentation occurs, at
// which point the callback will be run on the compositor thread. A successful
// presentation is considered relevant if the presented frame's token is
// greater than or equal to `frame_token`.
- void RegisterCompositorPresentationTimeCallback(
+ void RegisterCompositorThreadSuccessfulPresentationTimeCallbackForTesting(
uint32_t frame_token,
- PresentationTimeCallbackBuffer::CompositorCallback callback);
+ PresentationTimeCallbackBuffer::SuccessfulCallback callback);
virtual bool WillBeginImplFrame(const viz::BeginFrameArgs& args);
virtual void DidFinishImplFrame(const viz::BeginFrameArgs& args);
@@ -862,7 +867,7 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient,
// was presented.
void NotifyDidPresentCompositorFrameOnImplThread(
uint32_t frame_token,
- std::vector<PresentationTimeCallbackBuffer::CompositorCallback> callbacks,
+ std::vector<PresentationTimeCallbackBuffer::SuccessfulCallback> callbacks,
const viz::FrameTimingDetails& details);
CompositorFrameReportingController* compositor_frame_reporting_controller()
@@ -1013,6 +1018,10 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient,
void NotifyLatencyInfoSwapPromiseMonitors();
private:
+ // Holds image decode cache instance. It can either be a shared cache or
+ // a cache create by this instance. Which is used depends on the settings.
+ class ImageDecodeCacheHolder;
+
void SetMemoryPolicyImpl(const ManagedMemoryPolicy& policy);
void SetContextVisibility(bool is_visible);
@@ -1044,6 +1053,10 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient,
// Wrapper for checking and updating |contains_srgb_cache_|.
bool CheckColorSpaceContainsSrgb(const gfx::ColorSpace& color_space) const;
+ // Registers callbacks, as needed, to track First Scroll Latency.
+ void ApplyFirstScrollTracking(const ui::LatencyInfo& latency,
+ uint32_t frame_token);
+
// Once bound, this instance owns the InputHandler. However, an InputHandler
// need not be bound so this should be null-checked before dereferencing.
std::unique_ptr<InputDelegateForCompositor> input_delegate_;
@@ -1098,7 +1111,7 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient,
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_;
+ std::unique_ptr<ImageDecodeCacheHolder> image_decode_cache_holder_;
GlobalStateThatImpactsTilePriority global_tile_state_;
@@ -1290,9 +1303,6 @@ class CC_EXPORT LayerTreeHostImpl : public TileManagerClient,
AverageLagTrackingManager lag_tracking_manager_;
- // Helper for de-jelly logic.
- DeJellyState de_jelly_state_;
-
EventsMetricsManager events_metrics_manager_;
std::unique_ptr<LCDTextMetricsReporter> lcd_text_metrics_reporter_;
diff --git a/chromium/cc/trees/layer_tree_host_impl_unittest.cc b/chromium/cc/trees/layer_tree_host_impl_unittest.cc
index 96e4bb2ff33..a5ecf4a59ff 100644
--- a/chromium/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/chromium/cc/trees/layer_tree_host_impl_unittest.cc
@@ -6,7 +6,6 @@
#include <stddef.h>
-#include <algorithm>
#include <cmath>
#include <memory>
#include <utility>
@@ -15,10 +14,11 @@
#include "base/callback_helpers.h"
#include "base/memory/memory_pressure_listener.h"
#include "base/memory/ptr_util.h"
+#include "base/ranges/algorithm.h"
#include "base/run_loop.h"
+#include "base/task/single_thread_task_runner.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
-#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "cc/animation/animation.h"
@@ -26,7 +26,6 @@
#include "cc/animation/animation_id_provider.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/input_handler.h"
#include "cc/input/main_thread_scrolling_reason.h"
@@ -72,6 +71,7 @@
#include "cc/trees/render_frame_metadata_observer.h"
#include "cc/trees/scroll_node.h"
#include "cc/trees/transform_node.h"
+#include "cc/view_transition/view_transition_request.h"
#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"
@@ -149,7 +149,8 @@ class LayerTreeHostImplTest : public testing::Test,
public LayerTreeHostImplClient {
public:
LayerTreeHostImplTest()
- : task_runner_provider_(base::ThreadTaskRunnerHandle::Get()),
+ : task_runner_provider_(
+ base::SingleThreadTaskRunner::GetCurrentDefault()),
always_main_thread_blocked_(&task_runner_provider_),
on_can_draw_state_changed_called_(false),
did_notify_ready_to_activate_(false),
@@ -272,18 +273,18 @@ class LayerTreeHostImplTest : public testing::Test,
PresentationTimeCallbackBuffer::PendingCallbacks activated,
const viz::FrameTimingDetails& details) override {
// We don't call main thread callbacks in this test.
- activated.main_thread_callbacks.clear();
+ activated.main_callbacks.clear();
+ activated.main_successful_callbacks.clear();
host_impl_->NotifyDidPresentCompositorFrameOnImplThread(
- frame_token, std::move(activated.compositor_thread_callbacks), details);
+ frame_token, std::move(activated.compositor_successful_callbacks),
+ details);
}
void NotifyAnimationWorkletStateChange(AnimationWorkletMutationState state,
ElementListType tree_type) override {}
void NotifyPaintWorkletStateChange(
Scheduler::PaintWorkletState state) override {}
void NotifyThroughputTrackerResults(CustomTrackerResults results) override {}
- void ReportEventLatency(
- std::vector<EventLatencyTracker::LatencyData> latencies) override {}
void DidObserveFirstScrollDelay(
base::TimeDelta first_scroll_delay,
@@ -714,38 +715,6 @@ class LayerTreeHostImplTest : public testing::Test,
return host_impl_->MakeRenderFrameMetadata(&frame);
}
- void TestGPUMemoryForTilings(const gfx::Size& layer_size) {
- std::unique_ptr<FakeRecordingSource> recording_source =
- FakeRecordingSource::CreateFilledRecordingSource(layer_size);
- PaintImage checkerable_image =
- CreateDiscardablePaintImage(gfx::Size(500, 500));
- recording_source->add_draw_image(checkerable_image, gfx::Point(0, 0));
-
- recording_source->Rerecord();
- scoped_refptr<FakeRasterSource> raster_source =
- FakeRasterSource::CreateFromRecordingSource(recording_source.get());
-
- // Create the pending tree.
- host_impl_->BeginCommit(0, /*trace_id=*/1);
- LayerTreeImpl* pending_tree = host_impl_->pending_tree();
- LayerImpl* root = SetupRootLayer<FakePictureLayerImpl>(
- pending_tree, layer_size, raster_source);
- root->SetDrawsContent(true);
- UpdateDrawProperties(pending_tree);
-
- // CompleteCommit which should perform a PrepareTiles, adding tilings for
- // the root layer, each one having a raster task.
- host_impl_->CommitComplete();
- // Activate the pending tree and ensure that all tiles are rasterized.
- while (!did_notify_ready_to_activate_)
- base::RunLoop().RunUntilIdle();
-
- DrawFrame();
-
- host_impl_->ReleaseLayerTreeFrameSink();
- host_impl_ = nullptr;
- }
-
void AllowedTouchActionTestHelper(float device_scale_factor,
float page_scale_factor) {
SetupViewportLayersInnerScrolls(gfx::Size(100, 100), gfx::Size(200, 200));
@@ -1278,34 +1247,6 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest, SyncedScrollAbortedCommit) {
synced_scroll->next_reflected_delta_in_main_tree());
}
-TEST_F(CommitToPendingTreeLayerTreeHostImplTest,
- GPUMemoryForSmallLayerHistogramTest) {
- base::HistogramTester histogram_tester;
- SetClientNameForMetrics("Renderer");
- host_impl_->SetDownsampleMetricsForTesting(false);
- // With default tile size being set to 256 * 256, the following layer needs
- // one tile only which costs 256 * 256 * 4 / 1024 = 256KB memory.
- TestGPUMemoryForTilings(gfx::Size(200, 200));
- histogram_tester.ExpectBucketCount(
- "Compositing.Renderer.GPUMemoryForTilingsInKb", 256, 1);
- histogram_tester.ExpectTotalCount(
- "Compositing.Renderer.GPUMemoryForTilingsInKb", 1);
-}
-
-TEST_F(CommitToPendingTreeLayerTreeHostImplTest,
- GPUMemoryForLargeLayerHistogramTest) {
- base::HistogramTester histogram_tester;
- SetClientNameForMetrics("Renderer");
- host_impl_->SetDownsampleMetricsForTesting(false);
- // With default tile size being set to 256 * 256, the following layer needs
- // 4 tiles which cost 256 * 256 * 4 * 4 / 1024 = 1024KB memory.
- TestGPUMemoryForTilings(gfx::Size(500, 500));
- histogram_tester.ExpectBucketCount(
- "Compositing.Renderer.GPUMemoryForTilingsInKb", 1024, 1);
- histogram_tester.ExpectTotalCount(
- "Compositing.Renderer.GPUMemoryForTilingsInKb", 1);
-}
-
// This test verifies that we drop a scroll (and don't crash) if a scroll is
// received before the root layer has been attached. https://crbug.com/895817.
TEST_P(ScrollUnifiedLayerTreeHostImplTest, ScrollBeforeRootLayerAttached) {
@@ -1841,73 +1782,108 @@ gfx::PresentationFeedback ExampleFeedback() {
return feedback;
}
-class LayerTreeHostImplTestInvokeMainThreadCallbacks
+class LayerTreeHostImplTestInvokePresentationCallbacks
: public LayerTreeHostImplTest {
public:
void DidPresentCompositorFrameOnImplThread(
uint32_t frame_token,
PresentationTimeCallbackBuffer::PendingCallbacks activated,
const viz::FrameTimingDetails& details) override {
- auto main_thread_callbacks = std::move(activated.main_thread_callbacks);
host_impl_->NotifyDidPresentCompositorFrameOnImplThread(
- frame_token, std::move(activated.compositor_thread_callbacks), details);
- for (auto& callback : main_thread_callbacks)
+ frame_token, std::move(activated.compositor_successful_callbacks),
+ details);
+ for (auto& callback : activated.main_callbacks)
std::move(callback).Run(details.presentation_feedback);
+ for (auto& callback : activated.main_successful_callbacks)
+ std::move(callback).Run(details.presentation_feedback.timestamp);
}
};
// Tests that, when the LayerTreeHostImpl receives presentation feedback, the
// feedback gets routed to a properly registered callback.
-TEST_F(LayerTreeHostImplTestInvokeMainThreadCallbacks,
+TEST_F(LayerTreeHostImplTestInvokePresentationCallbacks,
PresentationFeedbackCallbacksFire) {
- bool compositor_thread_callback_fired = false;
- bool main_thread_callback_fired = false;
- base::TimeTicks presentation_time_seen_by_compositor_thread_callback;
- gfx::PresentationFeedback feedback_seen_by_main_thread_callback;
+ bool compositor_successful_callback_fired = false;
+ bool main_callback_fired = false;
+ bool main_successful_callback_fired = false;
+ base::TimeTicks compositor_successful_callback_presentation_timestamp;
+ gfx::PresentationFeedback main_callback_presentation_feedback;
+ base::TimeTicks main_successful_callback_presentation_timestamp;
- // Register a compositor-thread callback to run when the frame for
- // |frame_token_1| gets presented.
constexpr uint32_t frame_token_1 = 1;
- host_impl_->RegisterCompositorPresentationTimeCallback(
- frame_token_1,
- base::BindLambdaForTesting([&](base::TimeTicks presentation_timestamp) {
- DCHECK(presentation_time_seen_by_compositor_thread_callback.is_null());
- DCHECK(!presentation_timestamp.is_null());
- compositor_thread_callback_fired = true;
- presentation_time_seen_by_compositor_thread_callback =
- presentation_timestamp;
- }));
-
- // Register a main-thread callback to run when the frame for |frame_token_2|
- // gets presented.
constexpr uint32_t frame_token_2 = 2;
- ASSERT_GT(frame_token_2, frame_token_1);
+ constexpr uint32_t frame_token_3 = 3;
+
+ // Register a compositor-thread successful presentation callback to run when
+ // the frame for `frame_token_1` gets presented.
+ host_impl_
+ ->RegisterCompositorThreadSuccessfulPresentationTimeCallbackForTesting(
+ frame_token_1,
+ base::BindLambdaForTesting(
+ [&](base::TimeTicks presentation_timestamp) {
+ DCHECK(compositor_successful_callback_presentation_timestamp
+ .is_null());
+ DCHECK(!presentation_timestamp.is_null());
+ compositor_successful_callback_fired = true;
+ compositor_successful_callback_presentation_timestamp =
+ presentation_timestamp;
+ }));
+
+ // Register a main-thread presentation callback to run when the presentation
+ // feedback for `frame_token_2` is received.
host_impl_->RegisterMainThreadPresentationTimeCallbackForTesting(
frame_token_2, base::BindLambdaForTesting(
[&](const gfx::PresentationFeedback& feedback) {
- main_thread_callback_fired = true;
- feedback_seen_by_main_thread_callback = feedback;
+ main_callback_fired = true;
+ main_callback_presentation_feedback = feedback;
}));
+ // Register a main-thread successful presentation callback to run when the
+ // frame for `frame_token_2` gets presented.
+ host_impl_->RegisterMainThreadSuccessfulPresentationTimeCallbackForTesting(
+ frame_token_2,
+ base::BindLambdaForTesting([&](base::TimeTicks presentation_timestamp) {
+ DCHECK(main_successful_callback_presentation_timestamp.is_null());
+ DCHECK(!presentation_timestamp.is_null());
+ main_successful_callback_fired = true;
+ main_successful_callback_presentation_timestamp =
+ presentation_timestamp;
+ }));
+
+ // Present frame for `frame_token_1` successfully.
viz::FrameTimingDetails mock_details;
mock_details.presentation_feedback = ExampleFeedback();
-
host_impl_->DidPresentCompositorFrame(frame_token_1, mock_details);
- EXPECT_TRUE(compositor_thread_callback_fired);
- EXPECT_EQ(presentation_time_seen_by_compositor_thread_callback,
+ // Only callbacks registered for `frame_token_1` should be called.
+ EXPECT_TRUE(compositor_successful_callback_fired);
+ EXPECT_FALSE(main_callback_fired);
+ EXPECT_FALSE(main_successful_callback_fired);
+ EXPECT_EQ(compositor_successful_callback_presentation_timestamp,
mock_details.presentation_feedback.timestamp);
+ EXPECT_EQ(main_callback_presentation_feedback, gfx::PresentationFeedback());
+ EXPECT_TRUE(main_successful_callback_presentation_timestamp.is_null());
- // Since |frame_token_2| is strictly greater than |frame_token_1|, the
- // main-thread callback must remain queued for now.
- EXPECT_FALSE(main_thread_callback_fired);
- EXPECT_EQ(feedback_seen_by_main_thread_callback, gfx::PresentationFeedback());
-
+ // Fail presentation of frame for `frame_token_2`.
+ mock_details.presentation_feedback = gfx::PresentationFeedback::Failure();
host_impl_->DidPresentCompositorFrame(frame_token_2, mock_details);
- EXPECT_TRUE(main_thread_callback_fired);
- EXPECT_EQ(feedback_seen_by_main_thread_callback,
+ // Only callbacks that are allowed to run on failed presentations should be
+ // called.
+ EXPECT_TRUE(main_callback_fired);
+ EXPECT_FALSE(main_successful_callback_fired);
+ EXPECT_EQ(main_callback_presentation_feedback,
mock_details.presentation_feedback);
+ EXPECT_TRUE(main_successful_callback_presentation_timestamp.is_null());
+
+ // Present frame for `frame_token_2` successfully.
+ mock_details.presentation_feedback = ExampleFeedback();
+ host_impl_->DidPresentCompositorFrame(frame_token_3, mock_details);
+
+ // Now the callbacks for successful presentation should be called, too.
+ EXPECT_TRUE(main_successful_callback_fired);
+ EXPECT_EQ(main_successful_callback_presentation_timestamp,
+ mock_details.presentation_feedback.timestamp);
}
TEST_P(ScrollUnifiedLayerTreeHostImplTest, NonFastScrollableRegionBasic) {
@@ -5840,7 +5816,6 @@ TEST_P(ScrollUnifiedLayerTreeHostImplTest,
settings.scrollbar_animator = LayerTreeSettings::AURA_OVERLAY;
settings.scrollbar_fade_delay = base::Milliseconds(20);
settings.scrollbar_fade_duration = base::Milliseconds(20);
- settings.enable_scroll_update_optimizations = true;
gfx::Size viewport_size(50, 50);
gfx::Size content_size(100, 100);
@@ -11268,10 +11243,9 @@ class FakeDrawableLayerImpl : public LayerImpl {
// the sub-buffer that is damaged.
TEST_P(ScrollUnifiedLayerTreeHostImplTest, PartialSwapReceivesDamageRect) {
auto gl_owned = std::make_unique<viz::TestGLES2Interface>();
- gl_owned->set_have_post_sub_buffer(true);
scoped_refptr<viz::TestContextProvider> context_provider(
viz::TestContextProvider::Create(std::move(gl_owned)));
- context_provider->BindToCurrentThread();
+ context_provider->BindToCurrentSequence();
std::unique_ptr<FakeLayerTreeFrameSink> layer_tree_frame_sink(
FakeLayerTreeFrameSink::Create3d(context_provider));
@@ -15748,11 +15722,7 @@ TEST_F(LayerTreeHostImplCountingLostSurfaces, TwiceLostSurface) {
size_t CountRenderPassesWithId(const viz::CompositorRenderPassList& list,
viz::CompositorRenderPassId id) {
- return std::count_if(
- list.begin(), list.end(),
- [id](const std::unique_ptr<viz::CompositorRenderPass>& p) {
- return p->id == id;
- });
+ return base::ranges::count(list, id, &viz::CompositorRenderPass::id);
}
TEST_P(ScrollUnifiedLayerTreeHostImplTest, RemoveUnreferencedRenderPass) {
@@ -16791,7 +16761,7 @@ class TestRenderFrameMetadataObserver : public RenderFrameMetadataObserver {
TestRenderFrameMetadataObserver& operator=(
const TestRenderFrameMetadataObserver&) = delete;
- void BindToCurrentThread() override {}
+ void BindToCurrentSequence() override {}
void OnRenderFrameSubmission(
const RenderFrameMetadata& render_frame_metadata,
viz::CompositorFrameMetadata* compositor_frame_metadata,
@@ -18498,7 +18468,7 @@ TEST_F(LayerTreeHostImplTest, FrameElementIdHitTestOverlapSibling) {
GetInputHandler().FindFrameElementIdAtPoint(gfx::PointF(30, 30)));
}
-TEST_F(LayerTreeHostImplTest, DocumentTransitionRequestCausesDamage) {
+TEST_F(LayerTreeHostImplTest, ViewTransitionRequestCausesDamage) {
const gfx::Size viewport_size(100, 100);
SetupDefaultRootLayer(viewport_size);
UpdateDrawProperties(host_impl_->active_tree());
@@ -18522,9 +18492,9 @@ TEST_F(LayerTreeHostImplTest, DocumentTransitionRequestCausesDamage) {
did_request_redraw_ = false;
// Adding a transition effect should cause us to redraw.
- host_impl_->active_tree()->AddDocumentTransitionRequest(
- DocumentTransitionRequest::CreateAnimateRenderer(
- /*document_tag=*/0));
+ host_impl_->active_tree()->AddViewTransitionRequest(
+ ViewTransitionRequest::CreateAnimateRenderer(
+ /*document_tag=*/0, viz::NavigationID::Null()));
// Ensure there is damage and we requested a redraw.
host_impl_->OnDraw(draw_transform, draw_viewport, resourceless_software_draw,
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc b/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc
index dd62f9fde19..f651da8e284 100644
--- a/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_filters.cc
@@ -637,6 +637,11 @@ TEST_P(LayerTreeHostFiltersPixelTest, ImageFilterScaled) {
}
TEST_P(LayerTreeHostFiltersPixelTest, BackdropFilterRotated) {
+ if (renderer_type() == viz::RendererType::kSkiaVk) {
+ // TODO(crbug.com/1354678): The vulkan expected image requires rebasing
+ // after Skia roll, so skip this test until then.
+ return;
+ }
// Add a white background with a rotated red rect in the center.
scoped_refptr<SolidColorLayer> background =
CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
@@ -904,7 +909,7 @@ TEST_P(LayerTreeHostFiltersPixelTest, RotatedDropShadowFilter) {
background->AddChild(child);
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS) || \
- defined(ARCH_CPU_ARM64) || defined(USE_OZONE)
+ defined(ARCH_CPU_ARM64) || BUILDFLAG(IS_OZONE)
#if defined(ARCH_CPU_ARM64) && \
(BUILDFLAG(IS_WIN) || BUILDFLAG(IS_FUCHSIA) || BUILDFLAG(IS_MAC))
// Windows, macOS, and Fuchsia on ARM64 has some pixels difference.
@@ -912,7 +917,7 @@ TEST_P(LayerTreeHostFiltersPixelTest, RotatedDropShadowFilter) {
float percentage_pixels_large_error = 0.89f;
float average_error_allowed_in_bad_pixels = 5.f;
int large_error_allowed = 17;
-#elif BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS) || defined(USE_OZONE)
+#elif BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_OZONE)
// There's a 1 pixel error on MacOS and ChromeOS
float percentage_pixels_large_error = 0.00111112f; // 1px / (300*300)
float average_error_allowed_in_bad_pixels = 1.f;
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc b/chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc
index 7d63bd26d77..48ba50f64f3 100644
--- a/chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc
@@ -56,11 +56,13 @@ class PaintedScrollbar : public FakeScrollbar {
flags.setColor(color_);
gfx::Rect inset_rect = rect;
while (!inset_rect.IsEmpty()) {
- int big = paint_scale_ + 2;
- int small = paint_scale_;
- inset_rect.Inset(gfx::Insets::TLBR(big, big, small, small));
+ int big_rect = paint_scale_ + 2;
+ int small_rect = paint_scale_;
+ inset_rect.Inset(
+ gfx::Insets::TLBR(big_rect, big_rect, small_rect, small_rect));
canvas->drawRect(RectToSkRect(inset_rect), flags);
- inset_rect.Inset(gfx::Insets::TLBR(big, big, small, small));
+ inset_rect.Inset(
+ gfx::Insets::TLBR(big_rect, big_rect, small_rect, small_rect));
}
}
@@ -155,7 +157,7 @@ TEST_P(LayerTreeHostScrollbarsPixelTest, MAYBE_HugeTransformScale) {
auto context = base::MakeRefCounted<viz::TestInProcessContextProvider>(
viz::TestContextType::kGLES2, /*support_locking=*/false);
- gpu::ContextResult result = context->BindToCurrentThread();
+ gpu::ContextResult result = context->BindToCurrentSequence();
DCHECK_EQ(result, gpu::ContextResult::kSuccess);
int max_texture_size = 0;
context->ContextGL()->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
diff --git a/chromium/cc/trees/layer_tree_host_unittest.cc b/chromium/cc/trees/layer_tree_host_unittest.cc
index fee74e4e00c..50b0d719c77 100644
--- a/chromium/cc/trees/layer_tree_host_unittest.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest.cc
@@ -27,7 +27,6 @@
#include "build/build_config.h"
#include "cc/animation/animation_host.h"
#include "cc/base/features.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"
@@ -70,6 +69,7 @@
#include "cc/trees/swap_promise.h"
#include "cc/trees/swap_promise_manager.h"
#include "cc/trees/transform_node.h"
+#include "cc/view_transition/view_transition_request.h"
#include "components/ukm/test_ukm_recorder.h"
#include "components/viz/common/features.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
@@ -6042,7 +6042,8 @@ class TestSwapPromise : public SwapPromise {
void DidSwap() override {}
- DidNotSwapAction DidNotSwap(DidNotSwapReason reason) override {
+ DidNotSwapAction DidNotSwap(DidNotSwapReason reason,
+ base::TimeTicks ts) override {
base::AutoLock lock(result_->lock);
EXPECT_FALSE(result_->did_swap_called);
EXPECT_FALSE(result_->did_not_swap_called);
@@ -8937,7 +8938,7 @@ class LayerTreeHostTestRequestForceSendMetadata
: target_(target) {}
// RenderFrameMetadataObserver implementation.
- void BindToCurrentThread() override { target_->BindToCurrentThread(); }
+ void BindToCurrentSequence() override { target_->BindToCurrentSequence(); }
void OnRenderFrameSubmission(
const RenderFrameMetadata& render_frame_metadata,
viz::CompositorFrameMetadata* compositor_frame_metadata,
@@ -8989,7 +8990,7 @@ class LayerTreeHostTestRequestForceSendMetadata
void AfterTest() override { EXPECT_EQ(1, num_force_sends_); }
// RenderFrameMetadataObserver implementation. Called on thread.
- void BindToCurrentThread() override {}
+ void BindToCurrentSequence() override {}
void OnRenderFrameSubmission(
const RenderFrameMetadata& render_frame_metadata,
viz::CompositorFrameMetadata* compositor_frame_metadata,
@@ -9172,7 +9173,7 @@ class LayerTreeHostTestDelegatedInkMetadataBase
: target_(target) {}
// RenderFrameMetadataObserver implementation.
- void BindToCurrentThread() override { target_->BindToCurrentThread(); }
+ void BindToCurrentSequence() override { target_->BindToCurrentSequence(); }
void OnRenderFrameSubmission(
const RenderFrameMetadata& render_frame_metadata,
viz::CompositorFrameMetadata* compositor_frame_metadata,
@@ -9246,7 +9247,7 @@ class LayerTreeHostTestDelegatedInkMetadataBase
}
// RenderFrameMetadataObserver implementation.
- void BindToCurrentThread() override {}
+ void BindToCurrentSequence() override {}
void OnRenderFrameSubmission(
const RenderFrameMetadata& render_frame_metadata,
viz::CompositorFrameMetadata* compositor_frame_metadata,
@@ -9488,8 +9489,8 @@ class LayerTreeHostTestEventsMetrics : public LayerTreeHostTest {
};
// Verifies that if the commit is aborted (deferred) due to LayerTreeHost being
-// hidden, events metrics are not thrown away to be used when it becomes
-// visible.
+// hidden, events metrics are discarded to prevent reporting arbitrarily large
+// latencies when the frame becomes visible again.
class LayerTreeHostTestKeepEventsMetricsForVisibility
: public LayerTreeHostTestEventsMetrics {
protected:
@@ -9521,19 +9522,20 @@ class LayerTreeHostTestKeepEventsMetricsForVisibility
EXPECT_EQ(reason, CommitEarlyOutReason::ABORTED_NOT_VISIBLE);
// Since the main frame is aborted due to invisibility, events metrics
- // should not have been thrown away.
- PostVerifyMainSavedEventsMetricsCount(1);
+ // should be discarded.
+ PostVerifyMainSavedEventsMetricsCount(0);
- // Make layer tree host visible so that the deferred commit is completed,
- // causing events metrics being passed to the impl thread.
+ // Make layer tree host visible so that the deferred commit is completed.
+ // Note that there is no events metrics to be passed to the impl thread.
PostSetLayerTreeHostVisible(true);
}
void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override {
- // Now that a commit is completed and activated, events metrics from main
- // thread should have been moved to the impl thread.
+ // Now a commit is completed and activated, but events metrics from main are
+ // already discarded, so there is no events metrics to be moved to the impl
+ // thread.
PostVerifyMainSavedEventsMetricsCount(0);
- EXPECT_SCOPED(VerifyImplEventsMetricsFromMainCount(impl, 1));
+ EXPECT_SCOPED(VerifyImplEventsMetricsFromMainCount(impl, 0));
EndTest();
}
@@ -9928,7 +9930,7 @@ class LayerTreeHostUkmSmoothnessMemoryOwnership : public LayerTreeTest {
MULTI_THREAD_TEST_F(LayerTreeHostUkmSmoothnessMemoryOwnership);
-class LayerTreeHostTestDocumentTransitionsPropagatedToMetadata
+class LayerTreeHostTestViewTransitionsPropagatedToMetadata
: public LayerTreeHostTest {
protected:
void SetupTree() override {
@@ -9937,9 +9939,10 @@ class LayerTreeHostTestDocumentTransitionsPropagatedToMetadata
}
void BeginTest() override {
- layer_tree_host()->AddDocumentTransitionRequest(
- DocumentTransitionRequest::CreateCapture(
- /*document_tag=*/0, /*shared_element_count=*/0, {},
+ layer_tree_host()->AddViewTransitionRequest(
+ ViewTransitionRequest::CreateCapture(
+ /*document_tag=*/0, /*shared_element_count=*/0,
+ viz::NavigationID::Null(), {},
base::BindLambdaForTesting([this]() { CommitLambdaCalled(); })));
}
@@ -9968,7 +9971,7 @@ class LayerTreeHostTestDocumentTransitionsPropagatedToMetadata
};
SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeHostTestDocumentTransitionsPropagatedToMetadata);
+ LayerTreeHostTestViewTransitionsPropagatedToMetadata);
class LayerTreeHostTestDebugStateDowngrade : public LayerTreeHostTest {
void InitializeSettings(LayerTreeSettings* settings) override {
@@ -10648,7 +10651,7 @@ class LayerTreeHostTestBeginFramePausedChanged : public LayerTreeHostTest {
}
private:
- TestLayerTreeFrameSink* layer_tree_frame_sink_;
+ raw_ptr<TestLayerTreeFrameSink> layer_tree_frame_sink_;
};
MULTI_THREAD_TEST_F(LayerTreeHostTestBeginFramePausedChanged);
@@ -10731,5 +10734,108 @@ class LayerTreeHostUpdateViewportContainerSize : public LayerTreeHostTest {
MULTI_THREAD_TEST_F(LayerTreeHostUpdateViewportContainerSize);
+// Ensures that a change in LCD text status forces tilings to be recreated on
+// the pending tree even during accelerated gestures (scrolling and pinch zoom)
+// and animations.
+class LayerTreeHostTestForceRecreateTilingForLCDText
+ : public LayerTreeHostTestWithHelper {
+ public:
+ LayerTreeHostTestForceRecreateTilingForLCDText() {}
+
+ void SetupTree() override {
+ client_.set_fill_with_nonsolid_color(true);
+ client_.set_has_draw_text_op();
+
+ scoped_refptr<FakePictureLayer> root_layer =
+ FakePictureLayer::Create(&client_);
+ root_layer->SetBounds(gfx::Size(150, 150));
+ root_layer->SetIsDrawable(true);
+
+ layer_on_main_ =
+ CreateAndAddFakePictureLayer(gfx::Size(30, 30), root_layer.get());
+
+ layer_tree_host()->SetRootLayer(root_layer);
+ LayerTreeHostTest::SetupTree();
+ client_.set_bounds(root_layer->bounds());
+
+ layer_id_ = layer_on_main_->id();
+ }
+
+ void WillCommit(const CommitState&) override {
+ switch (layer_tree_host()->SourceFrameNumber()) {
+ case 0:
+ // First frame enables LCD text by marking the layer opaque.
+ layer_on_main_->SetContentsOpaque(true);
+ layer_on_main_->SetBackgroundColor(SkColor4f::FromColor(SK_ColorBLACK));
+ break;
+ case 1:
+ // Now mark the layer non-opaque to disable LCD text.
+ layer_on_main_->SetContentsOpaque(false);
+ break;
+ case 2:
+ // Back to LCD text.
+ layer_on_main_->SetContentsOpaque(true);
+ break;
+ case 3:
+ // Disable LCD text from non-opaque background.
+ layer_on_main_->SetContentsOpaque(false);
+ layer_on_main_->SetBackgroundColor(
+ SkColor4f::FromColor(SK_ColorTRANSPARENT));
+ break;
+ }
+ }
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
+ FakePictureLayerImpl* layer_impl = static_cast<FakePictureLayerImpl*>(
+ host_impl->pending_tree()->LayerById(layer_id_));
+
+ switch (host_impl->pending_tree()->source_frame_number()) {
+ case 0:
+ ASSERT_FALSE(host_impl->IsPinchGestureActive());
+ EXPECT_TRUE(layer_impl->can_use_lcd_text());
+ EXPECT_TRUE(layer_impl->HighResTiling()->can_use_lcd_text());
+ host_impl->GetInputHandler().PinchGestureBegin(
+ gfx::Point(1, 1), ui::ScrollInputType::kWheel);
+ PostSetNeedsCommitToMainThread();
+ break;
+ case 1:
+ ASSERT_TRUE(host_impl->IsPinchGestureActive());
+ EXPECT_FALSE(layer_impl->can_use_lcd_text());
+ EXPECT_EQ(layer_impl->lcd_text_disallowed_reason(),
+ LCDTextDisallowedReason::kContentsNotOpaque);
+ EXPECT_FALSE(layer_impl->HighResTiling()->can_use_lcd_text());
+ host_impl->GetInputHandler().PinchGestureEnd(gfx::Point(1, 1));
+ break;
+ case 2:
+ ASSERT_FALSE(host_impl->IsPinchGestureActive());
+ EXPECT_TRUE(layer_impl->can_use_lcd_text());
+ EXPECT_TRUE(layer_impl->HighResTiling()->can_use_lcd_text());
+ host_impl->GetInputHandler().PinchGestureBegin(
+ gfx::Point(1, 1), ui::ScrollInputType::kWheel);
+ PostSetNeedsCommitToMainThread();
+ break;
+ case 3:
+ ASSERT_TRUE(host_impl->IsPinchGestureActive());
+ EXPECT_FALSE(layer_impl->can_use_lcd_text());
+ EXPECT_EQ(layer_impl->lcd_text_disallowed_reason(),
+ LCDTextDisallowedReason::kBackgroundColorNotOpaque);
+ EXPECT_FALSE(layer_impl->HighResTiling()->can_use_lcd_text());
+ EndTest();
+ break;
+ }
+ }
+
+ protected:
+ // main and impl thread.
+ int layer_id_;
+
+ // main thread only
+ FakeContentLayerClient client_;
+ scoped_refptr<FakePictureLayer> layer_on_main_;
+};
+MULTI_THREAD_TEST_F(LayerTreeHostTestForceRecreateTilingForLCDText);
+
} // 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 e8db591a42e..d4f459f84b8 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_animation.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_animation.cc
@@ -1043,9 +1043,10 @@ class LayerTreeHostPresentationDuringAnimation
if (const_cast<const LayerTreeHost*>(layer_tree_host())
->pending_commit_state()
->source_frame_number == 2) {
- layer_tree_host()->RequestPresentationTimeForNextFrame(base::BindOnce(
- &LayerTreeHostPresentationDuringAnimation::OnPresentation,
- base::Unretained(this)));
+ layer_tree_host()->RequestSuccessfulPresentationTimeForNextFrame(
+ base::BindOnce(
+ &LayerTreeHostPresentationDuringAnimation::OnPresentation,
+ base::Unretained(this)));
}
}
@@ -1079,7 +1080,7 @@ class LayerTreeHostPresentationDuringAnimation
}
private:
- void OnPresentation(const gfx::PresentationFeedback& feedback) { EndTest(); }
+ void OnPresentation(base::TimeTicks presentation_timestamp) { EndTest(); }
FakeContentLayerClient client_;
scoped_refptr<FakePictureLayer> scroll_layer_;
diff --git a/chromium/cc/trees/layer_tree_host_unittest_context.cc b/chromium/cc/trees/layer_tree_host_unittest_context.cc
index 68bfcd52739..83a9a0d2aad 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_context.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_context.cc
@@ -94,7 +94,6 @@ class LayerTreeHostContextTest : public LayerTreeTest {
auto gl_owned = std::make_unique<viz::TestGLES2Interface>();
if (context_should_support_io_surface_) {
- gl_owned->set_have_extension_io_surface(true);
gl_owned->set_have_extension_egl_image(true);
}
@@ -815,7 +814,7 @@ class LayerTreeHostContextTestDontUseLostResources
context_should_support_io_surface_ = true;
child_context_provider_ = viz::TestContextProvider::Create();
- auto result = child_context_provider_->BindToCurrentThread();
+ auto result = child_context_provider_->BindToCurrentSequence();
CHECK_EQ(result, gpu::ContextResult::kSuccess);
shared_bitmap_manager_ = std::make_unique<viz::TestSharedBitmapManager>();
child_resource_provider_ = std::make_unique<viz::ClientResourceProvider>();
diff --git a/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc b/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc
index 3135db07250..c7aec1ec490 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_copyrequest.cc
@@ -10,7 +10,6 @@
#include "base/synchronization/waitable_event.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/test_timeouts.h"
-#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "cc/layers/effect_tree_layer_list_iterator.h"
#include "cc/test/cc_test_suite.h"
@@ -85,7 +84,7 @@ class LayerTreeHostCopyRequestTestMultipleRequests
void DidCommit() override { WaitForCallback(); }
void WaitForCallback() {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
+ base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(&LayerTreeHostCopyRequestTestMultipleRequests::NextStep,
base::Unretained(this)));
@@ -877,7 +876,7 @@ class LayerTreeHostCopyRequestTestDeleteSharedImage
std::unique_ptr<viz::SkiaOutputSurface> CreateSkiaOutputSurfaceOnThread(
viz::DisplayCompositorMemoryAndTaskController*) override {
display_context_provider_ = viz::TestContextProvider::Create();
- display_context_provider_->BindToCurrentThread();
+ display_context_provider_->BindToCurrentSequence();
return viz::FakeSkiaOutputSurface::Create3d(display_context_provider_);
}
@@ -1022,7 +1021,7 @@ class LayerTreeHostCopyRequestTestCountSharedImages
std::unique_ptr<viz::SkiaOutputSurface> CreateSkiaOutputSurfaceOnThread(
viz::DisplayCompositorMemoryAndTaskController*) override {
display_context_provider_ = viz::TestContextProvider::Create();
- display_context_provider_->BindToCurrentThread();
+ display_context_provider_->BindToCurrentSequence();
return viz::FakeSkiaOutputSurface::Create3d(display_context_provider_);
}
diff --git a/chromium/cc/trees/layer_tree_impl.cc b/chromium/cc/trees/layer_tree_impl.cc
index a22b342349d..ce9eba96e1e 100644
--- a/chromium/cc/trees/layer_tree_impl.cc
+++ b/chromium/cc/trees/layer_tree_impl.cc
@@ -26,6 +26,7 @@
#include "base/notreached.h"
#include "base/ranges/algorithm.h"
#include "base/strings/stringprintf.h"
+#include "base/time/time.h"
#include "base/timer/elapsed_timer.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/traced_value.h"
@@ -34,7 +35,6 @@
#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"
@@ -54,6 +54,7 @@
#include "cc/trees/scroll_node.h"
#include "cc/trees/transform_node.h"
#include "cc/trees/tree_synchronizer.h"
+#include "cc/view_transition/view_transition_request.h"
#include "components/viz/common/traced_value.h"
#include "ui/gfx/geometry/box_f.h"
#include "ui/gfx/geometry/point_conversions.h"
@@ -599,10 +600,10 @@ void LayerTreeImpl::PullPropertiesFrom(
ForceRedrawNextActivation();
if (commit_state.next_commit_forces_recalculate_raster_scales)
ForceRecalculateRasterScales();
- if (!commit_state.pending_presentation_time_callbacks.empty()) {
- AddPresentationCallbacks(
- std::move(commit_state.pending_presentation_time_callbacks));
- }
+ AddPresentationCallbacks(
+ std::move(commit_state.pending_presentation_callbacks));
+ AddSuccessfulPresentationCallbacks(
+ std::move(commit_state.pending_successful_presentation_callbacks));
if (commit_state.needs_full_tree_sync)
TreeSynchronizer::SynchronizeTrees(commit_state, unsafe_state, this);
@@ -743,8 +744,8 @@ void LayerTreeImpl::PullLayerTreePropertiesFrom(CommitState& commit_state) {
delegated_ink_metadata_.reset();
// Transfer page transition directives.
- for (auto& request : commit_state.document_transition_requests)
- AddDocumentTransitionRequest(std::move(request));
+ for (auto& request : commit_state.view_transition_requests)
+ AddViewTransitionRequest(std::move(request));
SetVisualUpdateDurations(
commit_state.previous_surfaces_visual_update_duration,
@@ -862,6 +863,9 @@ void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) {
target_tree->HandleScrollbarShowRequests();
target_tree->AddPresentationCallbacks(std::move(presentation_callbacks_));
presentation_callbacks_.clear();
+ target_tree->AddSuccessfulPresentationCallbacks(
+ std::move(successful_presentation_callbacks_));
+ successful_presentation_callbacks_.clear();
if (delegated_ink_metadata_) {
TRACE_EVENT_WITH_FLOW1("delegated_ink_trails",
@@ -874,8 +878,8 @@ void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) {
target_tree->clear_delegated_ink_metadata();
}
- for (auto& request : TakeDocumentTransitionRequests())
- target_tree->AddDocumentTransitionRequest(std::move(request));
+ for (auto& request : TakeViewTransitionRequests())
+ target_tree->AddViewTransitionRequest(std::move(request));
target_tree->SetVisualUpdateDurations(
previous_surfaces_visual_update_duration_, visual_update_duration_);
@@ -997,19 +1001,30 @@ void LayerTreeImpl::SetBackdropFilterMutated(
}
void LayerTreeImpl::AddPresentationCallbacks(
- std::vector<PresentationTimeCallbackBuffer::MainCallback> callbacks) {
- std::copy(std::make_move_iterator(callbacks.begin()),
- std::make_move_iterator(callbacks.end()),
- std::back_inserter(presentation_callbacks_));
+ std::vector<PresentationTimeCallbackBuffer::Callback> callbacks) {
+ base::ranges::move(callbacks, std::back_inserter(presentation_callbacks_));
}
-std::vector<PresentationTimeCallbackBuffer::MainCallback>
+std::vector<PresentationTimeCallbackBuffer::Callback>
LayerTreeImpl::TakePresentationCallbacks() {
- std::vector<PresentationTimeCallbackBuffer::MainCallback> callbacks;
+ std::vector<PresentationTimeCallbackBuffer::Callback> callbacks;
callbacks.swap(presentation_callbacks_);
return callbacks;
}
+void LayerTreeImpl::AddSuccessfulPresentationCallbacks(
+ std::vector<PresentationTimeCallbackBuffer::SuccessfulCallback> callbacks) {
+ base::ranges::move(callbacks,
+ std::back_inserter(successful_presentation_callbacks_));
+}
+
+std::vector<PresentationTimeCallbackBuffer::SuccessfulCallback>
+LayerTreeImpl::TakeSuccessfulPresentationCallbacks() {
+ std::vector<PresentationTimeCallbackBuffer::SuccessfulCallback> callbacks;
+ callbacks.swap(successful_presentation_callbacks_);
+ return callbacks;
+}
+
LayerImpl* LayerTreeImpl::InnerViewportScrollLayerForTesting() const {
if (auto* scroll_node = InnerViewportScrollNode())
return LayerByElementId(scroll_node->element_id);
@@ -1515,10 +1530,6 @@ const TransformNode* LayerTreeImpl::OverscrollElasticityTransformNode() const {
viewport_property_ids_.overscroll_elasticity_transform);
}
-ElementId LayerTreeImpl::OverscrollElasticityEffectElementId() const {
- return viewport_property_ids_.overscroll_elasticity_effect;
-}
-
const TransformNode* LayerTreeImpl::PageScaleTransformNode() const {
return property_trees()->transform_tree().Node(
viewport_property_ids_.page_scale_transform);
@@ -1844,7 +1855,7 @@ TileManager* LayerTreeImpl::tile_manager() const {
}
ImageDecodeCache* LayerTreeImpl::image_decode_cache() const {
- return host_impl_->image_decode_cache();
+ return host_impl_->GetImageDecodeCache();
}
ImageAnimationController* LayerTreeImpl::image_animation_controller() const {
@@ -2022,8 +2033,9 @@ void LayerTreeImpl::QueuePinnedSwapPromise(
void LayerTreeImpl::PassSwapPromises(
std::vector<std::unique_ptr<SwapPromise>> new_swap_promises) {
+ base::TimeTicks timestamp = base::TimeTicks::Now();
for (auto& swap_promise : swap_promise_list_) {
- if (swap_promise->DidNotSwap(SwapPromise::SWAP_FAILS) ==
+ if (swap_promise->DidNotSwap(SwapPromise::SWAP_FAILS, timestamp) ==
SwapPromise::DidNotSwapAction::KEEP_ACTIVE) {
// |swap_promise| must remain active, so place it in |new_swap_promises|
// in order to keep it alive and active.
@@ -2058,10 +2070,11 @@ void LayerTreeImpl::ClearSwapPromises() {
}
void LayerTreeImpl::BreakSwapPromises(SwapPromise::DidNotSwapReason reason) {
+ base::TimeTicks invocation_timestamp = base::TimeTicks::Now();
{
std::vector<std::unique_ptr<SwapPromise>> persistent_swap_promises;
for (auto& swap_promise : swap_promise_list_) {
- if (swap_promise->DidNotSwap(reason) ==
+ if (swap_promise->DidNotSwap(reason, invocation_timestamp) ==
SwapPromise::DidNotSwapAction::KEEP_ACTIVE) {
persistent_swap_promises.push_back(std::move(swap_promise));
}
@@ -2073,7 +2086,7 @@ void LayerTreeImpl::BreakSwapPromises(SwapPromise::DidNotSwapReason reason) {
{
std::vector<std::unique_ptr<SwapPromise>> persistent_swap_promises;
for (auto& swap_promise : pinned_swap_promise_list_) {
- if (swap_promise->DidNotSwap(reason) ==
+ if (swap_promise->DidNotSwap(reason, invocation_timestamp) ==
SwapPromise::DidNotSwapAction::KEEP_ACTIVE) {
persistent_swap_promises.push_back(std::move(swap_promise));
}
@@ -2112,9 +2125,6 @@ void LayerTreeImpl::ProcessUIResourceRequestQueue() {
case UIResourceRequest::UI_RESOURCE_DELETE:
host_impl_->DeleteUIResource(req.GetId());
break;
- case UIResourceRequest::UI_RESOURCE_INVALID_REQUEST:
- NOTREACHED();
- break;
}
}
ui_resource_request_queue_.clear();
@@ -2242,8 +2252,7 @@ static bool PointHitsRect(
float* distance_to_camera) {
// If the transform is not invertible, then assume that this point doesn't hit
// this rect.
- gfx::Transform inverse_local_space_to_screen_space(
- gfx::Transform::kSkipInitialization);
+ gfx::Transform inverse_local_space_to_screen_space;
if (!local_space_to_screen_space_transform.GetInverse(
&inverse_local_space_to_screen_space))
return false;
@@ -2329,8 +2338,7 @@ static bool PointHitsRegion(const gfx::PointF& screen_space_point,
// If the transform is not invertible, then assume that this point doesn't hit
// this region.
- gfx::Transform inverse_screen_space_transform(
- gfx::Transform::kSkipInitialization);
+ gfx::Transform inverse_screen_space_transform;
if (!screen_space_transform.GetInverse(&inverse_screen_space_transform))
return false;
@@ -2907,20 +2915,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));
+void LayerTreeImpl::AddViewTransitionRequest(
+ std::unique_ptr<ViewTransitionRequest> request) {
+ view_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_);
+std::vector<std::unique_ptr<ViewTransitionRequest>>
+LayerTreeImpl::TakeViewTransitionRequests() {
+ return std::move(view_transition_requests_);
}
-bool LayerTreeImpl::HasDocumentTransitionRequests() const {
- return !document_transition_requests_.empty();
+bool LayerTreeImpl::HasViewTransitionRequests() const {
+ return !view_transition_requests_.empty();
}
bool LayerTreeImpl::IsReadyToActivate() const {
diff --git a/chromium/cc/trees/layer_tree_impl.h b/chromium/cc/trees/layer_tree_impl.h
index bc0a7f3b10b..9a1ce83429d 100644
--- a/chromium/cc/trees/layer_tree_impl.h
+++ b/chromium/cc/trees/layer_tree_impl.h
@@ -49,7 +49,7 @@ namespace cc {
enum class ActivelyScrollingType;
class DebugRectHistory;
-class DocumentTransitionRequest;
+class ViewTransitionRequest;
class DroppedFrameCounter;
class HeadsUpDisplayLayerImpl;
class ImageDecodeCache;
@@ -313,12 +313,15 @@ class CC_EXPORT LayerTreeImpl {
gfx::PointF TotalMaxScrollOffset() const;
void AddPresentationCallbacks(
- std::vector<PresentationTimeCallbackBuffer::MainCallback> callbacks);
- std::vector<PresentationTimeCallbackBuffer::MainCallback>
+ std::vector<PresentationTimeCallbackBuffer::Callback> callbacks);
+ std::vector<PresentationTimeCallbackBuffer::Callback>
TakePresentationCallbacks();
- bool has_presentation_callbacks() const {
- return !presentation_callbacks_.empty();
- }
+
+ void AddSuccessfulPresentationCallbacks(
+ std::vector<PresentationTimeCallbackBuffer::SuccessfulCallback>
+ callbacks);
+ std::vector<PresentationTimeCallbackBuffer::SuccessfulCallback>
+ TakeSuccessfulPresentationCallbacks();
// The following viewport related property nodes will only ever be set on the
// main-frame's renderer (i.e. OOPIF and UI compositors will not have these
@@ -331,7 +334,6 @@ class CC_EXPORT LayerTreeImpl {
const_cast<const LayerTreeImpl*>(this)
->OverscrollElasticityTransformNode());
}
- ElementId OverscrollElasticityEffectElementId() const;
const TransformNode* PageScaleTransformNode() const;
TransformNode* PageScaleTransformNode() {
return const_cast<TransformNode*>(
@@ -791,16 +793,15 @@ class CC_EXPORT LayerTreeImpl {
return host_impl_->viewport_mobile_optimized();
}
- // Add a document transition request from the embedder.
- void AddDocumentTransitionRequest(
- std::unique_ptr<DocumentTransitionRequest> request);
+ // Add a view transition request from the embedder.
+ void AddViewTransitionRequest(std::unique_ptr<ViewTransitionRequest> request);
- // Returns all of the document transition requests stored so far, and empties
+ // Returns all of the view transition requests stored so far, and empties
// the internal list.
- std::vector<std::unique_ptr<DocumentTransitionRequest>>
- TakeDocumentTransitionRequests();
+ std::vector<std::unique_ptr<ViewTransitionRequest>>
+ TakeViewTransitionRequests();
- bool HasDocumentTransitionRequests() const;
+ bool HasViewTransitionRequests() const;
void ClearVisualUpdateDurations();
void SetVisualUpdateDurations(
@@ -960,8 +961,9 @@ class CC_EXPORT LayerTreeImpl {
// Display transform hint to tag frames generated from this tree.
gfx::OverlayTransform display_transform_hint_ = gfx::OVERLAY_TRANSFORM_NONE;
- std::vector<PresentationTimeCallbackBuffer::MainCallback>
- presentation_callbacks_;
+ std::vector<PresentationTimeCallbackBuffer::Callback> presentation_callbacks_;
+ std::vector<PresentationTimeCallbackBuffer::SuccessfulCallback>
+ successful_presentation_callbacks_;
// Event metrics that are reported back from the main thread.
EventMetrics::List events_metrics_from_main_thread_;
@@ -969,8 +971,7 @@ class CC_EXPORT LayerTreeImpl {
std::unique_ptr<gfx::DelegatedInkMetadata> delegated_ink_metadata_;
// Document transition requests to be transferred to Viz.
- std::vector<std::unique_ptr<DocumentTransitionRequest>>
- document_transition_requests_;
+ std::vector<std::unique_ptr<ViewTransitionRequest>> view_transition_requests_;
// The cumulative time spent performing visual updates for all Surfaces before
// this one.
diff --git a/chromium/cc/trees/layer_tree_impl_unittest.cc b/chromium/cc/trees/layer_tree_impl_unittest.cc
index 37382cfba37..2f7ed539c73 100644
--- a/chromium/cc/trees/layer_tree_impl_unittest.cc
+++ b/chromium/cc/trees/layer_tree_impl_unittest.cc
@@ -6,6 +6,7 @@
#include "base/cxx17_backports.h"
#include "base/memory/raw_ptr.h"
+#include "base/time/time.h"
#include "cc/layers/heads_up_display_layer_impl.h"
#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/fake_raster_source.h"
@@ -2133,8 +2134,7 @@ TEST_F(LayerTreeImplTest, SelectionBoundsWithLargeTransforms) {
LayerImpl* root = root_layer();
root->SetBounds(gfx::Size(100, 100));
- gfx::Transform large_transform;
- large_transform.Scale(SkDoubleToScalar(1e37), SkDoubleToScalar(1e37));
+ gfx::Transform large_transform = gfx::Transform::MakeScale(1e37);
large_transform.RotateAboutYAxis(30);
LayerImpl* child = AddLayer<LayerImpl>();
@@ -2322,7 +2322,8 @@ class PersistentSwapPromise
MOCK_METHOD1(WillSwap, void(viz::CompositorFrameMetadata* metadata));
MOCK_METHOD0(DidSwap, void());
- DidNotSwapAction DidNotSwap(DidNotSwapReason reason) override {
+ DidNotSwapAction DidNotSwap(DidNotSwapReason reason,
+ base::TimeTicks ts) override {
return DidNotSwapAction::KEEP_ACTIVE;
}
int64_t GetTraceId() const override { return 0; }
@@ -2339,7 +2340,8 @@ class NotPersistentSwapPromise
void WillSwap(viz::CompositorFrameMetadata* metadata) override {}
void DidSwap() override {}
- DidNotSwapAction DidNotSwap(DidNotSwapReason reason) override {
+ DidNotSwapAction DidNotSwap(DidNotSwapReason reason,
+ base::TimeTicks ts) override {
return DidNotSwapAction::BREAK_PROMISE;
}
int64_t GetTraceId() const override { return 0; }
diff --git a/chromium/cc/trees/layer_tree_settings.h b/chromium/cc/trees/layer_tree_settings.h
index d9b3e3cbeb7..012e0f781d2 100644
--- a/chromium/cc/trees/layer_tree_settings.h
+++ b/chromium/cc/trees/layer_tree_settings.h
@@ -181,9 +181,6 @@ class CC_EXPORT LayerTreeSettings {
// Defaults to true.
bool enable_occlusion = true;
- // Whether experimental de-jelly effect is allowed.
- bool allow_de_jelly_effect = false;
-
// Whether the compositor should attempt to sync with the scroll handlers
// before submitting a frame.
bool enable_synchronized_scrolling = true;
@@ -216,9 +213,6 @@ class CC_EXPORT LayerTreeSettings {
// to find the link to the Fluent Scrollbar spec and related CLs.
bool enable_fluent_scrollbar = false;
- // This corresponds to the ScrollUpdateOptimizations feature.
- bool enable_scroll_update_optimizations = false;
-
// Whether to disable the frame rate limit in the scheduler.
bool disable_frame_rate_limit = false;
@@ -226,6 +220,10 @@ class CC_EXPORT LayerTreeSettings {
// not be synchronized at the beginning of the frame because main frames were
// being deferred.
bool skip_commits_if_not_synchronizing_compositor_state = true;
+
+ // Enables shared image cache for gpu.
+ // TODO(crbug.com/1378251): not ready to be used by renderer cc instance yet.
+ bool enable_shared_image_cache_for_gpu = false;
};
class CC_EXPORT LayerListSettings : public LayerTreeSettings {
diff --git a/chromium/cc/trees/occlusion.cc b/chromium/cc/trees/occlusion.cc
index a0664c7ea3d..5ced73122a1 100644
--- a/chromium/cc/trees/occlusion.cc
+++ b/chromium/cc/trees/occlusion.cc
@@ -56,7 +56,7 @@ gfx::Rect Occlusion::GetUnoccludedContentRect(
if (unoccluded_rect_in_target_surface.IsEmpty())
return gfx::Rect();
- gfx::Transform inverse_draw_transform(gfx::Transform::kSkipInitialization);
+ gfx::Transform inverse_draw_transform;
bool ok = draw_transform_.GetInverse(&inverse_draw_transform);
// TODO(ajuma): Skip drawing layers with uninvertible draw transforms, and
// change this to a DCHECK. crbug.com/517170
diff --git a/chromium/cc/trees/occlusion_tracker.cc b/chromium/cc/trees/occlusion_tracker.cc
index fdb210cf66c..64c2a99a426 100644
--- a/chromium/cc/trees/occlusion_tracker.cc
+++ b/chromium/cc/trees/occlusion_tracker.cc
@@ -81,8 +81,7 @@ void OcclusionTracker::LeaveLayer(
static gfx::Rect ScreenSpaceClipRectInTargetSurface(
const RenderSurfaceImpl* target_surface,
const gfx::Rect& screen_space_clip_rect) {
- gfx::Transform inverse_screen_space_transform(
- gfx::Transform::kSkipInitialization);
+ gfx::Transform inverse_screen_space_transform;
if (!target_surface->screen_space_transform().GetInverse(
&inverse_screen_space_transform))
return target_surface->content_rect();
@@ -147,9 +146,7 @@ void OcclusionTracker::EnterRenderTarget(
new_occlusion_immune_ancestor &&
new_occlusion_immune_ancestor != old_occlusion_immune_ancestor;
- gfx::Transform inverse_new_target_screen_space_transform(
- // Note carefully, not used if screen space transform is uninvertible.
- gfx::Transform::kSkipInitialization);
+ gfx::Transform inverse_new_target_screen_space_transform;
bool have_transform_from_screen_to_new_target =
new_target_surface->screen_space_transform().GetInverse(
&inverse_new_target_screen_space_transform);
@@ -205,7 +202,7 @@ void OcclusionTracker::FinishedRenderTarget(
!IsOccludingBlendMode(finished_target_surface->BlendMode()) ||
target_is_only_for_copy_request_or_force_render_surface ||
finished_target_surface->Filters().HasFilterThatAffectsOpacity() ||
- finished_target_surface->GetDocumentTransitionSharedElementId().valid()) {
+ finished_target_surface->GetViewTransitionElementId().valid()) {
stack_.back().occlusion_from_outside_target.Clear();
stack_.back().occlusion_from_inside_target.Clear();
}
@@ -228,12 +225,8 @@ static void ReduceOcclusionBelowSurface(
return;
gfx::Rect affected_area_in_target =
- contributing_surface->BackdropFilters().HasFilterOfType(
- FilterOperation::FilterType::BLUR)
- ? contributing_surface->BackdropFilters().MapRect(target_rect,
- SkMatrix::I())
- : contributing_surface->BackdropFilters().MapRectReverse(
- target_rect, SkMatrix::I());
+ contributing_surface->BackdropFilters().MapRectReverse(target_rect,
+ SkMatrix::I());
// Unite target_rect because we only care about positive outsets.
affected_area_in_target.Union(target_rect);
diff --git a/chromium/cc/trees/paint_holding_commit_trigger.cc b/chromium/cc/trees/paint_holding_commit_trigger.cc
index fd67cb711ca..ac2e1d788a4 100644
--- a/chromium/cc/trees/paint_holding_commit_trigger.cc
+++ b/chromium/cc/trees/paint_holding_commit_trigger.cc
@@ -12,8 +12,8 @@ PaintHoldingCommitTrigger ReasonToTimeoutTrigger(PaintHoldingReason reason) {
switch (reason) {
case PaintHoldingReason::kFirstContentfulPaint:
return PaintHoldingCommitTrigger::kTimeoutFCP;
- case PaintHoldingReason::kDocumentTransition:
- return PaintHoldingCommitTrigger::kTimeoutDocumentTransition;
+ case PaintHoldingReason::kViewTransition:
+ return PaintHoldingCommitTrigger::kTimeoutViewTransition;
}
NOTREACHED();
return PaintHoldingCommitTrigger::kTimeoutFCP;
diff --git a/chromium/cc/trees/paint_holding_commit_trigger.h b/chromium/cc/trees/paint_holding_commit_trigger.h
index b9869f04beb..a86e96e5876 100644
--- a/chromium/cc/trees/paint_holding_commit_trigger.h
+++ b/chromium/cc/trees/paint_holding_commit_trigger.h
@@ -23,12 +23,12 @@ enum class PaintHoldingCommitTrigger {
kTimeoutFCP = 3,
// The timeout was never set, probably due to non-main frame
kNotDeferred = 4,
- // The commit was triggered by a document transition start
- kDocumentTransition = 5,
- // The commit was triggered by a timeout waiting for document transition start
- kTimeoutDocumentTransition = 6,
+ // The commit was triggered by a view transition start
+ kViewTransition = 5,
+ // The commit was triggered by a timeout waiting for view transition start
+ kTimeoutViewTransition = 6,
// Required for UMA enum
- kMaxValue = kTimeoutDocumentTransition
+ kMaxValue = kTimeoutViewTransition
};
PaintHoldingCommitTrigger ReasonToTimeoutTrigger(PaintHoldingReason reason);
diff --git a/chromium/cc/trees/paint_holding_reason.h b/chromium/cc/trees/paint_holding_reason.h
index a97c2d59ceb..066195c76af 100644
--- a/chromium/cc/trees/paint_holding_reason.h
+++ b/chromium/cc/trees/paint_holding_reason.h
@@ -13,7 +13,7 @@ enum class PaintHoldingReason {
// Deferred to allow the document to be updated asynchronously for a
// transition.
- kDocumentTransition,
+ kViewTransition,
};
} // namespace cc
diff --git a/chromium/cc/trees/presentation_time_callback_buffer.cc b/chromium/cc/trees/presentation_time_callback_buffer.cc
index 12dc2b2a5e1..21e46119bf2 100644
--- a/chromium/cc/trees/presentation_time_callback_buffer.cc
+++ b/chromium/cc/trees/presentation_time_callback_buffer.cc
@@ -37,26 +37,44 @@ PresentationTimeCallbackBuffer::FrameTokenInfo::operator=(FrameTokenInfo&&) =
default;
PresentationTimeCallbackBuffer::FrameTokenInfo::~FrameTokenInfo() = default;
-void PresentationTimeCallbackBuffer::RegisterMainThreadPresentationCallbacks(
+void PresentationTimeCallbackBuffer::RegisterMainThreadCallbacks(
uint32_t frame_token,
- std::vector<MainCallback> callbacks) {
+ std::vector<Callback> callbacks) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- FrameTokenInfo& frame_info = GetOrMakeRegistration(frame_token);
+ if (callbacks.empty())
+ return;
- // Splice the given |callbacks| onto the vector of existing callbacks.
- auto& sink = frame_info.main_thread_callbacks;
+ // Splice the given `callbacks` onto the vector of existing callbacks.
+ auto& sink = GetOrMakeRegistration(frame_token).main_callbacks;
sink.reserve(sink.size() + callbacks.size());
- std::move(callbacks.begin(), callbacks.end(), std::back_inserter(sink));
+ base::ranges::move(callbacks, std::back_inserter(sink));
}
-void PresentationTimeCallbackBuffer::RegisterCompositorPresentationCallbacks(
+void PresentationTimeCallbackBuffer::RegisterMainThreadSuccessfulCallbacks(
uint32_t frame_token,
- std::vector<CompositorCallback> callbacks) {
+ std::vector<SuccessfulCallback> callbacks) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (callbacks.empty())
+ return;
+
+ // Splice the given `callbacks` onto the vector of existing callbacks.
+ auto& sink = GetOrMakeRegistration(frame_token).main_successful_callbacks;
+ sink.reserve(sink.size() + callbacks.size());
+ base::ranges::move(callbacks, std::back_inserter(sink));
+}
+
+void PresentationTimeCallbackBuffer::
+ RegisterCompositorThreadSuccessfulCallbacks(
+ uint32_t frame_token,
+ std::vector<SuccessfulCallback> callbacks) {
+ if (callbacks.empty())
+ return;
+
// Splice the given |callbacks| onto the vector of existing callbacks.
- std::vector<CompositorCallback>& sink =
- GetOrMakeRegistration(frame_token).compositor_thread_callbacks;
+ std::vector<SuccessfulCallback>& sink =
+ GetOrMakeRegistration(frame_token).compositor_successful_callbacks;
sink.reserve(sink.size() + callbacks.size());
- std::move(callbacks.begin(), callbacks.end(), std::back_inserter(sink));
+ base::ranges::move(callbacks, std::back_inserter(sink));
}
PresentationTimeCallbackBuffer::PendingCallbacks::PendingCallbacks() = default;
@@ -69,7 +87,7 @@ PresentationTimeCallbackBuffer::PendingCallbacks::~PendingCallbacks() = default;
PresentationTimeCallbackBuffer::PendingCallbacks
PresentationTimeCallbackBuffer::PopPendingCallbacks(uint32_t frame_token,
- bool main_only) {
+ bool presentation_failed) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
PendingCallbacks result;
@@ -79,20 +97,26 @@ PresentationTimeCallbackBuffer::PopPendingCallbacks(uint32_t frame_token,
if (viz::FrameTokenGT(info->token, frame_token))
break;
- std::move(info->main_thread_callbacks.begin(),
- info->main_thread_callbacks.end(),
- std::back_inserter(result.main_thread_callbacks));
- info->main_thread_callbacks.clear();
+ // Presentation time callbacks should be run whether presentation was
+ // successful or not.
+ base::ranges::move(info->main_callbacks,
+ std::back_inserter(result.main_callbacks));
+ info->main_callbacks.clear();
- const bool should_keep_callbacks =
- main_only && !info->compositor_thread_callbacks.empty();
+ const bool should_keep_info =
+ presentation_failed && (!info->main_successful_callbacks.empty() ||
+ !info->compositor_successful_callbacks.empty());
- if (should_keep_callbacks) {
+ if (should_keep_info) {
++info;
} else {
- std::move(info->compositor_thread_callbacks.begin(),
- info->compositor_thread_callbacks.end(),
- std::back_inserter(result.compositor_thread_callbacks));
+ // Successful presentation time callbacks should only be run when the
+ // presentation was successful.
+ base::ranges::move(info->main_successful_callbacks,
+ std::back_inserter(result.main_successful_callbacks));
+ base::ranges::move(
+ info->compositor_successful_callbacks,
+ std::back_inserter(result.compositor_successful_callbacks));
info = frame_token_infos_.erase(info);
}
}
diff --git a/chromium/cc/trees/presentation_time_callback_buffer.h b/chromium/cc/trees/presentation_time_callback_buffer.h
index 605d6dc01ec..fa062d9d1fe 100644
--- a/chromium/cc/trees/presentation_time_callback_buffer.h
+++ b/chromium/cc/trees/presentation_time_callback_buffer.h
@@ -18,14 +18,15 @@ namespace cc {
// Maintains a queue of callbacks and compositor frame times that we want to
// buffer until a relevant frame is presented.
//
-// Callbacks are queued through |RegisterMainThreadPresentationCallbacks| and
-// |RegisterCompositorPresentationCallbacks| if the callback is to be run on
-// the main thread or compositor thread respectively.
+// Callbacks are queued through `RegisterMainThreadCallbacks()` or
+// `RegisterMainThreadSuccessfulCallbacks()` if the they are to be run on the
+// main thread and `RegisterCompositorThreadSuccessfulCallbacks()` if they are
+// to be run on the compositor thread.
//
// Once a frame is presented, users of this class can call
-// |PopPendingCallbacks| to get their callbacks back. This class never runs
-// callbacks itself so it's up to calling code to |PostTask| or call |Run()| as
-// needed.
+// `PopPendingCallbacks()` to get their callbacks back. This class never runs
+// callbacks itself so it's up to calling code to `PostTask()` or call `Run()`
+// as needed.
//
// This class is thread unsafe so concurrent access would require external
// synchronization. In practice, however, instances of this class are only used
@@ -40,15 +41,8 @@ class CC_EXPORT PresentationTimeCallbackBuffer {
// don't expect many presentation callbacks waiting for a frame presentation.
static constexpr size_t kMaxBufferSize = 60u;
- // TODO(crbug.com/1199373): Compositor thread callbacks are only run for
- // successful presentations and only need the presentation timestamp. On the
- // other hand, main thread callbacks can be run on both successful and failed
- // presentations and need a full `gfx::PresentationFeedback`. Conceptually,
- // main thread callbacks should only be run for successful presentations, too,
- // in which case the two callback signatures can be unified.
- using MainCallback =
- base::OnceCallback<void(const gfx::PresentationFeedback&)>;
- using CompositorCallback = base::OnceCallback<void(base::TimeTicks)>;
+ using Callback = base::OnceCallback<void(const gfx::PresentationFeedback&)>;
+ using SuccessfulCallback = base::OnceCallback<void(base::TimeTicks)>;
PresentationTimeCallbackBuffer();
@@ -62,19 +56,25 @@ class CC_EXPORT PresentationTimeCallbackBuffer {
~PresentationTimeCallbackBuffer();
- // Buffers the given |callbacks| in preparation for a GPU frame swap at or
- // after the given |frame_token|. Calling code posts these callbacks to the
- // main thread once they're popped.
- void RegisterMainThreadPresentationCallbacks(
+ // Buffers the given `callbacks` in preparation for a presentation at or after
+ // the given `frame_token`. The presentation is not necessarily successful.
+ // Calling code posts these callbacks to the main thread once they're popped.
+ void RegisterMainThreadCallbacks(uint32_t frame_token,
+ std::vector<Callback> callbacks);
+
+ // Buffers the given `callbacks` in preparation for a successful presentation
+ // at or after the given `frame_token`. Calling code posts these callbacks to
+ // the main thread once they're popped.
+ void RegisterMainThreadSuccessfulCallbacks(
uint32_t frame_token,
- std::vector<MainCallback> callbacks);
+ std::vector<SuccessfulCallback> callbacks);
- // Buffers the given |callbacks| in preparation for a GPU frame swap at or
- // after the given |frame_token|. Calling code invokes these callbacks on the
- // compositor thread once they're popped.
- void RegisterCompositorPresentationCallbacks(
+ // Buffers the given `callbacks` in preparation for a successful presentation
+ // at or after the given `frame_token`. Calling code invokes these callbacks
+ // on the compositor thread once they're popped.
+ void RegisterCompositorThreadSuccessfulCallbacks(
uint32_t frame_token,
- std::vector<CompositorCallback> callbacks);
+ std::vector<SuccessfulCallback> callbacks);
// Structured return value for |PopPendingCallbacks|. CC_EXPORT is only
// needed for testing.
@@ -90,20 +90,33 @@ class CC_EXPORT PresentationTimeCallbackBuffer {
~PendingCallbacks();
// Holds callbacks registered through
- // |RegisterMainThreadPresentationCallbacks|.
- std::vector<MainCallback> main_thread_callbacks;
+ // `RegisterMainThreadPresentationCallbacks()`.
+ std::vector<Callback> main_callbacks;
+
+ // Holds callbacks registered through
+ // `RegisterMainThreadSuccessfulPresentationCallbacks()`.
+ std::vector<SuccessfulCallback> main_successful_callbacks;
// Holds callbacks registered through
- // |RegisterCompositorPresentationCallbacks|.
- std::vector<CompositorCallback> compositor_thread_callbacks;
+ // `RegisterCompositorThreadSuccessfulPresentationCallbacks()`.
+ std::vector<SuccessfulCallback> compositor_successful_callbacks;
};
// Call this once the presentation for the given `frame_token` has completed.
// Yields any pending callbacks that were registered against a frame token
- // that was less than or equal to the given `frame_token`. If `main_only` is
- // true, only callbacks for the main thread are returned. It is the caller's
- // responsibility to run the callbacks on the right threads/sequences.
- PendingCallbacks PopPendingCallbacks(uint32_t frame_token, bool main_only);
+ // that was less than or equal to the given `frame_token`. If
+ // `presentation_failed` is true, successful presentation time callbacks are
+ // not returned. They are only returned on successful presentations. Note that
+ // since failed presentation feedbacks can arrive out of order (i.e. earlier
+ // than previous frames that might get presented successfully), when called on
+ // a failed presentation, this might return callbacks for previous frames that
+ // are still in flight. This is okay for now as we aim to only allow
+ // registering callbacks for successful presentations which will make this a
+ // non-issue.
+ // It is the caller's responsibility to run the callbacks on the right
+ // threads/sequences.
+ PendingCallbacks PopPendingCallbacks(uint32_t frame_token,
+ bool presentation_failed);
private:
// Stores information needed once we get a response for a particular
@@ -120,11 +133,14 @@ class CC_EXPORT PresentationTimeCallbackBuffer {
// presentation feedback with the relevant compositor frame.
uint32_t token;
- // The callbacks to send back to the main thread.
- std::vector<MainCallback> main_thread_callbacks;
+ // The presentation callbacks to send back to the main thread.
+ std::vector<Callback> main_callbacks;
+
+ // The successful presentation callbacks to send back to the main thread.
+ std::vector<SuccessfulCallback> main_successful_callbacks;
- // The callbacks to invoke on the compositor thread.
- std::vector<CompositorCallback> compositor_thread_callbacks;
+ // The successful presentation callbacks to invoke on the compositor thread.
+ std::vector<SuccessfulCallback> compositor_successful_callbacks;
};
// Returns a reference to a |FrameTokenInfo| with the given |frame_token|.
diff --git a/chromium/cc/trees/presentation_time_callback_buffer_unittest.cc b/chromium/cc/trees/presentation_time_callback_buffer_unittest.cc
index 347fd5f24e1..db8d389d93c 100644
--- a/chromium/cc/trees/presentation_time_callback_buffer_unittest.cc
+++ b/chromium/cc/trees/presentation_time_callback_buffer_unittest.cc
@@ -10,9 +10,9 @@
namespace {
-std::vector<cc::PresentationTimeCallbackBuffer::MainCallback>
-GenerateMainCallbacks(int num_callbacks) {
- std::vector<cc::PresentationTimeCallbackBuffer::MainCallback> result;
+std::vector<cc::PresentationTimeCallbackBuffer::Callback> GenerateCallbacks(
+ int num_callbacks) {
+ std::vector<cc::PresentationTimeCallbackBuffer::Callback> result;
while (num_callbacks-- > 0) {
// `PresentationTimeCallbackBuffer` isn't supposed to invoke any callbacks.
@@ -26,9 +26,9 @@ GenerateMainCallbacks(int num_callbacks) {
return result;
}
-std::vector<cc::PresentationTimeCallbackBuffer::CompositorCallback>
-GenerateCompositorCallbacks(int num_callbacks) {
- std::vector<cc::PresentationTimeCallbackBuffer::CompositorCallback> result;
+std::vector<cc::PresentationTimeCallbackBuffer::SuccessfulCallback>
+GenerateSuccessfulCallbacks(int num_callbacks) {
+ std::vector<cc::PresentationTimeCallbackBuffer::SuccessfulCallback> result;
while (num_callbacks-- > 0) {
// `PresentationTimeCallbackBuffer` isn't supposed to invoke any callbacks.
@@ -54,162 +54,272 @@ namespace cc {
TEST(PresentationTimeCallbackBufferTest, TestNoCallbacks) {
PresentationTimeCallbackBuffer buffer;
- auto result = buffer.PopPendingCallbacks(kFrameToken1, false);
+ auto result =
+ buffer.PopPendingCallbacks(kFrameToken1, /*presentation_failed=*/false);
- EXPECT_TRUE(result.main_thread_callbacks.empty());
- EXPECT_TRUE(result.compositor_thread_callbacks.empty());
+ EXPECT_TRUE(result.main_callbacks.empty());
+ EXPECT_TRUE(result.main_successful_callbacks.empty());
+ EXPECT_TRUE(result.compositor_successful_callbacks.empty());
}
-TEST(PresentationTimeCallbackBufferTest, TestOneMainThreadCallback) {
+TEST(PresentationTimeCallbackBufferTest, TestMainThreadCallbackOnSuccess) {
PresentationTimeCallbackBuffer buffer;
- buffer.RegisterMainThreadPresentationCallbacks(kFrameToken2,
- GenerateMainCallbacks(1));
+ buffer.RegisterMainThreadCallbacks(kFrameToken2, GenerateCallbacks(1));
// Make sure that popping early frame tokens doesn't return irrelevant
// entries.
{
- auto result = buffer.PopPendingCallbacks(kFrameToken1, false);
- EXPECT_TRUE(result.main_thread_callbacks.empty());
- EXPECT_TRUE(result.compositor_thread_callbacks.empty());
+ auto result =
+ buffer.PopPendingCallbacks(kFrameToken1, /*presentation_failed=*/false);
+ EXPECT_TRUE(result.main_callbacks.empty());
+ EXPECT_TRUE(result.main_successful_callbacks.empty());
+ EXPECT_TRUE(result.compositor_successful_callbacks.empty());
}
+ // Make sure the callback is returned on a successful presentation.
{
- auto result = buffer.PopPendingCallbacks(kFrameToken2, false);
- EXPECT_EQ(result.main_thread_callbacks.size(), 1ull);
- EXPECT_TRUE(result.compositor_thread_callbacks.empty());
+ auto result =
+ buffer.PopPendingCallbacks(kFrameToken2, /*presentation_failed=*/false);
+ EXPECT_EQ(result.main_callbacks.size(), 1ull);
+ EXPECT_TRUE(result.main_successful_callbacks.empty());
+ EXPECT_TRUE(result.compositor_successful_callbacks.empty());
}
// Make sure that the buffer has removed the registration since the "pop".
{
- auto result = buffer.PopPendingCallbacks(kFrameToken2, false);
- EXPECT_TRUE(result.main_thread_callbacks.empty());
- EXPECT_TRUE(result.compositor_thread_callbacks.empty());
+ auto result =
+ buffer.PopPendingCallbacks(kFrameToken2, /*presentation_failed=*/false);
+ EXPECT_TRUE(result.main_callbacks.empty());
+ EXPECT_TRUE(result.main_successful_callbacks.empty());
+ EXPECT_TRUE(result.compositor_successful_callbacks.empty());
}
}
-TEST(PresentationTimeCallbackBufferTest, TestOneCompositorThreadCallback) {
+TEST(PresentationTimeCallbackBufferTest, TestMainThreadCallbackOnFailure) {
PresentationTimeCallbackBuffer buffer;
- buffer.RegisterCompositorPresentationCallbacks(
- kFrameToken2, GenerateCompositorCallbacks(1));
+ buffer.RegisterMainThreadCallbacks(kFrameToken2, GenerateCallbacks(1));
// Make sure that popping early frame tokens doesn't return irrelevant
// entries.
{
- auto result = buffer.PopPendingCallbacks(kFrameToken1, false);
- EXPECT_TRUE(result.main_thread_callbacks.empty());
- EXPECT_TRUE(result.compositor_thread_callbacks.empty());
+ auto result =
+ buffer.PopPendingCallbacks(kFrameToken1, /*presentation_failed=*/false);
+ EXPECT_TRUE(result.main_callbacks.empty());
+ EXPECT_TRUE(result.main_successful_callbacks.empty());
+ EXPECT_TRUE(result.compositor_successful_callbacks.empty());
}
+ // Make sure the callback is returned on a failed presentation.
{
- auto result = buffer.PopPendingCallbacks(kFrameToken2, false);
- EXPECT_TRUE(result.main_thread_callbacks.empty());
- EXPECT_EQ(result.compositor_thread_callbacks.size(), 1ull);
+ auto result =
+ buffer.PopPendingCallbacks(kFrameToken2, /*presentation_failed=*/true);
+ EXPECT_EQ(result.main_callbacks.size(), 1ull);
+ EXPECT_TRUE(result.main_successful_callbacks.empty());
+ EXPECT_TRUE(result.compositor_successful_callbacks.empty());
}
// Make sure that the buffer has removed the registration since the "pop".
{
- auto result = buffer.PopPendingCallbacks(kFrameToken2, false);
- EXPECT_TRUE(result.main_thread_callbacks.empty());
- EXPECT_TRUE(result.compositor_thread_callbacks.empty());
+ auto result =
+ buffer.PopPendingCallbacks(kFrameToken2, /*presentation_failed=*/false);
+ EXPECT_TRUE(result.main_callbacks.empty());
+ EXPECT_TRUE(result.main_successful_callbacks.empty());
+ EXPECT_TRUE(result.compositor_successful_callbacks.empty());
}
}
-TEST(PresentationTimeCallbackBufferTest, TestMixedCallbacks) {
+TEST(PresentationTimeCallbackBufferTest, TestMainThreadSuccessfulCallback) {
PresentationTimeCallbackBuffer buffer;
- buffer.RegisterMainThreadPresentationCallbacks(kFrameToken2,
- GenerateMainCallbacks(1));
- buffer.RegisterCompositorPresentationCallbacks(
- kFrameToken2, GenerateCompositorCallbacks(1));
+ buffer.RegisterMainThreadSuccessfulCallbacks(kFrameToken2,
+ GenerateSuccessfulCallbacks(1));
// Make sure that popping early frame tokens doesn't return irrelevant
// entries.
{
- auto result = buffer.PopPendingCallbacks(kFrameToken1, false);
- EXPECT_TRUE(result.main_thread_callbacks.empty());
- EXPECT_TRUE(result.compositor_thread_callbacks.empty());
+ auto result =
+ buffer.PopPendingCallbacks(kFrameToken1, /*presentation_failed=*/false);
+ EXPECT_TRUE(result.main_callbacks.empty());
+ EXPECT_TRUE(result.main_successful_callbacks.empty());
+ EXPECT_TRUE(result.compositor_successful_callbacks.empty());
}
+ // Make sure the callback is not returned on a failed presentation.
{
- auto result = buffer.PopPendingCallbacks(kFrameToken2, false);
- EXPECT_EQ(result.main_thread_callbacks.size(), 1ull);
- EXPECT_EQ(result.compositor_thread_callbacks.size(), 1ull);
+ auto result =
+ buffer.PopPendingCallbacks(kFrameToken2, /*presentation_failed=*/true);
+ EXPECT_TRUE(result.main_callbacks.empty());
+ EXPECT_TRUE(result.main_successful_callbacks.empty());
+ EXPECT_TRUE(result.compositor_successful_callbacks.empty());
+ }
+
+ // Make sure the callback is returned on a successful presentation.
+ {
+ auto result =
+ buffer.PopPendingCallbacks(kFrameToken2, /*presentation_failed=*/false);
+ EXPECT_TRUE(result.main_callbacks.empty());
+ EXPECT_EQ(result.main_successful_callbacks.size(), 1ull);
+ EXPECT_TRUE(result.compositor_successful_callbacks.empty());
+ }
+
+ // Make sure that the buffer has removed the registration since the "pop".
+ {
+ auto result =
+ buffer.PopPendingCallbacks(kFrameToken2, /*presentation_failed=*/false);
+ EXPECT_TRUE(result.main_callbacks.empty());
+ EXPECT_TRUE(result.main_successful_callbacks.empty());
+ EXPECT_TRUE(result.compositor_successful_callbacks.empty());
+ }
+}
+
+TEST(PresentationTimeCallbackBufferTest,
+ TestCompositorThreadSuccessfulCallback) {
+ PresentationTimeCallbackBuffer buffer;
+
+ buffer.RegisterCompositorThreadSuccessfulCallbacks(
+ kFrameToken2, GenerateSuccessfulCallbacks(1));
+
+ // Make sure that popping early frame tokens doesn't return irrelevant
+ // entries.
+ {
+ auto result =
+ buffer.PopPendingCallbacks(kFrameToken1, /*presentation_failed=*/false);
+ EXPECT_TRUE(result.main_callbacks.empty());
+ EXPECT_TRUE(result.main_successful_callbacks.empty());
+ EXPECT_TRUE(result.compositor_successful_callbacks.empty());
+ }
+
+ // Make sure the callback is not returned on a failed presentation.
+ {
+ auto result =
+ buffer.PopPendingCallbacks(kFrameToken2, /*presentation_failed=*/true);
+ EXPECT_TRUE(result.main_callbacks.empty());
+ EXPECT_TRUE(result.main_successful_callbacks.empty());
+ EXPECT_TRUE(result.compositor_successful_callbacks.empty());
+ }
+
+ // Make sure the callback is returned on a successful presentation.
+ {
+ auto result =
+ buffer.PopPendingCallbacks(kFrameToken2, /*presentation_failed=*/false);
+ EXPECT_TRUE(result.main_callbacks.empty());
+ EXPECT_TRUE(result.main_successful_callbacks.empty());
+ EXPECT_EQ(result.compositor_successful_callbacks.size(), 1ull);
+ }
+
+ // Make sure that the buffer has removed the registration since the "pop".
+ {
+ auto result =
+ buffer.PopPendingCallbacks(kFrameToken2, /*presentation_failed=*/false);
+ EXPECT_TRUE(result.main_callbacks.empty());
+ EXPECT_TRUE(result.main_successful_callbacks.empty());
+ EXPECT_TRUE(result.compositor_successful_callbacks.empty());
+ }
+}
+
+TEST(PresentationTimeCallbackBufferTest, TestMixedCallbacksOnSuccess) {
+ PresentationTimeCallbackBuffer buffer;
+
+ buffer.RegisterMainThreadCallbacks(kFrameToken2, GenerateCallbacks(1));
+ buffer.RegisterMainThreadSuccessfulCallbacks(kFrameToken2,
+ GenerateSuccessfulCallbacks(1));
+ buffer.RegisterCompositorThreadSuccessfulCallbacks(
+ kFrameToken2, GenerateSuccessfulCallbacks(1));
+
+ // Make sure that popping early frame tokens doesn't return irrelevant
+ // entries.
+ {
+ auto result =
+ buffer.PopPendingCallbacks(kFrameToken1, /*presentation_failed=*/false);
+ EXPECT_TRUE(result.main_callbacks.empty());
+ EXPECT_TRUE(result.main_successful_callbacks.empty());
+ EXPECT_TRUE(result.compositor_successful_callbacks.empty());
+ }
+
+ // Make sure all callbacks are returned on a successful presentation.
+ {
+ auto result =
+ buffer.PopPendingCallbacks(kFrameToken2, /*presentation_failed=*/false);
+ EXPECT_EQ(result.main_callbacks.size(), 1ull);
+ EXPECT_EQ(result.main_successful_callbacks.size(), 1ull);
+ EXPECT_EQ(result.compositor_successful_callbacks.size(), 1ull);
}
// Make sure that the buffer has removed the registrations since the "pop".
{
- auto result = buffer.PopPendingCallbacks(kFrameToken2, false);
- EXPECT_TRUE(result.main_thread_callbacks.empty());
- EXPECT_TRUE(result.compositor_thread_callbacks.empty());
+ auto result =
+ buffer.PopPendingCallbacks(kFrameToken2, /*presentation_failed=*/false);
+ EXPECT_TRUE(result.main_callbacks.empty());
+ EXPECT_TRUE(result.main_successful_callbacks.empty());
+ EXPECT_TRUE(result.compositor_successful_callbacks.empty());
}
}
-TEST(PresentationTimeCallbackBufferTest, TestCallbackBatching) {
+TEST(PresentationTimeCallbackBufferTest, TestMixedCallbacksOnFailure) {
PresentationTimeCallbackBuffer buffer;
- // Register one callback for frame1, two for frame2 and two for frame4.
- buffer.RegisterMainThreadPresentationCallbacks(kFrameToken1,
- GenerateMainCallbacks(1));
- buffer.RegisterMainThreadPresentationCallbacks(kFrameToken2,
- GenerateMainCallbacks(2));
- buffer.RegisterMainThreadPresentationCallbacks(kFrameToken4,
- GenerateMainCallbacks(2));
+ buffer.RegisterMainThreadCallbacks(kFrameToken2, GenerateCallbacks(1));
+ buffer.RegisterMainThreadSuccessfulCallbacks(kFrameToken2,
+ GenerateSuccessfulCallbacks(1));
+ buffer.RegisterCompositorThreadSuccessfulCallbacks(
+ kFrameToken2, GenerateSuccessfulCallbacks(1));
- // Pop callbacks up to and including frame3. Should be three in total; one
- // from frame1 and two from frame2.
+ // Make sure that popping early frame tokens doesn't return irrelevant
+ // entries.
+ {
+ auto result =
+ buffer.PopPendingCallbacks(kFrameToken1, /*presentation_failed=*/false);
+ EXPECT_TRUE(result.main_callbacks.empty());
+ EXPECT_TRUE(result.main_successful_callbacks.empty());
+ EXPECT_TRUE(result.compositor_successful_callbacks.empty());
+ }
+
+ // Make sure only feedback callbacks are returned on a failed presentation.
+ {
+ auto result =
+ buffer.PopPendingCallbacks(kFrameToken2, /*presentation_failed=*/true);
+ EXPECT_EQ(result.main_callbacks.size(), 1ull);
+ EXPECT_TRUE(result.main_successful_callbacks.empty());
+ EXPECT_TRUE(result.compositor_successful_callbacks.empty());
+ }
+
+ // Make sure time callbacks are returned on a successful presentation.
{
- auto result = buffer.PopPendingCallbacks(kFrameToken3, false);
- EXPECT_EQ(result.main_thread_callbacks.size(), 3ull);
- EXPECT_TRUE(result.compositor_thread_callbacks.empty());
+ auto result =
+ buffer.PopPendingCallbacks(kFrameToken2, /*presentation_failed=*/false);
+ EXPECT_TRUE(result.main_callbacks.empty());
+ EXPECT_EQ(result.main_successful_callbacks.size(), 1ull);
+ EXPECT_EQ(result.compositor_successful_callbacks.size(), 1ull);
+ }
+
+ // Make sure that the buffer has removed the registrations since the "pop".
+ {
+ auto result =
+ buffer.PopPendingCallbacks(kFrameToken2, /*presentation_failed=*/false);
+ EXPECT_TRUE(result.main_callbacks.empty());
+ EXPECT_TRUE(result.main_successful_callbacks.empty());
+ EXPECT_TRUE(result.compositor_successful_callbacks.empty());
}
}
-// Tests that popping callbacks for main thread only vs. for both main and
-// compositor threads works properly.
-TEST(PresentationTimeCallbackBufferTest, PopMainCallbacksOnly) {
+TEST(PresentationTimeCallbackBufferTest, TestCallbackBatching) {
PresentationTimeCallbackBuffer buffer;
- // Register callbacks for main and compositor threads of 3 frames.
- buffer.RegisterMainThreadPresentationCallbacks(kFrameToken1,
- GenerateMainCallbacks(1));
- buffer.RegisterCompositorPresentationCallbacks(
- kFrameToken1, GenerateCompositorCallbacks(1));
- buffer.RegisterMainThreadPresentationCallbacks(kFrameToken2,
- GenerateMainCallbacks(1));
- buffer.RegisterCompositorPresentationCallbacks(
- kFrameToken2, GenerateCompositorCallbacks(1));
- buffer.RegisterMainThreadPresentationCallbacks(kFrameToken3,
- GenerateMainCallbacks(1));
- buffer.RegisterCompositorPresentationCallbacks(
- kFrameToken3, GenerateCompositorCallbacks(1));
-
- // Pop only main thread callbacks up to and including frame1. The result
- // should only contain 1 main thread callback of frame1 and no compositor
- // thread callback.
- {
- auto result = buffer.PopPendingCallbacks(kFrameToken1, true);
- EXPECT_EQ(result.main_thread_callbacks.size(), 1ull);
- EXPECT_TRUE(result.compositor_thread_callbacks.empty());
- }
-
- // Pop only main thread callbacks up to and including frame2. The result
- // should only contain 1 main thread callback of frame2 and no compositor
- // thread callback.
- {
- auto result = buffer.PopPendingCallbacks(kFrameToken2, true);
- EXPECT_EQ(result.main_thread_callbacks.size(), 1ull);
- EXPECT_TRUE(result.compositor_thread_callbacks.empty());
- }
-
- // Pop both main and compositor thread callbacks up to and including frame3.
- // The result should contain 1 main thread callback of frame3 and all 3
- // compositor thread callbacks of the 3 frames.
- {
- auto result = buffer.PopPendingCallbacks(kFrameToken3, false);
- EXPECT_EQ(result.main_thread_callbacks.size(), 1ull);
- EXPECT_EQ(result.compositor_thread_callbacks.size(), 3ull);
+ // Register one callback for frame1, two for frame2 and two for frame4.
+ buffer.RegisterMainThreadCallbacks(kFrameToken1, GenerateCallbacks(1));
+ buffer.RegisterMainThreadCallbacks(kFrameToken2, GenerateCallbacks(2));
+ buffer.RegisterMainThreadCallbacks(kFrameToken4, GenerateCallbacks(2));
+
+ // Pop callbacks up to and including frame3. Should be three in total; one
+ // from frame1 and two from frame2.
+ {
+ auto result =
+ buffer.PopPendingCallbacks(kFrameToken3, /*presentation_failed=*/false);
+ EXPECT_EQ(result.main_callbacks.size(), 3ull);
+ EXPECT_TRUE(result.main_successful_callbacks.empty());
+ EXPECT_TRUE(result.compositor_successful_callbacks.empty());
}
}
diff --git a/chromium/cc/trees/property_tree.cc b/chromium/cc/trees/property_tree.cc
index 9687ec9eed2..5dd5647d0ec 100644
--- a/chromium/cc/trees/property_tree.cc
+++ b/chromium/cc/trees/property_tree.cc
@@ -12,6 +12,7 @@
#include "base/check_op.h"
#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
#include "base/numerics/checked_math.h"
#include "base/numerics/safe_conversions.h"
#include "base/trace_event/traced_value.h"
@@ -31,6 +32,12 @@
namespace cc {
+void AnimationUpdateOnMissingPropertyNodeUMALog(bool missing_property_node) {
+ UMA_HISTOGRAM_BOOLEAN(
+ "Compositing.Renderer.AnimationUpdateOnMissingPropertyNode",
+ missing_property_node);
+}
+
template <typename T>
PropertyTree<T>::PropertyTree(PropertyTrees* property_trees)
: needs_update_(false), property_trees_(property_trees) {
@@ -149,11 +156,13 @@ void TransformTree::set_needs_update(bool needs_update) {
bool TransformTree::OnTransformAnimated(ElementId element_id,
const gfx::Transform& transform) {
TransformNode* node = FindNodeFromElementId(element_id);
- DCHECK(node);
// TODO(crbug.com/1307498): Remove this when we no longer animate
// non-existent nodes.
- if (!node)
+ if (!node) {
+ AnimationUpdateOnMissingPropertyNodeUMALog(true);
return false;
+ }
+ AnimationUpdateOnMissingPropertyNodeUMALog(false);
if (node->local == transform)
return false;
node->local = transform;
@@ -273,7 +282,7 @@ void TransformTree::CombineTransformsBetween(int source_id,
size_t index = source_to_destination_size - 1 - i;
const TransformNode* node = Node(source_to_destination[index]);
if (node->flattens_inherited_transform)
- combined_transform.FlattenTo2d();
+ combined_transform.Flatten();
combined_transform.PreConcat(node->to_parent);
}
@@ -568,7 +577,7 @@ void TransformTree::UpdateScreenSpaceTransform(TransformNode* node,
DCHECK(parent_node);
gfx::Transform to_screen_space_transform = ToScreen(parent_node->id);
if (node->flattens_inherited_transform)
- to_screen_space_transform.FlattenTo2d();
+ to_screen_space_transform.Flatten();
to_screen_space_transform.PreConcat(node->to_parent);
node->ancestors_are_invertible = parent_node->ancestors_are_invertible;
node->node_and_ancestors_are_flat =
@@ -614,7 +623,7 @@ void TransformTree::UpdateSnapping(TransformNode* node) {
// X = ST^-1 * ST'. We cache ST and ST^-1 to make this more efficient.
DCHECK_LT(node->id, static_cast<int>(cached_data_.size()));
gfx::Transform& to_screen = cached_data_[node->id].to_screen;
- to_screen.RoundTranslationComponents();
+ to_screen.Round2dTranslationComponents();
gfx::Transform& from_screen = cached_data_[node->id].from_screen;
gfx::Transform delta = from_screen;
delta *= to_screen;
@@ -632,7 +641,7 @@ void TransformTree::UpdateSnapping(TransformNode* node) {
node->to_parent.Translate(translation);
// Avoid accumulation of errors in to_parent.
if (node->to_parent.IsApproximatelyIdentityOrIntegerTranslation(kTolerance))
- node->to_parent.RoundTranslationComponents();
+ node->to_parent.RoundToIdentityOrIntegerTranslation();
}
void TransformTree::UpdateTransformChanged(TransformNode* node,
@@ -696,9 +705,7 @@ void TransformTree::SetRootScaleAndTransform(
gfx::Transform root_to_screen;
root_to_screen.Scale(screen_space_scale.x(), screen_space_scale.y());
- gfx::Transform root_from_screen;
- bool invertible = root_to_screen.GetInverse(&root_from_screen);
- DCHECK(invertible);
+ gfx::Transform root_from_screen = root_to_screen.GetCheckedInverse();
if (root_to_screen != ToScreen(kRootPropertyNodeId)) {
SetToScreen(kRootPropertyNodeId, root_to_screen);
SetFromScreen(kRootPropertyNodeId, root_from_screen);
@@ -897,7 +904,7 @@ void EffectTree::UpdateOnlyDrawsVisibleContent(EffectNode* node,
EffectNode* parent_node) {
node->only_draws_visible_content =
!node->has_copy_request && !node->subtree_capture_id.is_valid() &&
- !node->shared_element_resource_id.IsValid();
+ !node->view_transition_element_resource_id.IsValid();
if (parent_node)
node->only_draws_visible_content &= parent_node->only_draws_visible_content;
if (!node->backdrop_filters.IsEmpty()) {
@@ -934,11 +941,13 @@ void EffectTree::UpdateSurfaceContentsScale(EffectNode* effect_node) {
bool EffectTree::OnOpacityAnimated(ElementId id, float opacity) {
EffectNode* node = FindNodeFromElementId(id);
- DCHECK(node);
// TODO(crbug.com/1307498): Remove this when we no longer animate
// non-existent nodes.
- if (!node)
+ if (!node) {
+ AnimationUpdateOnMissingPropertyNodeUMALog(true);
return false;
+ }
+ AnimationUpdateOnMissingPropertyNodeUMALog(false);
if (node->opacity == opacity)
return false;
node->opacity = opacity;
@@ -951,11 +960,13 @@ bool EffectTree::OnOpacityAnimated(ElementId id, float opacity) {
bool EffectTree::OnFilterAnimated(ElementId id,
const FilterOperations& filters) {
EffectNode* node = FindNodeFromElementId(id);
- DCHECK(node);
// TODO(crbug.com/1307498): Remove this when we no longer animate
// non-existent nodes.
- if (!node)
+ if (!node) {
+ AnimationUpdateOnMissingPropertyNodeUMALog(true);
return false;
+ }
+ AnimationUpdateOnMissingPropertyNodeUMALog(false);
if (node->filters == filters)
return false;
node->filters = filters;
@@ -969,11 +980,13 @@ bool EffectTree::OnBackdropFilterAnimated(
ElementId id,
const FilterOperations& backdrop_filters) {
EffectNode* node = FindNodeFromElementId(id);
- DCHECK(node);
// TODO(crbug.com/1307498): Remove this when we no longer animate
// non-existent nodes.
- if (!node)
+ if (!node) {
+ AnimationUpdateOnMissingPropertyNodeUMALog(true);
return false;
+ }
+ AnimationUpdateOnMissingPropertyNodeUMALog(false);
if (node->backdrop_filters == backdrop_filters)
return false;
node->backdrop_filters = backdrop_filters;
@@ -1001,7 +1014,7 @@ void EffectTree::UpdateEffects(int id) {
void EffectTree::UpdateClosestAncestorSharedElement(EffectNode* node,
EffectNode* parent_node) {
- if (node->shared_element_resource_id.IsValid()) {
+ if (node->view_transition_element_resource_id.IsValid()) {
node->closest_ancestor_with_shared_element_id = node->id;
} else if (parent_node) {
node->closest_ancestor_with_shared_element_id =
@@ -1535,7 +1548,7 @@ gfx::Transform ScrollTree::ScreenSpaceTransform(int scroll_node_id) const {
screen_space_transform.PostConcat(
transform_tree.ToScreen(transform_node->id));
if (scroll_node->should_flatten)
- screen_space_transform.FlattenTo2d();
+ screen_space_transform.Flatten();
return screen_space_transform;
}
diff --git a/chromium/cc/trees/property_tree.h b/chromium/cc/trees/property_tree.h
index ffd0ad55508..43f9ba50365 100644
--- a/chromium/cc/trees/property_tree.h
+++ b/chromium/cc/trees/property_tree.h
@@ -18,6 +18,7 @@
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/memory/raw_ptr.h"
+#include "base/memory/raw_ref.h"
#include "base/memory/weak_ptr.h"
#include "cc/base/synced_property.h"
#include "cc/cc_export.h"
@@ -30,7 +31,7 @@
#include "cc/trees/scroll_node.h"
#include "cc/trees/sticky_position_constraint.h"
#include "cc/trees/transform_node.h"
-#include "components/viz/common/shared_element_resource_id.h"
+#include "components/viz/common/view_transition_element_resource_id.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/geometry/rect_f.h"
@@ -717,7 +718,7 @@ class CC_EXPORT PropertyTrees final {
#endif
const ProtectedSequenceSynchronizer& synchronizer() const {
- return synchronizer_;
+ return *synchronizer_;
}
const ClipTree& clip_tree() const { return clip_tree_; }
@@ -822,7 +823,7 @@ class CC_EXPORT PropertyTrees final {
bool HasElement(ElementId element_id) const;
private:
- const ProtectedSequenceSynchronizer& synchronizer_;
+ const raw_ref<const ProtectedSequenceSynchronizer> synchronizer_;
TransformTree transform_tree_;
EffectTree effect_tree_;
diff --git a/chromium/cc/trees/property_tree_builder.cc b/chromium/cc/trees/property_tree_builder.cc
index a3b2c6e4ae3..8f56fef47e1 100644
--- a/chromium/cc/trees/property_tree_builder.cc
+++ b/chromium/cc/trees/property_tree_builder.cc
@@ -47,8 +47,8 @@ struct DataForRecursion {
bool animation_axis_aligned_since_render_target;
bool not_axis_aligned_since_last_clip;
gfx::Transform compound_transform_since_render_target;
- bool* subtree_has_rounded_corner;
- bool* subtree_has_gradient_mask;
+ raw_ptr<bool> subtree_has_rounded_corner;
+ raw_ptr<bool> subtree_has_gradient_mask;
};
class PropertyTreeBuilderContext {
diff --git a/chromium/cc/trees/property_tree_builder_unittest.cc b/chromium/cc/trees/property_tree_builder_unittest.cc
index 74775660667..f30b68019ed 100644
--- a/chromium/cc/trees/property_tree_builder_unittest.cc
+++ b/chromium/cc/trees/property_tree_builder_unittest.cc
@@ -455,7 +455,7 @@ TEST_F(PropertyTreeBuilderTest, TextureLayerSnapping) {
auto child_screen_space_transform = ImplOf(child)->ScreenSpaceTransform();
EXPECT_NE(child_screen_space_transform, fractional_translate);
- fractional_translate.RoundTranslationComponents();
+ fractional_translate.Round2dTranslationComponents();
EXPECT_TRANSFORM_EQ(child_screen_space_transform, fractional_translate);
gfx::RectF layer_bounds_in_screen_space = MathUtil::MapClippedRect(
child_screen_space_transform, gfx::RectF(gfx::SizeF(child->bounds())));
diff --git a/chromium/cc/trees/property_tree_unittest.cc b/chromium/cc/trees/property_tree_unittest.cc
index 95c9fad45bd..41e5a796230 100644
--- a/chromium/cc/trees/property_tree_unittest.cc
+++ b/chromium/cc/trees/property_tree_unittest.cc
@@ -282,7 +282,7 @@ TEST(PropertyTreeTest, TransformsWithFlattening) {
property_trees.ResetCachedData();
gfx::Transform flattened_rotation_about_x = rotation_about_x;
- flattened_rotation_about_x.FlattenTo2d();
+ flattened_rotation_about_x.Flatten();
gfx::Transform to_target;
property_trees.GetToTarget(child, effect_parent, &to_target);
@@ -458,7 +458,7 @@ TEST(PropertyTreeTest, FlatteningWhenDestinationHasOnlyFlatAncestors) {
draw_property_utils::ComputeTransforms(&tree, ViewportPropertyIds());
gfx::Transform flattened_rotation_about_x = rotation_about_x;
- flattened_rotation_about_x.FlattenTo2d();
+ flattened_rotation_about_x.Flatten();
gfx::Transform grand_child_to_parent;
tree.CombineTransformsBetween(grand_child, parent, &grand_child_to_parent);
@@ -528,7 +528,7 @@ TEST(PropertyTreeTest, SingularTransformSnapTest) {
gfx::Transform rounded;
property_trees.GetToTarget(child, effect_parent, &rounded);
- rounded.RoundTranslationComponents();
+ rounded.Round2dTranslationComponents();
property_trees.GetToTarget(child, effect_parent, &to_target);
EXPECT_NE(to_target, rounded);
}
diff --git a/chromium/cc/trees/proxy.h b/chromium/cc/trees/proxy.h
index 6868bf0cb7a..e990e28a429 100644
--- a/chromium/cc/trees/proxy.h
+++ b/chromium/cc/trees/proxy.h
@@ -8,7 +8,6 @@
#include <memory>
#include <string>
-#include "base/memory/ref_counted.h"
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
#include "cc/cc_export.h"
diff --git a/chromium/cc/trees/proxy_impl.cc b/chromium/cc/trees/proxy_impl.cc
index debf83156f3..4cc820fd939 100644
--- a/chromium/cc/trees/proxy_impl.cc
+++ b/chromium/cc/trees/proxy_impl.cc
@@ -14,6 +14,7 @@
#include "base/auto_reset.h"
#include "base/bind.h"
+#include "base/debug/crash_logging.h"
#include "base/memory/raw_ptr.h"
#include "base/notreached.h"
#include "base/trace_event/trace_event.h"
@@ -48,6 +49,9 @@ namespace {
constexpr auto kSmoothnessTakesPriorityExpirationDelay =
base::Milliseconds(250);
+// Make this less than kHungRendererDelay (15 sec).
+constexpr base::TimeDelta kHungCommitTimeout = base::Seconds(14);
+
} // namespace
// Ensures that a CompletionEvent for commit is always signaled.
@@ -318,14 +322,6 @@ void ProxyImpl::FrameSinksToThrottleUpdated(
NOTREACHED();
}
-void ProxyImpl::ReportEventLatency(
- std::vector<EventLatencyTracker::LatencyData> latencies) {
- DCHECK(IsImplThread());
- MainThreadTaskRunner()->PostTask(
- FROM_HERE, base::BindOnce(&ProxyMain::ReportEventLatency,
- proxy_main_weak_ptr_, std::move(latencies)));
-}
-
void ProxyImpl::NotifyReadyToCommitOnImpl(
CompletionEvent* completion_event,
std::unique_ptr<CommitState> commit_state,
@@ -382,6 +378,9 @@ void ProxyImpl::NotifyReadyToCommitOnImpl(
completion_event, start_time, MainThreadTaskRunner(),
proxy_main_weak_ptr_),
std::move(commit_state), unsafe_state, commit_timestamps);
+ hung_commit_timer_.Start(
+ FROM_HERE, kHungCommitTimeout,
+ base::BindOnce(&ProxyImpl::OnHungCommit, base::Unretained(this)));
// Extract metrics data from the layer tree host and send them to the
// scheduler to pass them to the compositor_timing_history object.
@@ -393,6 +392,16 @@ void ProxyImpl::NotifyReadyToCommitOnImpl(
scheduler_->SetNeedsBeginMainFrame();
}
+void ProxyImpl::OnHungCommit() {
+ UMA_HISTOGRAM_BOOLEAN("Compositing.Renderer.CommitHung", true);
+ static auto* hung_commit_data = base::debug::AllocateCrashKeyString(
+ "hung_commit", base::debug::CrashKeySize::Size256);
+ std::string debug_info = scheduler_->GetHungCommitDebugInfo();
+ LOG(ERROR) << "commit hung: " << debug_info;
+ base::debug::SetCrashKeyString(hung_commit_data, debug_info);
+ scheduler_->TraceHungCommitDebugInfo();
+}
+
void ProxyImpl::DidLoseLayerTreeFrameSinkOnImplThread() {
TRACE_EVENT0("cc", "ProxyImpl::DidLoseLayerTreeFrameSinkOnImplThread");
DCHECK(IsImplThread());
@@ -635,14 +644,15 @@ void ProxyImpl::DidPresentCompositorFrameOnImplThread(
uint32_t frame_token,
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.compositor_thread_callbacks), details);
+ frame_token, std::move(activated.compositor_successful_callbacks),
+ details);
MainThreadTaskRunner()->PostTask(
FROM_HERE, base::BindOnce(&ProxyMain::DidPresentCompositorFrame,
proxy_main_weak_ptr_, frame_token,
- std::move(main_thread_callbacks),
+ std::move(activated.main_callbacks),
+ std::move(activated.main_successful_callbacks),
details.presentation_feedback));
if (scheduler_)
scheduler_->DidPresentCompositorFrame(frame_token, details);
@@ -806,6 +816,7 @@ void ProxyImpl::ScheduledActionCommit() {
}
data_for_commit_.reset();
+ hung_commit_timer_.Stop();
}
void ProxyImpl::ScheduledActionPostCommit() {
diff --git a/chromium/cc/trees/proxy_impl.h b/chromium/cc/trees/proxy_impl.h
index 34147f988f1..f642fc41072 100644
--- a/chromium/cc/trees/proxy_impl.h
+++ b/chromium/cc/trees/proxy_impl.h
@@ -137,8 +137,6 @@ class CC_EXPORT ProxyImpl : public LayerTreeHostImplClient,
bool IsInSynchronousComposite() const override;
void FrameSinksToThrottleUpdated(
const base::flat_set<viz::FrameSinkId>& id) override;
- void ReportEventLatency(
- std::vector<EventLatencyTracker::LatencyData> latencies) override;
// SchedulerClient implementation
bool WillBeginImplFrame(const viz::BeginFrameArgs& args) override;
@@ -171,6 +169,8 @@ class CC_EXPORT ProxyImpl : public LayerTreeHostImplClient,
base::SingleThreadTaskRunner* MainThreadTaskRunner();
bool ShouldDeferBeginMainFrame() const;
+ void OnHungCommit();
+
const int layer_tree_host_id_;
std::unique_ptr<Scheduler> scheduler_;
@@ -230,6 +230,9 @@ class CC_EXPORT ProxyImpl : public LayerTreeHostImplClient,
// Either thread can request deferring BeginMainFrame; keep track of both.
bool main_wants_defer_begin_main_frame_ = false;
bool impl_wants_defer_begin_main_frame_ = false;
+
+ // Temporary for production debugging of renderer hang (crbug.com/1159366).
+ base::OneShotTimer hung_commit_timer_;
};
} // namespace cc
diff --git a/chromium/cc/trees/proxy_main.cc b/chromium/cc/trees/proxy_main.cc
index ac0d58819c1..c3a56f3ae39 100644
--- a/chromium/cc/trees/proxy_main.cc
+++ b/chromium/cc/trees/proxy_main.cc
@@ -165,9 +165,11 @@ void ProxyMain::BeginMainFrame(
"viz,benchmark", "MainFrame.BeginMainFrameAbortedOnMain",
TRACE_ID_LOCAL(begin_main_frame_state->trace_id),
TRACE_EVENT_FLAG_FLOW_IN, "reason", "ABORTED_NOT_VISIBLE");
- // In this case, since the commit is deferred to a later time, gathered
- // events metrics are not discarded so that they can be reported if the
- // commit happens in the future.
+ // Since the commit is deferred due to the page becoming invisible, the
+ // metrics are not meaningful anymore (as the page might become visible in
+ // any arbitrary time in the future and cause an arbitrarily large latency).
+ // Discard event metrics.
+ layer_tree_host_->ClearEventsMetrics();
std::vector<std::unique_ptr<SwapPromise>> empty_swap_promises;
ImplThreadTaskRunner()->PostTask(
FROM_HERE,
@@ -215,6 +217,14 @@ void ProxyMain::BeginMainFrame(
return;
}
+ // This call winds through to the LocalFrameView to mark the beginning
+ // of a main frame for metrics purposes. Some metrics are only gathered
+ // between calls to RecordStartOfFrameMetrics and RecordEndOfFrameMetrics.
+ // This is not wrapped into layer_tree_host_->WillBeginMainFrame because
+ // it should only be called from the multi-threaded proxy (we do not want
+ // metrics gathering in tests).
+ layer_tree_host_->RecordStartOfFrameMetrics();
+
final_pipeline_stage_ =
std::max(final_pipeline_stage_, deferred_final_pipeline_stage_);
deferred_final_pipeline_stage_ = NO_PIPELINE_STAGE;
@@ -246,14 +256,6 @@ void ProxyMain::BeginMainFrame(
layer_tree_host_->WillBeginMainFrame();
- // This call winds through to the LocalFrameView to mark the beginning
- // of a main frame for metrics purposes. Some metrics are only gathered
- // between calls to RecordStartOfFrameMetrics and RecordEndOfFrameMetrics.
- // This is not wrapped into layer_tree_host_->WillBeginMainFrame because
- // it should only be called from the multi-threaded proxy (we do not want
- // metrics gathering in tests).
- layer_tree_host_->RecordStartOfFrameMetrics();
-
// See LayerTreeHostClient::BeginMainFrame for more documentation on
// what this does.
layer_tree_host_->BeginMainFrame(frame_args);
@@ -466,10 +468,14 @@ void ProxyMain::DidCompleteCommit(CommitTimestamps commit_timestamps) {
void ProxyMain::DidPresentCompositorFrame(
uint32_t frame_token,
- std::vector<PresentationTimeCallbackBuffer::MainCallback> callbacks,
+ std::vector<PresentationTimeCallbackBuffer::Callback>
+ presentation_callbacks,
+ std::vector<PresentationTimeCallbackBuffer::SuccessfulCallback>
+ sucessful_presentation_callbacks,
const gfx::PresentationFeedback& feedback) {
- layer_tree_host_->DidPresentCompositorFrame(frame_token, std::move(callbacks),
- feedback);
+ layer_tree_host_->DidPresentCompositorFrame(
+ frame_token, std::move(presentation_callbacks),
+ std::move(sucessful_presentation_callbacks), feedback);
}
void ProxyMain::NotifyThroughputTrackerResults(CustomTrackerResults results) {
@@ -483,11 +489,6 @@ void ProxyMain::DidObserveFirstScrollDelay(
first_scroll_timestamp);
}
-void ProxyMain::ReportEventLatency(
- std::vector<EventLatencyTracker::LatencyData> latencies) {
- layer_tree_host_->ReportEventLatency(std::move(latencies));
-}
-
void ProxyMain::NotifyTransitionRequestFinished(uint32_t sequence_id) {
layer_tree_host_->NotifyTransitionRequestsFinished({sequence_id});
}
@@ -720,7 +721,7 @@ void ProxyMain::Stop() {
}
void ProxyMain::SetMutator(std::unique_ptr<LayerTreeMutator> mutator) {
- TRACE_EVENT0("cc", "ThreadProxy::SetMutator");
+ TRACE_EVENT0("cc", "ProxyMain::SetMutator");
ImplThreadTaskRunner()->PostTask(
FROM_HERE,
base::BindOnce(&ProxyImpl::InitializeMutatorOnImpl,
@@ -729,7 +730,7 @@ void ProxyMain::SetMutator(std::unique_ptr<LayerTreeMutator> mutator) {
void ProxyMain::SetPaintWorkletLayerPainter(
std::unique_ptr<PaintWorkletLayerPainter> painter) {
- TRACE_EVENT0("cc", "ThreadProxy::SetPaintWorkletLayerPainter");
+ TRACE_EVENT0("cc", "ProxyMain::SetPaintWorkletLayerPainter");
ImplThreadTaskRunner()->PostTask(
FROM_HERE,
base::BindOnce(&ProxyImpl::InitializePaintWorkletLayerPainterOnImpl,
@@ -793,6 +794,7 @@ bool ProxyMain::SendCommitRequestToImplThreadIfNeeded(
ImplThreadTaskRunner()->PostTask(
FROM_HERE, base::BindOnce(&ProxyImpl::SetNeedsCommitOnImpl,
base::Unretained(proxy_impl_.get())));
+ layer_tree_host_->OnCommitRequested();
return true;
}
diff --git a/chromium/cc/trees/proxy_main.h b/chromium/cc/trees/proxy_main.h
index f671dfcb27b..61326f47f5a 100644
--- a/chromium/cc/trees/proxy_main.h
+++ b/chromium/cc/trees/proxy_main.h
@@ -12,7 +12,6 @@
#include "base/time/time.h"
#include "cc/cc_export.h"
#include "cc/input/browser_controls_state.h"
-#include "cc/metrics/event_latency_tracker.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/paint_holding_reason.h"
#include "cc/trees/proxy.h"
@@ -67,13 +66,14 @@ class CC_EXPORT ProxyMain : public Proxy {
void DidCompleteCommit(CommitTimestamps);
void DidPresentCompositorFrame(
uint32_t frame_token,
- std::vector<PresentationTimeCallbackBuffer::MainCallback> callbacks,
+ std::vector<PresentationTimeCallbackBuffer::Callback>
+ presentation_callbacks,
+ std::vector<PresentationTimeCallbackBuffer::SuccessfulCallback>
+ successful_presentation_callbacks,
const gfx::PresentationFeedback& feedback);
void NotifyThroughputTrackerResults(CustomTrackerResults results);
void DidObserveFirstScrollDelay(base::TimeDelta first_scroll_delay,
base::TimeTicks first_scroll_timestamp);
- void ReportEventLatency(
- std::vector<EventLatencyTracker::LatencyData> latencies);
void NotifyTransitionRequestFinished(uint32_t sequence_id);
CommitPipelineStage max_requested_pipeline_stage() const {
diff --git a/chromium/cc/trees/raster_context_provider_wrapper.cc b/chromium/cc/trees/raster_context_provider_wrapper.cc
index a113c6b6d78..6ce0e27486e 100644
--- a/chromium/cc/trees/raster_context_provider_wrapper.cc
+++ b/chromium/cc/trees/raster_context_provider_wrapper.cc
@@ -4,6 +4,7 @@
#include "cc/trees/raster_context_provider_wrapper.h"
+#include "base/functional/bind.h"
#include "cc/tiles/gpu_image_decode_cache.h"
#include "components/viz/common/gpu/raster_context_provider.h"
@@ -55,6 +56,15 @@ RasterContextProviderWrapper::RasterContextProviderWrapper(
max_working_set_bytes_(max_working_set_bytes),
max_texture_size_(GetMaxTextureSize(context_)) {
CheckValidThreadOrLockSupported();
+
+ viz::RasterContextProvider::ScopedRasterContextLock scoped_context(
+ context.get());
+ // This callback can use a raw ptr for the cb as the wrapper outlive the cache
+ // controller.
+ context_->CacheController()->SetNotifyAllClientsVisibilityChangedCb(
+ base::BindRepeating(
+ &RasterContextProviderWrapper::OnAllClientsVisibilityChanged,
+ base::Unretained(this)));
}
RasterContextProviderWrapper::~RasterContextProviderWrapper() {
@@ -70,6 +80,32 @@ void RasterContextProviderWrapper::CheckValidThreadOrLockSupported() const {
#endif
}
+void RasterContextProviderWrapper::OnAllClientsVisibilityChanged(bool visible) {
+ // Once all the clients are invisible, we should aggressively free resources
+ // from the image decode caches. This what ContextCacheController also does -
+ // it notifies the context support it must aggressively free resources if
+ // all clients that share the same context became invisible.
+ const bool should_aggressively_free_resources = !visible;
+
+ // The caller of
+ // ContextCacheController::ClientBecomeVisible/ClientBecomeNotVisible must
+ // acquire lock. Thus, we are called with lock acquired. Unfortunately, we
+ // have to either make ImageDecodeCache require acquiring lock or provide it
+ // with information that lock has been acquired. Otherwise, a deadlock
+ // happens.
+ //
+ // If lock is not supported, lock has not been acquired.
+ const bool context_lock_acquired = context_supports_locking_;
+ if (context_supports_locking_)
+ context_->GetLock()->AssertAcquired();
+
+ base::AutoLock scoped_lock(lock_);
+ for (const auto& item : gpu_image_decode_cache_map_) {
+ item.second->SetShouldAggressivelyFreeResources(
+ should_aggressively_free_resources, context_lock_acquired);
+ }
+}
+
const scoped_refptr<viz::RasterContextProvider>&
RasterContextProviderWrapper::GetContext() const {
return context_;
diff --git a/chromium/cc/trees/raster_context_provider_wrapper.h b/chromium/cc/trees/raster_context_provider_wrapper.h
index 31722c66ebf..a2a9aa528a5 100644
--- a/chromium/cc/trees/raster_context_provider_wrapper.h
+++ b/chromium/cc/trees/raster_context_provider_wrapper.h
@@ -58,6 +58,8 @@ class CC_EXPORT RasterContextProviderWrapper
void CheckValidThreadOrLockSupported() const;
+ void OnAllClientsVisibilityChanged(bool visible);
+
// The worker context that this wrapper holds.
const scoped_refptr<viz::RasterContextProvider> context_;
diff --git a/chromium/cc/trees/render_frame_metadata_observer.h b/chromium/cc/trees/render_frame_metadata_observer.h
index fb225b53dd0..a44d34896a4 100644
--- a/chromium/cc/trees/render_frame_metadata_observer.h
+++ b/chromium/cc/trees/render_frame_metadata_observer.h
@@ -29,7 +29,7 @@ class CC_EXPORT RenderFrameMetadataObserver {
// Binds on the current thread. This should only be called from the compositor
// thread.
- virtual void BindToCurrentThread() = 0;
+ virtual void BindToCurrentSequence() = 0;
// Notification of the RendarFrameMetadata for the frame being submitted to
// the display compositor.
diff --git a/chromium/cc/trees/single_thread_proxy.cc b/chromium/cc/trees/single_thread_proxy.cc
index ad5e3b1d8c9..e5957253734 100644
--- a/chromium/cc/trees/single_thread_proxy.cc
+++ b/chromium/cc/trees/single_thread_proxy.cc
@@ -192,6 +192,7 @@ void SingleThreadProxy::SetNeedsAnimate() {
DebugScopedSetImplThread impl(task_runner_provider_);
if (scheduler_on_impl_thread_)
scheduler_on_impl_thread_->SetNeedsBeginMainFrame();
+ layer_tree_host_->OnCommitRequested();
}
void SingleThreadProxy::SetNeedsUpdateLayers() {
@@ -669,11 +670,13 @@ void SingleThreadProxy::DidPresentCompositorFrameOnImplThread(
DCHECK(!task_runner_provider_->HasImplThread() ||
task_runner_provider_->IsImplThread());
host_impl_->NotifyDidPresentCompositorFrameOnImplThread(
- frame_token, std::move(callbacks.compositor_thread_callbacks), details);
+ frame_token, std::move(callbacks.compositor_successful_callbacks),
+ details);
{
DebugScopedSetMainThread main(task_runner_provider_);
layer_tree_host_->DidPresentCompositorFrame(
- frame_token, std::move(callbacks.main_thread_callbacks),
+ frame_token, std::move(callbacks.main_callbacks),
+ std::move(callbacks.main_successful_callbacks),
details.presentation_feedback);
}
if (scheduler_on_impl_thread_) {
@@ -773,9 +776,12 @@ void SingleThreadProxy::CompositeImmediatelyForTest(
// a commit here.
commit_requested_ = true;
StopDeferringCommits(PaintHoldingCommitTrigger::kFeatureDisabled);
+ layer_tree_host_->RecordStartOfFrameMetrics();
DoBeginMainFrame(begin_frame_args);
commit_requested_ = false;
DoPainting(begin_frame_args);
+ layer_tree_host_->RecordEndOfFrameMetrics(frame_begin_time,
+ /* trackers */ 0u);
DoCommit(begin_frame_args);
DoPostCommit();
@@ -919,14 +925,6 @@ size_t SingleThreadProxy::CommitDurationSampleCountForTesting() const {
->CommitDurationSampleCountForTesting(); // IN-TEST
}
-void SingleThreadProxy::ReportEventLatency(
- std::vector<EventLatencyTracker::LatencyData> latencies) {
- DCHECK(!task_runner_provider_->HasImplThread() ||
- task_runner_provider_->IsImplThread());
- DebugScopedSetMainThread main(task_runner_provider_);
- layer_tree_host_->ReportEventLatency(std::move(latencies));
-}
-
void SingleThreadProxy::SetRenderFrameObserver(
std::unique_ptr<RenderFrameMetadataObserver> observer) {
DCHECK(task_runner_provider_->IsMainThread());
@@ -1012,9 +1010,10 @@ void SingleThreadProxy::BeginMainFrame(
ScopedAbortRemainingSwapPromises swap_promise_checker(
layer_tree_host_->GetSwapPromiseManager());
+ base::TimeTicks frame_start_time = base::TimeTicks::Now();
+
if (scheduler_on_impl_thread_) {
- scheduler_on_impl_thread_->NotifyBeginMainFrameStarted(
- base::TimeTicks::Now());
+ scheduler_on_impl_thread_->NotifyBeginMainFrameStarted(frame_start_time);
}
commit_requested_ = false;
@@ -1032,6 +1031,13 @@ void SingleThreadProxy::BeginMainFrame(
if (!layer_tree_host_->IsVisible()) {
TRACE_EVENT_INSTANT0("cc", "EarlyOut_NotVisible", TRACE_EVENT_SCOPE_THREAD);
+
+ // Since the commit is deferred due to the page becoming invisible, the
+ // metrics are not meaningful anymore (as the page might become visible in
+ // any arbitrary time in the future and cause an arbitrarily large latency).
+ // Discard event metrics.
+ layer_tree_host_->ClearEventsMetrics();
+
BeginMainFrameAbortedOnImplThread(
CommitEarlyOutReason::ABORTED_NOT_VISIBLE);
return;
@@ -1045,9 +1051,10 @@ void SingleThreadProxy::BeginMainFrame(
// Check now if we should stop deferring commits. Do this before
// DoBeginMainFrame because the latter updates scroll offsets, which
// we should avoid if deferring commits.
- if (IsDeferringCommits() && base::TimeTicks::Now() > commits_restart_time_)
+ if (IsDeferringCommits() && frame_start_time > commits_restart_time_)
StopDeferringCommits(ReasonToTimeoutTrigger(*paint_holding_reason_));
+ layer_tree_host_->RecordStartOfFrameMetrics();
DoBeginMainFrame(begin_frame_args);
// New commits requested inside UpdateLayers should be respected.
@@ -1061,11 +1068,15 @@ void SingleThreadProxy::BeginMainFrame(
TRACE_EVENT_SCOPE_THREAD);
BeginMainFrameAbortedOnImplThread(
CommitEarlyOutReason::ABORTED_DEFERRED_COMMIT);
+ layer_tree_host_->RecordEndOfFrameMetrics(frame_start_time,
+ /* trackers */ 0u);
layer_tree_host_->DidBeginMainFrame();
return;
}
DoPainting(begin_frame_args);
+ layer_tree_host_->RecordEndOfFrameMetrics(frame_start_time,
+ /* trackers */ 0u);
}
void SingleThreadProxy::DoBeginMainFrame(
diff --git a/chromium/cc/trees/single_thread_proxy.h b/chromium/cc/trees/single_thread_proxy.h
index b6535843a37..d6575b654c9 100644
--- a/chromium/cc/trees/single_thread_proxy.h
+++ b/chromium/cc/trees/single_thread_proxy.h
@@ -149,8 +149,6 @@ class CC_EXPORT SingleThreadProxy : public Proxy,
const base::flat_set<viz::FrameSinkId>& ids) override;
void ClearHistory() override;
size_t CommitDurationSampleCountForTesting() const override;
- void ReportEventLatency(
- std::vector<EventLatencyTracker::LatencyData> latencies) override;
void RequestNewLayerTreeFrameSink();
diff --git a/chromium/cc/trees/swap_promise.h b/chromium/cc/trees/swap_promise.h
index 464eaf31637..3fb3c2b85a0 100644
--- a/chromium/cc/trees/swap_promise.h
+++ b/chromium/cc/trees/swap_promise.h
@@ -7,6 +7,7 @@
#include <stdint.h>
+#include "base/time/time.h"
#include "cc/cc_export.h"
#include "components/viz/common/quads/compositor_frame_metadata.h"
@@ -66,7 +67,8 @@ class CC_EXPORT SwapPromise {
// Return `DidNotSwapAction::KEEP_ACTIVE` if this promise should remain active
// (should not be broken by the owner).
- virtual DidNotSwapAction DidNotSwap(DidNotSwapReason reason) = 0;
+ virtual DidNotSwapAction DidNotSwap(DidNotSwapReason reason,
+ base::TimeTicks timestamp) = 0;
// This is called when the main thread starts a (blocking) commit
virtual void OnCommit() {}
diff --git a/chromium/cc/trees/swap_promise_manager.cc b/chromium/cc/trees/swap_promise_manager.cc
index 096cd8ce574..cee8978b33e 100644
--- a/chromium/cc/trees/swap_promise_manager.cc
+++ b/chromium/cc/trees/swap_promise_manager.cc
@@ -55,8 +55,10 @@ void SwapPromiseManager::BreakSwapPromises(
SwapPromise::DidNotSwapReason reason) {
std::vector<std::unique_ptr<SwapPromise>> keep_active_swap_promises;
keep_active_swap_promises.reserve(swap_promise_list_.size());
+
+ base::TimeTicks timestamp = base::TimeTicks::Now();
for (auto& swap_promise : swap_promise_list_) {
- if (swap_promise->DidNotSwap(reason) ==
+ if (swap_promise->DidNotSwap(reason, timestamp) ==
SwapPromise::DidNotSwapAction::KEEP_ACTIVE) {
keep_active_swap_promises.push_back(std::move(swap_promise));
}
diff --git a/chromium/cc/trees/swap_promise_manager_unittest.cc b/chromium/cc/trees/swap_promise_manager_unittest.cc
index aeb331dd180..49b30447acb 100644
--- a/chromium/cc/trees/swap_promise_manager_unittest.cc
+++ b/chromium/cc/trees/swap_promise_manager_unittest.cc
@@ -7,6 +7,7 @@
#include <memory>
#include <utility>
+#include "base/time/time.h"
#include "cc/test/mock_latency_info_swap_promise_monitor.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -24,7 +25,8 @@ class MockSwapPromise : public SwapPromise {
void DidActivate() override {}
void WillSwap(viz::CompositorFrameMetadata* metadata) override {}
void DidSwap() override {}
- DidNotSwapAction DidNotSwap(DidNotSwapReason reason) override {
+ DidNotSwapAction DidNotSwap(DidNotSwapReason reason,
+ base::TimeTicks ts) override {
return DidNotSwapAction::BREAK_PROMISE;
}
MOCK_METHOD0(OnCommit, void());
diff --git a/chromium/cc/trees/tree_synchronizer.cc b/chromium/cc/trees/tree_synchronizer.cc
index 9491da32220..6274802f870 100644
--- a/chromium/cc/trees/tree_synchronizer.cc
+++ b/chromium/cc/trees/tree_synchronizer.cc
@@ -15,7 +15,6 @@
#include "base/containers/flat_set.h"
#include "base/debug/crash_logging.h"
#include "base/debug/dump_without_crashing.h"
-#include "base/strings/stringprintf.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 6869510b73b..39afbc48613 100644
--- a/chromium/cc/trees/tree_synchronizer_unittest.cc
+++ b/chromium/cc/trees/tree_synchronizer_unittest.cc
@@ -16,7 +16,7 @@
#include "base/format_macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/task/single_thread_task_runner.h"
#include "cc/animation/animation_host.h"
#include "cc/layers/layer.h"
#include "cc/layers/layer_impl.h"
@@ -125,8 +125,9 @@ class TreeSynchronizerTest : public testing::Test {
host_.reset();
host_ = FakeLayerTreeHost::Create(&client_, &task_graph_runner_,
animation_host_.get(), settings);
- host_->InitializeSingleThreaded(&single_thread_client_,
- base::ThreadTaskRunnerHandle::Get());
+ host_->InitializeSingleThreaded(
+ &single_thread_client_,
+ base::SingleThreadTaskRunner::GetCurrentDefault());
host_->host_impl()->CreatePendingTree();
}
diff --git a/chromium/cc/trees/viewport_property_ids.h b/chromium/cc/trees/viewport_property_ids.h
index 240ad01153a..941a010406c 100644
--- a/chromium/cc/trees/viewport_property_ids.h
+++ b/chromium/cc/trees/viewport_property_ids.h
@@ -12,7 +12,6 @@ namespace cc {
struct ViewportPropertyIds {
int overscroll_elasticity_transform = kInvalidPropertyNodeId;
- ElementId overscroll_elasticity_effect;
int page_scale_transform = kInvalidPropertyNodeId;
int inner_scroll = kInvalidPropertyNodeId;
int outer_clip = kInvalidPropertyNodeId;
diff --git a/chromium/cc/document_transition/README.md b/chromium/cc/view_transition/README.md
index 3b764d357b0..10bf4070260 100644
--- a/chromium/cc/document_transition/README.md
+++ b/chromium/cc/view_transition/README.md
@@ -1,5 +1,5 @@
# cc/document\_transition
-The document transition direction supports the Document Transition and Shared
+The view 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/view_transition/view_transition_request.cc
index 1bf2845095c..70030766df7 100644
--- a/chromium/cc/document_transition/document_transition_request.cc
+++ b/chromium/cc/view_transition/view_transition_request.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "cc/document_transition/document_transition_request.h"
+#include "cc/view_transition/view_transition_request.h"
#include <map>
#include <memory>
@@ -14,7 +14,7 @@
#include "base/callback_helpers.h"
#include "base/memory/ptr_util.h"
#include "base/ranges/algorithm.h"
-#include "cc/document_transition/document_transition_shared_element_id.h"
+#include "cc/view_transition/view_transition_shared_element_id.h"
#include "components/viz/common/quads/compositor_frame_transition_directive.h"
#include "components/viz/common/quads/compositor_render_pass.h"
@@ -35,51 +35,58 @@ std::string TypeToString(viz::CompositorFrameTransitionDirective::Type type) {
} // namespace
-uint32_t DocumentTransitionRequest::s_next_sequence_id_ = 1;
+uint32_t ViewTransitionRequest::s_next_sequence_id_ = 1;
// static
-std::unique_ptr<DocumentTransitionRequest>
-DocumentTransitionRequest::CreateCapture(
+std::unique_ptr<ViewTransitionRequest> ViewTransitionRequest::CreateCapture(
uint32_t document_tag,
uint32_t shared_element_count,
- std::vector<viz::SharedElementResourceId> capture_ids,
+ viz::NavigationID navigation_id,
+ std::vector<viz::ViewTransitionElementResourceId> capture_ids,
base::OnceClosure commit_callback) {
- return base::WrapUnique(new DocumentTransitionRequest(
- Type::kSave, document_tag, shared_element_count, std::move(capture_ids),
- std::move(commit_callback)));
+ return base::WrapUnique(new ViewTransitionRequest(
+ Type::kSave, document_tag, shared_element_count, navigation_id,
+ std::move(capture_ids), std::move(commit_callback)));
}
// static
-std::unique_ptr<DocumentTransitionRequest>
-DocumentTransitionRequest::CreateAnimateRenderer(uint32_t document_tag) {
- return base::WrapUnique(new DocumentTransitionRequest(
- Type::kAnimateRenderer, document_tag, 0u, {}, base::DoNothing()));
+std::unique_ptr<ViewTransitionRequest>
+ViewTransitionRequest::CreateAnimateRenderer(uint32_t document_tag,
+ viz::NavigationID navigation_id) {
+ return base::WrapUnique(
+ new ViewTransitionRequest(Type::kAnimateRenderer, document_tag, 0u,
+ navigation_id, {}, base::OnceClosure()));
}
// static
-std::unique_ptr<DocumentTransitionRequest>
-DocumentTransitionRequest::CreateRelease(uint32_t document_tag) {
- return base::WrapUnique(new DocumentTransitionRequest(
- Type::kRelease, document_tag, 0u, {}, base::DoNothing()));
+std::unique_ptr<ViewTransitionRequest> ViewTransitionRequest::CreateRelease(
+ uint32_t document_tag) {
+ return base::WrapUnique(new ViewTransitionRequest(
+ Type::kRelease, document_tag, 0u, viz::NavigationID::Null(), {},
+ base::OnceClosure()));
}
-DocumentTransitionRequest::DocumentTransitionRequest(
+ViewTransitionRequest::ViewTransitionRequest(
Type type,
uint32_t document_tag,
uint32_t shared_element_count,
- std::vector<viz::SharedElementResourceId> capture_ids,
+ viz::NavigationID navigation_id,
+ std::vector<viz::ViewTransitionElementResourceId> capture_ids,
base::OnceClosure commit_callback)
: type_(type),
document_tag_(document_tag),
shared_element_count_(shared_element_count),
+ navigation_id_(navigation_id),
commit_callback_(std::move(commit_callback)),
sequence_id_(s_next_sequence_id_++),
- capture_resource_ids_(std::move(capture_ids)) {}
+ capture_resource_ids_(std::move(capture_ids)) {
+ DCHECK(type_ == Type::kSave || !commit_callback_);
+}
-DocumentTransitionRequest::~DocumentTransitionRequest() = default;
+ViewTransitionRequest::~ViewTransitionRequest() = default;
viz::CompositorFrameTransitionDirective
-DocumentTransitionRequest::ConstructDirective(
+ViewTransitionRequest::ConstructDirective(
const SharedElementMap& shared_element_render_pass_id_map) const {
std::vector<viz::CompositorFrameTransitionDirective::SharedElement>
shared_elements(shared_element_count_);
@@ -93,7 +100,8 @@ DocumentTransitionRequest::ConstructDirective(
if (it == shared_element_render_pass_id_map.end())
continue;
shared_elements[i].render_pass_id = it->second.render_pass_id;
- shared_elements[i].shared_element_resource_id = it->second.resource_id;
+ shared_elements[i].view_transition_element_resource_id =
+ it->second.resource_id;
// Remove the resource id from our capture ids, since we just want to have
// "empty" resource ids left -- the ones that don't have a render pass
@@ -107,22 +115,22 @@ DocumentTransitionRequest::ConstructDirective(
// Add invalid render pass id for each empty resource id left in capture ids.
for (auto& empty_resource_id : capture_resource_ids) {
shared_elements.emplace_back();
- shared_elements.back().shared_element_resource_id = empty_resource_id;
+ shared_elements.back().view_transition_element_resource_id =
+ empty_resource_id;
}
- // TODO(vmpstr): Clean up the directive parameters.
- return viz::CompositorFrameTransitionDirective(sequence_id_, type_,
- std::move(shared_elements));
+ return viz::CompositorFrameTransitionDirective(
+ navigation_id_, sequence_id_, type_, std::move(shared_elements));
}
-std::string DocumentTransitionRequest::ToString() const {
+std::string ViewTransitionRequest::ToString() const {
std::ostringstream str;
str << "[type: " << TypeToString(type_) << " sequence_id: " << sequence_id_
<< "]";
return str.str();
}
-DocumentTransitionRequest::SharedElementInfo::SharedElementInfo() = default;
-DocumentTransitionRequest::SharedElementInfo::~SharedElementInfo() = default;
+ViewTransitionRequest::SharedElementInfo::SharedElementInfo() = default;
+ViewTransitionRequest::SharedElementInfo::~SharedElementInfo() = default;
} // namespace cc
diff --git a/chromium/cc/document_transition/document_transition_request.h b/chromium/cc/view_transition/view_transition_request.h
index b57c86118d5..9a476df348c 100644
--- a/chromium/cc/document_transition/document_transition_request.h
+++ b/chromium/cc/view_transition/view_transition_request.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CC_DOCUMENT_TRANSITION_DOCUMENT_TRANSITION_REQUEST_H_
-#define CC_DOCUMENT_TRANSITION_DOCUMENT_TRANSITION_REQUEST_H_
+#ifndef CC_VIEW_TRANSITION_VIEW_TRANSITION_REQUEST_H_
+#define CC_VIEW_TRANSITION_VIEW_TRANSITION_REQUEST_H_
#include <map>
#include <memory>
@@ -13,47 +13,48 @@
#include "base/callback.h"
#include "cc/cc_export.h"
-#include "cc/document_transition/document_transition_shared_element_id.h"
+#include "cc/view_transition/view_transition_shared_element_id.h"
#include "components/viz/common/quads/compositor_frame_transition_directive.h"
#include "components/viz/common/quads/compositor_render_pass.h"
namespace cc {
-// This class represents a document transition request. It is constructed in
+// This class represents a view 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 {
+class CC_EXPORT ViewTransitionRequest {
public:
struct CC_EXPORT SharedElementInfo {
SharedElementInfo();
~SharedElementInfo();
viz::CompositorRenderPassId render_pass_id;
- viz::SharedElementResourceId resource_id;
+ viz::ViewTransitionElementResourceId resource_id;
};
- using SharedElementMap =
- std::map<DocumentTransitionSharedElementId, SharedElementInfo>;
+ using SharedElementMap = std::map<ViewTransitionElementId, SharedElementInfo>;
// Creates a Type::kCapture type of request.
- static std::unique_ptr<DocumentTransitionRequest> CreateCapture(
+ static std::unique_ptr<ViewTransitionRequest> CreateCapture(
uint32_t document_tag,
uint32_t shared_element_count,
- std::vector<viz::SharedElementResourceId> capture_ids,
+ viz::NavigationID navigation_id,
+ std::vector<viz::ViewTransitionElementResourceId> capture_ids,
base::OnceClosure commit_callback);
// Creates a Type::kAnimateRenderer type of request.
- static std::unique_ptr<DocumentTransitionRequest> CreateAnimateRenderer(
- uint32_t document_tag);
+ static std::unique_ptr<ViewTransitionRequest> CreateAnimateRenderer(
+ uint32_t document_tag,
+ viz::NavigationID navigation_id);
// Creates a Type::kRelease type of request.
- static std::unique_ptr<DocumentTransitionRequest> CreateRelease(
+ static std::unique_ptr<ViewTransitionRequest> CreateRelease(
uint32_t document_tag);
- DocumentTransitionRequest(DocumentTransitionRequest&) = delete;
- ~DocumentTransitionRequest();
+ ViewTransitionRequest(ViewTransitionRequest&) = delete;
+ ~ViewTransitionRequest();
- DocumentTransitionRequest& operator=(DocumentTransitionRequest&) = delete;
+ ViewTransitionRequest& operator=(ViewTransitionRequest&) = delete;
// The callback is run when the request is sufficiently processed for us to be
// able to begin the next step in the animation. In other words, when this
@@ -78,23 +79,25 @@ class CC_EXPORT DocumentTransitionRequest {
private:
using Type = viz::CompositorFrameTransitionDirective::Type;
- DocumentTransitionRequest(
+ ViewTransitionRequest(
Type type,
uint32_t document_tag,
uint32_t shared_element_count,
- std::vector<viz::SharedElementResourceId> capture_ids,
+ viz::NavigationID navigation_id,
+ std::vector<viz::ViewTransitionElementResourceId> capture_ids,
base::OnceClosure commit_callback);
const Type type_;
const uint32_t document_tag_;
const uint32_t shared_element_count_;
+ const viz::NavigationID navigation_id_;
base::OnceClosure commit_callback_;
const uint32_t sequence_id_;
- const std::vector<viz::SharedElementResourceId> capture_resource_ids_;
+ const std::vector<viz::ViewTransitionElementResourceId> capture_resource_ids_;
static uint32_t s_next_sequence_id_;
};
} // namespace cc
-#endif // CC_DOCUMENT_TRANSITION_DOCUMENT_TRANSITION_REQUEST_H_
+#endif // CC_VIEW_TRANSITION_VIEW_TRANSITION_REQUEST_H_
diff --git a/chromium/cc/document_transition/document_transition_request_unittest.cc b/chromium/cc/view_transition/view_transition_request_unittest.cc
index 10cc50102de..1032437e52d 100644
--- a/chromium/cc/document_transition/document_transition_request_unittest.cc
+++ b/chromium/cc/view_transition/view_transition_request_unittest.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "cc/document_transition/document_transition_request.h"
+#include "cc/view_transition/view_transition_request.h"
#include <utility>
@@ -11,12 +11,13 @@
namespace cc {
-TEST(DocumentTransitionRequestTest, PrepareRequest) {
+TEST(ViewTransitionRequestTest, PrepareRequest) {
bool called = false;
auto callback = base::BindLambdaForTesting([&called]() { called = true; });
- auto request = DocumentTransitionRequest::CreateCapture(
- /*document_tag=*/0, /*shared_element_count=*/0, {}, std::move(callback));
+ auto request = ViewTransitionRequest::CreateCapture(
+ /*document_tag=*/0, /*shared_element_count=*/0, viz::NavigationID::Null(),
+ {}, std::move(callback));
EXPECT_FALSE(called);
request->TakeFinishedCallback().Run();
@@ -33,11 +34,10 @@ TEST(DocumentTransitionRequestTest, PrepareRequest) {
EXPECT_EQ(duplicate.type(), directive.type());
}
-TEST(DocumentTransitionRequestTest, StartRequest) {
- auto request = DocumentTransitionRequest::CreateAnimateRenderer(
- /*document_tag=*/0);
+TEST(ViewTransitionRequestTest, StartRequest) {
+ auto request = ViewTransitionRequest::CreateAnimateRenderer(
+ /*document_tag=*/0, viz::NavigationID::Null());
- request->TakeFinishedCallback().Run();
EXPECT_TRUE(request->TakeFinishedCallback().is_null());
auto directive = request->ConstructDirective({});
diff --git a/chromium/cc/view_transition/view_transition_shared_element_id.cc b/chromium/cc/view_transition/view_transition_shared_element_id.cc
new file mode 100644
index 00000000000..ed88e6e1474
--- /dev/null
+++ b/chromium/cc/view_transition/view_transition_shared_element_id.cc
@@ -0,0 +1,51 @@
+// Copyright 2021 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/view_transition/view_transition_shared_element_id.h"
+
+#include <sstream>
+#include <string>
+
+#include "base/check_op.h"
+#include "base/containers/flat_set.h"
+
+namespace cc {
+
+ViewTransitionElementId::ViewTransitionElementId() = default;
+
+ViewTransitionElementId::ViewTransitionElementId(uint32_t document_tag)
+ : document_tag_(document_tag) {}
+
+ViewTransitionElementId::ViewTransitionElementId(ViewTransitionElementId&&) =
+ default;
+
+ViewTransitionElementId::ViewTransitionElementId(
+ const ViewTransitionElementId&) = default;
+
+ViewTransitionElementId::~ViewTransitionElementId() = default;
+
+void ViewTransitionElementId::AddIndex(uint32_t index) {
+ DCHECK_NE(document_tag_, 0u);
+ element_indices_.insert(index);
+}
+
+bool ViewTransitionElementId::Matches(uint32_t document_tag,
+ uint32_t index) const {
+ return document_tag_ == document_tag && element_indices_.count(index) != 0;
+}
+
+std::string ViewTransitionElementId::ToString() const {
+ std::ostringstream str;
+ str << "ViewTransitionElementId{ document_tag: " << document_tag_
+ << " element_indices: [";
+ std::string separator = "";
+ for (auto index : element_indices_) {
+ str << separator << index;
+ separator = ", ";
+ }
+ str << "]}";
+ return str.str();
+}
+
+} // namespace cc
diff --git a/chromium/cc/document_transition/document_transition_shared_element_id.h b/chromium/cc/view_transition/view_transition_shared_element_id.h
index 134a449626a..f3e41181351 100644
--- a/chromium/cc/document_transition/document_transition_shared_element_id.h
+++ b/chromium/cc/view_transition/view_transition_shared_element_id.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CC_DOCUMENT_TRANSITION_DOCUMENT_TRANSITION_SHARED_ELEMENT_ID_H_
-#define CC_DOCUMENT_TRANSITION_DOCUMENT_TRANSITION_SHARED_ELEMENT_ID_H_
+#ifndef CC_VIEW_TRANSITION_VIEW_TRANSITION_SHARED_ELEMENT_ID_H_
+#define CC_VIEW_TRANSITION_VIEW_TRANSITION_SHARED_ELEMENT_ID_H_
#include <stdint.h>
@@ -15,13 +15,13 @@
namespace cc {
-class CC_EXPORT DocumentTransitionSharedElementId {
+class CC_EXPORT ViewTransitionElementId {
public:
- DocumentTransitionSharedElementId();
- explicit DocumentTransitionSharedElementId(uint32_t document_tag);
- DocumentTransitionSharedElementId(const DocumentTransitionSharedElementId&);
- DocumentTransitionSharedElementId(DocumentTransitionSharedElementId&&);
- ~DocumentTransitionSharedElementId();
+ ViewTransitionElementId();
+ explicit ViewTransitionElementId(uint32_t document_tag);
+ ViewTransitionElementId(const ViewTransitionElementId&);
+ ViewTransitionElementId(ViewTransitionElementId&&);
+ ~ViewTransitionElementId();
// Add a shared index to this id. It must have a valid document tag.
void AddIndex(uint32_t index);
@@ -30,22 +30,20 @@ class CC_EXPORT DocumentTransitionSharedElementId {
// list of indices for this id.
bool Matches(uint32_t document_tag, uint32_t index) const;
- DocumentTransitionSharedElementId& operator=(
- DocumentTransitionSharedElementId&&) = default;
+ ViewTransitionElementId& operator=(ViewTransitionElementId&&) = default;
- DocumentTransitionSharedElementId& operator=(
- const DocumentTransitionSharedElementId&) = default;
+ ViewTransitionElementId& operator=(const ViewTransitionElementId&) = default;
- bool operator==(const DocumentTransitionSharedElementId& other) const {
+ bool operator==(const ViewTransitionElementId& other) const {
return element_indices_ == other.element_indices_ &&
document_tag_ == other.document_tag_;
}
- bool operator!=(const DocumentTransitionSharedElementId& other) const {
+ bool operator!=(const ViewTransitionElementId& other) const {
return !(*this == other);
}
- bool operator<(const DocumentTransitionSharedElementId& other) const {
+ bool operator<(const ViewTransitionElementId& other) const {
return std::tie(document_tag_, element_indices_) <
std::tie(other.document_tag_, other.element_indices_);
}
@@ -63,4 +61,4 @@ class CC_EXPORT DocumentTransitionSharedElementId {
} // namespace cc
-#endif // CC_DOCUMENT_TRANSITION_DOCUMENT_TRANSITION_SHARED_ELEMENT_ID_H_
+#endif // CC_VIEW_TRANSITION_VIEW_TRANSITION_SHARED_ELEMENT_ID_H_