summaryrefslogtreecommitdiff
path: root/chromium/cc
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2017-07-17 13:57:45 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2017-07-19 13:44:40 +0000
commit6ec7b8da05d21a3878bd21c691b41e675d74bb1c (patch)
treeb87f250bc19413750b9bb9cdbf2da20ef5014820 /chromium/cc
parentec02ee4181c49b61fce1c8fb99292dbb8139cc90 (diff)
downloadqtwebengine-chromium-6ec7b8da05d21a3878bd21c691b41e675d74bb1c.tar.gz
BASELINE: Update Chromium to 60.0.3112.70
Change-Id: I9911c2280a014d4632f254857876a395d4baed2d Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/cc')
-rw-r--r--chromium/cc/BUILD.gn15
-rw-r--r--chromium/cc/OWNERS3
-rw-r--r--chromium/cc/README.md199
-rw-r--r--chromium/cc/animation/animation_host.cc6
-rw-r--r--chromium/cc/animation/animation_host.h10
-rw-r--r--chromium/cc/animation/animation_host_unittest.cc3
-rw-r--r--chromium/cc/animation/animation_player.cc28
-rw-r--r--chromium/cc/animation/animation_player_unittest.cc8
-rw-r--r--chromium/cc/animation/element_animations_unittest.cc49
-rw-r--r--chromium/cc/animation/keyframed_animation_curve_unittest.cc61
-rw-r--r--chromium/cc/animation/scroll_offset_animations_impl.cc4
-rw-r--r--chromium/cc/animation/scroll_offset_animations_impl.h6
-rw-r--r--chromium/cc/animation/timing_function.cc45
-rw-r--r--chromium/cc/animation/timing_function.h25
-rw-r--r--chromium/cc/base/BUILD.gn1
-rw-r--r--chromium/cc/base/list_container.h32
-rw-r--r--chromium/cc/base/list_container_helper.cc50
-rw-r--r--chromium/cc/base/list_container_helper.h11
-rw-r--r--chromium/cc/base/list_container_unittest.cc151
-rw-r--r--chromium/cc/base/math_util.cc8
-rw-r--r--chromium/cc/base/math_util.h6
-rw-r--r--chromium/cc/base/math_util_unittest.cc4
-rw-r--r--chromium/cc/base/random_access_list_container.h96
-rw-r--r--chromium/cc/base/random_access_list_container_unittest.cc109
-rw-r--r--chromium/cc/base/resource_id.h5
-rw-r--r--chromium/cc/base/rtree.cc13
-rw-r--r--chromium/cc/base/rtree.h31
-rw-r--r--chromium/cc/base/rtree_perftest.cc11
-rw-r--r--chromium/cc/base/rtree_unittest.cc46
-rw-r--r--chromium/cc/base/simple_enclosed_region.cc17
-rw-r--r--chromium/cc/base/simple_enclosed_region_unittest.cc154
-rw-r--r--chromium/cc/base/switches.cc11
-rw-r--r--chromium/cc/base/switches.h4
-rw-r--r--chromium/cc/benchmarks/rasterize_and_record_benchmark.cc8
-rw-r--r--chromium/cc/benchmarks/unittest_only_benchmark.h1
-rw-r--r--chromium/cc/blink/web_display_item_list_impl.cc6
-rw-r--r--chromium/cc/blink/web_display_item_list_impl.h3
-rw-r--r--chromium/cc/blink/web_image_layer_impl.cc9
-rw-r--r--chromium/cc/blink/web_image_layer_impl.h3
-rw-r--r--chromium/cc/blink/web_layer_impl.cc8
-rw-r--r--chromium/cc/blink/web_layer_impl.h2
-rw-r--r--chromium/cc/blink/web_scrollbar_layer_impl.cc17
-rw-r--r--chromium/cc/blink/web_scrollbar_layer_impl.h2
-rw-r--r--chromium/cc/debug/debug_colors.cc2
-rw-r--r--chromium/cc/input/browser_controls_offset_manager.h4
-rw-r--r--chromium/cc/input/main_thread_scrolling_reason.h10
-rw-r--r--chromium/cc/input/scrollbar_animation_controller.cc189
-rw-r--r--chromium/cc/input/scrollbar_animation_controller.h52
-rw-r--r--chromium/cc/input/scrollbar_animation_controller_unittest.cc418
-rw-r--r--chromium/cc/input/scroller_size_metrics.h20
-rw-r--r--chromium/cc/input/single_scrollbar_animation_controller_thinning.cc103
-rw-r--r--chromium/cc/input/single_scrollbar_animation_controller_thinning.h28
-rw-r--r--chromium/cc/input/single_scrollbar_animation_controller_thinning_unittest.cc89
-rw-r--r--chromium/cc/input/touch_action.h56
-rw-r--r--chromium/cc/ipc/begin_frame_args_struct_traits.cc2
-rw-r--r--chromium/cc/ipc/cc_param_traits.cc36
-rw-r--r--chromium/cc/ipc/cc_param_traits.h11
-rw-r--r--chromium/cc/ipc/cc_param_traits_macros.h11
-rw-r--r--chromium/cc/ipc/cc_param_traits_unittest.cc32
-rw-r--r--chromium/cc/ipc/cc_serialization_perftest.cc6
-rw-r--r--chromium/cc/ipc/compositor_frame_metadata.mojom2
-rw-r--r--chromium/cc/ipc/compositor_frame_metadata_struct_traits.cc2
-rw-r--r--chromium/cc/ipc/compositor_frame_metadata_struct_traits.h4
-rw-r--r--chromium/cc/ipc/compositor_frame_struct_traits.cc8
-rw-r--r--chromium/cc/ipc/mojo_compositor_frame_sink.mojom4
-rw-r--r--chromium/cc/ipc/quads.mojom2
-rw-r--r--chromium/cc/ipc/quads_struct_traits.cc3
-rw-r--r--chromium/cc/ipc/quads_struct_traits.h6
-rw-r--r--chromium/cc/ipc/shared_quad_state.mojom4
-rw-r--r--chromium/cc/ipc/shared_quad_state_struct_traits.h10
-rw-r--r--chromium/cc/ipc/struct_traits_unittest.cc146
-rw-r--r--chromium/cc/ipc/transferable_resource.mojom2
-rw-r--r--chromium/cc/ipc/transferable_resource_struct_traits.cc3
-rw-r--r--chromium/cc/ipc/transferable_resource_struct_traits.h6
-rw-r--r--chromium/cc/layers/append_quads_data.h6
-rw-r--r--chromium/cc/layers/effect_tree_layer_list_iterator.cc27
-rw-r--r--chromium/cc/layers/effect_tree_layer_list_iterator_unittest.cc53
-rw-r--r--chromium/cc/layers/heads_up_display_layer_impl.cc4
-rw-r--r--chromium/cc/layers/layer.cc125
-rw-r--r--chromium/cc/layers/layer.h33
-rw-r--r--chromium/cc/layers/layer_collections.h2
-rw-r--r--chromium/cc/layers/layer_impl.cc162
-rw-r--r--chromium/cc/layers/layer_impl.h85
-rw-r--r--chromium/cc/layers/layer_impl_test_properties.cc1
-rw-r--r--chromium/cc/layers/layer_impl_test_properties.h1
-rw-r--r--chromium/cc/layers/layer_impl_unittest.cc57
-rw-r--r--chromium/cc/layers/layer_position_constraint_unittest.cc119
-rw-r--r--chromium/cc/layers/layer_unittest.cc65
-rw-r--r--chromium/cc/layers/nine_patch_layer_unittest.cc1
-rw-r--r--chromium/cc/layers/paint_properties.h23
-rw-r--r--chromium/cc/layers/painted_overlay_scrollbar_layer.cc26
-rw-r--r--chromium/cc/layers/painted_overlay_scrollbar_layer.h11
-rw-r--r--chromium/cc/layers/painted_scrollbar_layer.cc24
-rw-r--r--chromium/cc/layers/painted_scrollbar_layer.h11
-rw-r--r--chromium/cc/layers/painted_scrollbar_layer_impl.cc5
-rw-r--r--chromium/cc/layers/painted_scrollbar_layer_impl.h2
-rw-r--r--chromium/cc/layers/painted_scrollbar_layer_unittest.cc3
-rw-r--r--chromium/cc/layers/picture_image_layer.cc23
-rw-r--r--chromium/cc/layers/picture_image_layer.h7
-rw-r--r--chromium/cc/layers/picture_image_layer_unittest.cc3
-rw-r--r--chromium/cc/layers/picture_layer.cc16
-rw-r--r--chromium/cc/layers/picture_layer_impl.cc110
-rw-r--r--chromium/cc/layers/picture_layer_impl.h12
-rw-r--r--chromium/cc/layers/picture_layer_impl_perftest.cc25
-rw-r--r--chromium/cc/layers/picture_layer_impl_unittest.cc185
-rw-r--r--chromium/cc/layers/picture_layer_unittest.cc90
-rw-r--r--chromium/cc/layers/recording_source.cc13
-rw-r--r--chromium/cc/layers/recording_source.h2
-rw-r--r--chromium/cc/layers/recording_source_unittest.cc26
-rw-r--r--chromium/cc/layers/render_surface_impl.cc51
-rw-r--r--chromium/cc/layers/render_surface_impl.h23
-rw-r--r--chromium/cc/layers/render_surface_impl_unittest.cc19
-rw-r--r--chromium/cc/layers/render_surface_unittest.cc12
-rw-r--r--chromium/cc/layers/scrollbar_layer_impl_base.cc53
-rw-r--r--chromium/cc/layers/scrollbar_layer_impl_base.h19
-rw-r--r--chromium/cc/layers/scrollbar_layer_interface.h4
-rw-r--r--chromium/cc/layers/scrollbar_layer_unittest.cc125
-rw-r--r--chromium/cc/layers/solid_color_scrollbar_layer.cc30
-rw-r--r--chromium/cc/layers/solid_color_scrollbar_layer.h13
-rw-r--r--chromium/cc/layers/surface_layer.cc1
-rw-r--r--chromium/cc/layers/surface_layer_impl.cc44
-rw-r--r--chromium/cc/layers/surface_layer_impl.h7
-rw-r--r--chromium/cc/layers/surface_layer_impl_unittest.cc76
-rw-r--r--chromium/cc/layers/surface_layer_unittest.cc162
-rw-r--r--chromium/cc/layers/texture_layer_unittest.cc24
-rw-r--r--chromium/cc/layers/ui_resource_layer_unittest.cc5
-rw-r--r--chromium/cc/layers/video_layer_impl.cc7
-rw-r--r--chromium/cc/output/bsp_tree_perftest.cc16
-rw-r--r--chromium/cc/output/ca_layer_overlay.cc35
-rw-r--r--chromium/cc/output/ca_layer_overlay.h6
-rw-r--r--chromium/cc/output/compositor_frame.cc1
-rw-r--r--chromium/cc/output/compositor_frame_metadata.h14
-rw-r--r--chromium/cc/output/compositor_frame_sink.h19
-rw-r--r--chromium/cc/output/compositor_frame_sink_unittest.cc1
-rw-r--r--chromium/cc/output/dc_layer_overlay.cc16
-rw-r--r--chromium/cc/output/dc_layer_overlay.h7
-rw-r--r--chromium/cc/output/direct_renderer.cc54
-rw-r--r--chromium/cc/output/direct_renderer.h16
-rw-r--r--chromium/cc/output/gl_renderer.cc64
-rw-r--r--chromium/cc/output/gl_renderer.h5
-rw-r--r--chromium/cc/output/gl_renderer_unittest.cc14
-rw-r--r--chromium/cc/output/overlay_processor.cc33
-rw-r--r--chromium/cc/output/overlay_processor.h17
-rw-r--r--chromium/cc/output/overlay_strategy_fullscreen.cc4
-rw-r--r--chromium/cc/output/overlay_strategy_single_on_top.cc2
-rw-r--r--chromium/cc/output/overlay_unittest.cc304
-rw-r--r--chromium/cc/output/renderer_pixeltest.cc94
-rw-r--r--chromium/cc/output/renderer_settings.h6
-rw-r--r--chromium/cc/output/software_renderer.cc60
-rw-r--r--chromium/cc/output/software_renderer_unittest.cc40
-rw-r--r--chromium/cc/paint/BUILD.gn10
-rw-r--r--chromium/cc/paint/clip_display_item.h4
-rw-r--r--chromium/cc/paint/clip_path_display_item.h4
-rw-r--r--chromium/cc/paint/compositing_display_item.h4
-rw-r--r--chromium/cc/paint/discardable_image_map.cc257
-rw-r--r--chromium/cc/paint/discardable_image_map.h19
-rw-r--r--chromium/cc/paint/discardable_image_map_unittest.cc280
-rw-r--r--chromium/cc/paint/discardable_image_store.cc259
-rw-r--r--chromium/cc/paint/discardable_image_store.h52
-rw-r--r--chromium/cc/paint/display_item_list.cc124
-rw-r--r--chromium/cc/paint/display_item_list.h29
-rw-r--r--chromium/cc/paint/display_item_list_unittest.cc201
-rw-r--r--chromium/cc/paint/draw_image.cc7
-rw-r--r--chromium/cc/paint/draw_image.h12
-rw-r--r--chromium/cc/paint/drawing_display_item.cc16
-rw-r--r--chromium/cc/paint/drawing_display_item.h6
-rw-r--r--chromium/cc/paint/filter_display_item.h4
-rw-r--r--chromium/cc/paint/float_clip_display_item.h4
-rw-r--r--chromium/cc/paint/image_id.h9
-rw-r--r--chromium/cc/paint/paint_canvas.cc4
-rw-r--r--chromium/cc/paint/paint_canvas.h51
-rw-r--r--chromium/cc/paint/paint_flags.cc42
-rw-r--r--chromium/cc/paint/paint_flags.h12
-rw-r--r--chromium/cc/paint/paint_image.cc39
-rw-r--r--chromium/cc/paint/paint_image.h66
-rw-r--r--chromium/cc/paint/paint_op_buffer.cc797
-rw-r--r--chromium/cc/paint/paint_op_buffer.h978
-rw-r--r--chromium/cc/paint/paint_op_buffer_unittest.cc901
-rw-r--r--chromium/cc/paint/paint_record.cc27
-rw-r--r--chromium/cc/paint/paint_record.h19
-rw-r--r--chromium/cc/paint/paint_recorder.cc27
-rw-r--r--chromium/cc/paint/paint_recorder.h35
-rw-r--r--chromium/cc/paint/paint_shader.h8
-rw-r--r--chromium/cc/paint/record_paint_canvas.cc372
-rw-r--r--chromium/cc/paint/record_paint_canvas.h158
-rw-r--r--chromium/cc/paint/skia_paint_canvas.cc51
-rw-r--r--chromium/cc/paint/skia_paint_canvas.h21
-rw-r--r--chromium/cc/paint/transform_display_item.cc6
-rw-r--r--chromium/cc/paint/transform_display_item.h4
-rw-r--r--chromium/cc/quads/draw_polygon_unittest.cc2
-rw-r--r--chromium/cc/quads/draw_quad.h4
-rw-r--r--chromium/cc/quads/draw_quad_perftest.cc4
-rw-r--r--chromium/cc/quads/draw_quad_unittest.cc8
-rw-r--r--chromium/cc/quads/largest_draw_quad.cc55
-rw-r--r--chromium/cc/quads/largest_draw_quad.h1
-rw-r--r--chromium/cc/quads/render_pass.cc22
-rw-r--r--chromium/cc/quads/render_pass.h5
-rw-r--r--chromium/cc/quads/render_pass_unittest.cc23
-rw-r--r--chromium/cc/quads/shared_quad_state.cc6
-rw-r--r--chromium/cc/quads/shared_quad_state.h6
-rw-r--r--chromium/cc/raster/bitmap_raster_buffer_provider.cc2
-rw-r--r--chromium/cc/raster/bitmap_raster_buffer_provider.h1
-rw-r--r--chromium/cc/raster/gpu_raster_buffer_provider.cc10
-rw-r--r--chromium/cc/raster/gpu_raster_buffer_provider.h1
-rw-r--r--chromium/cc/raster/image_hijack_canvas.cc48
-rw-r--r--chromium/cc/raster/image_hijack_canvas.h5
-rw-r--r--chromium/cc/raster/image_hijack_canvas_unittest.cc28
-rw-r--r--chromium/cc/raster/one_copy_raster_buffer_provider.cc26
-rw-r--r--chromium/cc/raster/one_copy_raster_buffer_provider.h4
-rw-r--r--chromium/cc/raster/raster_buffer_provider.cc55
-rw-r--r--chromium/cc/raster/raster_buffer_provider.h4
-rw-r--r--chromium/cc/raster/raster_source.cc10
-rw-r--r--chromium/cc/raster/raster_source.h6
-rw-r--r--chromium/cc/raster/raster_source_unittest.cc2
-rw-r--r--chromium/cc/raster/staging_buffer_pool.cc4
-rw-r--r--chromium/cc/raster/zero_copy_raster_buffer_provider.cc2
-rw-r--r--chromium/cc/raster/zero_copy_raster_buffer_provider.h1
-rw-r--r--chromium/cc/resources/resource_pool.cc44
-rw-r--r--chromium/cc/resources/resource_pool.h20
-rw-r--r--chromium/cc/resources/resource_pool_unittest.cc126
-rw-r--r--chromium/cc/resources/resource_provider.cc13
-rw-r--r--chromium/cc/resources/resource_provider.h4
-rw-r--r--chromium/cc/resources/ui_resource_bitmap.cc39
-rw-r--r--chromium/cc/resources/ui_resource_bitmap.h26
-rw-r--r--chromium/cc/resources/video_resource_updater.cc26
-rw-r--r--chromium/cc/resources/video_resource_updater.h5
-rw-r--r--chromium/cc/scheduler/begin_frame_source.cc179
-rw-r--r--chromium/cc/scheduler/begin_frame_source.h70
-rw-r--r--chromium/cc/scheduler/begin_frame_source_unittest.cc294
-rw-r--r--chromium/cc/scheduler/begin_frame_tracker.cc9
-rw-r--r--chromium/cc/scheduler/scheduler.cc90
-rw-r--r--chromium/cc/scheduler/scheduler.h32
-rw-r--r--chromium/cc/scheduler/scheduler_state_machine.cc242
-rw-r--r--chromium/cc/scheduler/scheduler_state_machine.h123
-rw-r--r--chromium/cc/scheduler/scheduler_state_machine_unittest.cc84
-rw-r--r--chromium/cc/scheduler/scheduler_unittest.cc241
-rw-r--r--chromium/cc/surfaces/BUILD.gn14
-rw-r--r--chromium/cc/surfaces/compositor_frame_sink_support.cc229
-rw-r--r--chromium/cc/surfaces/compositor_frame_sink_support.h60
-rw-r--r--chromium/cc/surfaces/compositor_frame_sink_support_unittest.cc1848
-rw-r--r--chromium/cc/surfaces/direct_compositor_frame_sink.cc30
-rw-r--r--chromium/cc/surfaces/direct_compositor_frame_sink.h8
-rw-r--r--chromium/cc/surfaces/direct_compositor_frame_sink_unittest.cc17
-rw-r--r--chromium/cc/surfaces/display.cc37
-rw-r--r--chromium/cc/surfaces/display.h5
-rw-r--r--chromium/cc/surfaces/display_unittest.cc30
-rw-r--r--chromium/cc/surfaces/frame_sink_manager.cc (renamed from chromium/cc/surfaces/framesink_manager.cc)33
-rw-r--r--chromium/cc/surfaces/frame_sink_manager.h (renamed from chromium/cc/surfaces/framesink_manager.h)46
-rw-r--r--chromium/cc/surfaces/frame_sink_manager_client.h22
-rw-r--r--chromium/cc/surfaces/pending_frame_observer.h41
-rw-r--r--chromium/cc/surfaces/primary_begin_frame_source.cc87
-rw-r--r--chromium/cc/surfaces/primary_begin_frame_source.h56
-rw-r--r--chromium/cc/surfaces/referenced_surface_tracker.cc53
-rw-r--r--chromium/cc/surfaces/referenced_surface_tracker.h22
-rw-r--r--chromium/cc/surfaces/surface.cc259
-rw-r--r--chromium/cc/surfaces/surface.h95
-rw-r--r--chromium/cc/surfaces/surface_aggregator.cc113
-rw-r--r--chromium/cc/surfaces/surface_aggregator.h32
-rw-r--r--chromium/cc/surfaces/surface_aggregator_perftest.cc60
-rw-r--r--chromium/cc/surfaces/surface_aggregator_unittest.cc118
-rw-r--r--chromium/cc/surfaces/surface_dependency_deadline.cc55
-rw-r--r--chromium/cc/surfaces/surface_dependency_deadline.h44
-rw-r--r--chromium/cc/surfaces/surface_dependency_tracker.cc168
-rw-r--r--chromium/cc/surfaces/surface_dependency_tracker.h48
-rw-r--r--chromium/cc/surfaces/surface_factory.cc151
-rw-r--r--chromium/cc/surfaces/surface_factory.h112
-rw-r--r--chromium/cc/surfaces/surface_factory_client.h37
-rw-r--r--chromium/cc/surfaces/surface_factory_unittest.cc768
-rw-r--r--chromium/cc/surfaces/surface_hittest.cc3
-rw-r--r--chromium/cc/surfaces/surface_hittest_unittest.cc21
-rw-r--r--chromium/cc/surfaces/surface_manager.cc77
-rw-r--r--chromium/cc/surfaces/surface_manager.h64
-rw-r--r--chromium/cc/surfaces/surface_manager_ref_unittest.cc14
-rw-r--r--chromium/cc/surfaces/surface_manager_unittest.cc122
-rw-r--r--chromium/cc/surfaces/surface_observer.h3
-rw-r--r--chromium/cc/surfaces/surface_resource_holder.cc21
-rw-r--r--chromium/cc/surfaces/surface_resource_holder.h6
-rw-r--r--chromium/cc/surfaces/surface_resource_holder_client.h23
-rw-r--r--chromium/cc/surfaces/surface_synchronization_unittest.cc1394
-rw-r--r--chromium/cc/surfaces/surface_unittest.cc16
-rw-r--r--chromium/cc/surfaces/surfaces_pixeltest.cc26
-rw-r--r--chromium/cc/tiles/checker_image_tracker.cc190
-rw-r--r--chromium/cc/tiles/checker_image_tracker.h95
-rw-r--r--chromium/cc/tiles/checker_image_tracker_unittest.cc375
-rw-r--r--chromium/cc/tiles/gpu_image_decode_cache.cc52
-rw-r--r--chromium/cc/tiles/gpu_image_decode_cache.h7
-rw-r--r--chromium/cc/tiles/gpu_image_decode_cache_unittest.cc678
-rw-r--r--chromium/cc/tiles/image_controller.cc13
-rw-r--r--chromium/cc/tiles/image_controller.h12
-rw-r--r--chromium/cc/tiles/image_controller_unittest.cc5
-rw-r--r--chromium/cc/tiles/image_decode_cache.h6
-rw-r--r--chromium/cc/tiles/picture_layer_tiling.cc174
-rw-r--r--chromium/cc/tiles/picture_layer_tiling.h9
-rw-r--r--chromium/cc/tiles/picture_layer_tiling_set.h5
-rw-r--r--chromium/cc/tiles/picture_layer_tiling_unittest.cc28
-rw-r--r--chromium/cc/tiles/prioritized_tile.cc7
-rw-r--r--chromium/cc/tiles/prioritized_tile.h7
-rw-r--r--chromium/cc/tiles/software_image_decode_cache.cc63
-rw-r--r--chromium/cc/tiles/software_image_decode_cache.h18
-rw-r--r--chromium/cc/tiles/software_image_decode_cache_perftest.cc6
-rw-r--r--chromium/cc/tiles/software_image_decode_cache_unittest.cc572
-rw-r--r--chromium/cc/tiles/tile.h14
-rw-r--r--chromium/cc/tiles/tile_draw_info.cc2
-rw-r--r--chromium/cc/tiles/tile_draw_info.h15
-rw-r--r--chromium/cc/tiles/tile_manager.cc208
-rw-r--r--chromium/cc/tiles/tile_manager.h36
-rw-r--r--chromium/cc/tiles/tile_manager_unittest.cc269
-rw-r--r--chromium/cc/tiles/tiling_set_raster_queue_all.cc17
-rw-r--r--chromium/cc/tiles/tiling_set_raster_queue_all.h3
-rw-r--r--chromium/cc/trees/damage_tracker.cc197
-rw-r--r--chromium/cc/trees/damage_tracker.h31
-rw-r--r--chromium/cc/trees/damage_tracker_unittest.cc413
-rw-r--r--chromium/cc/trees/debug_rect_history.cc69
-rw-r--r--chromium/cc/trees/debug_rect_history.h9
-rw-r--r--chromium/cc/trees/draw_property_utils.cc87
-rw-r--r--chromium/cc/trees/draw_property_utils.h15
-rw-r--r--chromium/cc/trees/effect_node.cc16
-rw-r--r--chromium/cc/trees/effect_node.h45
-rw-r--r--chromium/cc/trees/element_id.cc19
-rw-r--r--chromium/cc/trees/element_id.h41
-rw-r--r--chromium/cc/trees/layer_tree_host.cc196
-rw-r--r--chromium/cc/trees/layer_tree_host.h53
-rw-r--r--chromium/cc/trees/layer_tree_host_client.h2
-rw-r--r--chromium/cc/trees/layer_tree_host_common.cc346
-rw-r--r--chromium/cc/trees/layer_tree_host_common.h20
-rw-r--r--chromium/cc/trees/layer_tree_host_common_perftest.cc18
-rw-r--r--chromium/cc/trees/layer_tree_host_common_unittest.cc2050
-rw-r--r--chromium/cc/trees/layer_tree_host_impl.cc475
-rw-r--r--chromium/cc/trees/layer_tree_host_impl.h58
-rw-r--r--chromium/cc/trees/layer_tree_host_impl_unittest.cc1003
-rw-r--r--chromium/cc/trees/layer_tree_host_perftest.cc63
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_blending.cc7
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_masks.cc125
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc14
-rw-r--r--chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc40
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest.cc698
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_animation.cc122
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_checkerimaging.cc1
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_context.cc6
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_damage.cc17
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_occlusion.cc27
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_picture.cc7
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_scroll.cc22
-rw-r--r--chromium/cc/trees/layer_tree_host_unittest_video.cc3
-rw-r--r--chromium/cc/trees/layer_tree_impl.cc466
-rw-r--r--chromium/cc/trees/layer_tree_impl.h131
-rw-r--r--chromium/cc/trees/layer_tree_impl_unittest.cc197
-rw-r--r--chromium/cc/trees/layer_tree_settings.h11
-rw-r--r--chromium/cc/trees/mutator_host.h3
-rw-r--r--chromium/cc/trees/occlusion_tracker.cc17
-rw-r--r--chromium/cc/trees/occlusion_tracker_unittest.cc14
-rw-r--r--chromium/cc/trees/property_tree.cc104
-rw-r--r--chromium/cc/trees/property_tree.h28
-rw-r--r--chromium/cc/trees/property_tree_builder.cc225
-rw-r--r--chromium/cc/trees/proxy_impl.cc49
-rw-r--r--chromium/cc/trees/proxy_impl.h10
-rw-r--r--chromium/cc/trees/proxy_main.cc15
-rw-r--r--chromium/cc/trees/proxy_main.h5
-rw-r--r--chromium/cc/trees/scroll_node.cc2
-rw-r--r--chromium/cc/trees/scroll_node.h21
-rw-r--r--chromium/cc/trees/single_thread_proxy.cc24
-rw-r--r--chromium/cc/trees/single_thread_proxy.h11
-rw-r--r--chromium/cc/trees/transform_node.h13
-rw-r--r--chromium/cc/trees/tree_synchronizer.cc28
-rw-r--r--chromium/cc/trees/tree_synchronizer_unittest.cc17
365 files changed, 17936 insertions, 11488 deletions
diff --git a/chromium/cc/BUILD.gn b/chromium/cc/BUILD.gn
index f791854447d..18e185613e9 100644
--- a/chromium/cc/BUILD.gn
+++ b/chromium/cc/BUILD.gn
@@ -48,6 +48,7 @@ cc_component("cc") {
"input/selection.h",
"input/single_scrollbar_animation_controller_thinning.cc",
"input/single_scrollbar_animation_controller_thinning.h",
+ "input/touch_action.h",
"layers/append_quads_data.cc",
"layers/append_quads_data.h",
"layers/content_layer_client.h",
@@ -79,7 +80,6 @@ cc_component("cc") {
"layers/nine_patch_layer.h",
"layers/nine_patch_layer_impl.cc",
"layers/nine_patch_layer_impl.h",
- "layers/paint_properties.h",
"layers/painted_overlay_scrollbar_layer.cc",
"layers/painted_overlay_scrollbar_layer.h",
"layers/painted_overlay_scrollbar_layer_impl.cc",
@@ -519,6 +519,8 @@ cc_static_library("test_support") {
"test/begin_frame_args_test.h",
"test/begin_frame_source_test.cc",
"test/begin_frame_source_test.h",
+ "test/compositor_frame_helpers.cc",
+ "test/compositor_frame_helpers.h",
"test/fake_compositor_frame_sink.cc",
"test/fake_compositor_frame_sink.h",
"test/fake_compositor_frame_sink_client.cc",
@@ -566,6 +568,8 @@ cc_static_library("test_support") {
"test/fake_scoped_ui_resource.h",
"test/fake_scrollbar.cc",
"test/fake_scrollbar.h",
+ "test/fake_surface_resource_holder_client.cc",
+ "test/fake_surface_resource_holder_client.h",
"test/fake_tile_manager.cc",
"test/fake_tile_manager.h",
"test/fake_tile_manager_client.cc",
@@ -588,6 +592,8 @@ cc_static_library("test_support") {
"test/layer_tree_pixel_test.h",
"test/layer_tree_test.cc",
"test/layer_tree_test.h",
+ "test/mock_compositor_frame_sink_support_client.cc",
+ "test/mock_compositor_frame_sink_support_client.h",
"test/mock_helper.h",
"test/mock_occlusion_tracker.h",
"test/ordered_simple_task_runner.cc",
@@ -620,6 +626,7 @@ cc_static_library("test_support") {
"test/stub_layer_tree_host_client.h",
"test/stub_layer_tree_host_single_thread_client.cc",
"test/stub_layer_tree_host_single_thread_client.h",
+ "test/stub_surface_factory_client.h",
"test/surface_aggregator_test_helpers.cc",
"test/surface_aggregator_test_helpers.h",
"test/surface_hittest_test_helpers.cc",
@@ -647,6 +654,8 @@ cc_static_library("test_support") {
"test/test_occlusion_tracker.h",
"test/test_shared_bitmap_manager.cc",
"test/test_shared_bitmap_manager.h",
+ "test/test_skcanvas.cc",
+ "test/test_skcanvas.h",
"test/test_task_graph_runner.cc",
"test/test_task_graph_runner.h",
"test/test_texture.cc",
@@ -704,7 +713,6 @@ cc_test("cc_unittests") {
"base/index_rect_unittest.cc",
"base/list_container_unittest.cc",
"base/math_util_unittest.cc",
- "base/random_access_list_container_unittest.cc",
"base/region_unittest.cc",
"base/rolling_time_delta_history_unittest.cc",
"base/rtree_unittest.cc",
@@ -764,6 +772,7 @@ cc_test("cc_unittests") {
"output/texture_mailbox_deleter_unittest.cc",
"paint/discardable_image_map_unittest.cc",
"paint/display_item_list_unittest.cc",
+ "paint/paint_op_buffer_unittest.cc",
"quads/draw_polygon_unittest.cc",
"quads/draw_quad_unittest.cc",
"quads/nine_patch_generator_unittest.cc",
@@ -849,11 +858,11 @@ cc_test("cc_unittests") {
"surfaces/display_unittest.cc",
"surfaces/referenced_surface_tracker_unittest.cc",
"surfaces/surface_aggregator_unittest.cc",
- "surfaces/surface_factory_unittest.cc",
"surfaces/surface_hittest_unittest.cc",
"surfaces/surface_manager_ref_unittest.cc",
"surfaces/surface_manager_unittest.cc",
"surfaces/surface_sequence_generator_unittest.cc",
+ "surfaces/surface_synchronization_unittest.cc",
"surfaces/surface_unittest.cc",
"surfaces/surfaces_pixeltest.cc",
diff --git a/chromium/cc/OWNERS b/chromium/cc/OWNERS
index 5a30b1399e8..23652bf0d5d 100644
--- a/chromium/cc/OWNERS
+++ b/chromium/cc/OWNERS
@@ -52,6 +52,9 @@ weiliangc@chromium.org
vollick@chromium.org
ajuma@chromium.org
+# property trees
+chrishtr@chromium.org
+
# we miss you
# jamesr@chromium.org
# nduca@chromium.org
diff --git a/chromium/cc/README.md b/chromium/cc/README.md
new file mode 100644
index 00000000000..8180794bfcb
--- /dev/null
+++ b/chromium/cc/README.md
@@ -0,0 +1,199 @@
+# cc/
+
+This directory contains a compositor, used in both the renderer and the
+browser. In the renderer, Blink is the client. In the browser, both
+ui and Android browser compositor are the clients.
+
+The public API of the compositor is LayerTreeHost and Layer and its
+derived types. Embedders create a LayerTreeHost (single, multithreaded,
+or synchronous) and then attach a tree of Layers to it.
+
+When Layers are updated they request a commit, which takes the data
+of and structure of the tree of Layers and the data of its host and
+atomically pushes it to a tree of LayerImpls and a LayerTreeHostImpl
+and LayerTreeImpl. The main thread (which owns the tree of Layers
+and the embedder) is blocked during this commit operation.
+
+The commit is from the main thread Layer tree to the pending tree in
+multithreaded mode. The pending tree is a staging tree for
+rasterization. When enough rasterization has completed for
+invalidations and the pending tree is ready to activate. Activate is an
+analogous operation to commit, and pushes data from the pending tree to
+the active tree. The pending tree exists so that all the of the updates
+from the main thread can be displayed to the user atomically while
+the previous frame can be scrolled or animated.
+
+The single threaded compositor commits directly to the active
+tree and then stops drawing until the content is ready to be drawn.
+
+The active tree is responsible for drawing. The Scheduler and its
+SchedulerStateMachine decide when to draw (along with when to commit,
+etc etc). "Drawing" in a compositor consists of LayerImpl::AppendQuads
+which batches up a set of DrawQuads and RenderPasses into a
+CompositorFrame which is sent via a CompositorFrameSink.
+
+CompositorFrames from individual compositors are sent to the
+SurfaceManager (currently in the browser process). The
+SurfaceAggregator combines all CompositorFrames together and asks
+the Display to finally draw the frame via Renderer, which is either
+a GLRenderer or a SoftwareRenderer, which finally draws the entire
+composited browser contents into a backbuffer or a bitmap, respectively.
+
+Design documents for the graphics stack can be found at
+[chromium-graphics](https://www.chromium.org/developers/design-documents/chromium-graphics).
+
+## Glossaries
+
+### Active CompositorFrame
+
+### Active Tree
+The set of layers and property trees that was/will be used to submit a
+CompositorFrame from the layer compositor. Composited effects such as scrolling,
+pinch, and animations are done by modifying the active tree, which allows for
+producing and submitting a new CompositorFrame.
+
+### CompositorFrame
+A set of RenderPasses (which are a list of DrawQuads) along with metadata.
+Conceptually this is the instructions (transforms, texture ids, etc) for how to
+draw an entire scene which will be presented in a surface.
+
+### CopyOutputRequest (or Copy Request)
+A request for a texture (or bitmap) copy of some part of the compositor's
+output. Such requests force the compositor to use a separate RenderPass for the
+content to be copied, which allows it to do the copy operation once the
+RenderPass has been drawn to.
+
+### ElementID
+Chosen by cc's clients and can be used as a stable identifier across updates.
+For example, blink uses ElementIDs as a stable id for the object (opaque to cc)
+that is responsible for a composited animation. Some additional information in
+[element_id.h](https://codesearch.chromium.org/chromium/src/cc/trees/element_id.h)
+
+### DirectRenderer
+An abstraction that provides an API for the Display to draw a fully-aggregated
+CompositorFrame to a physical output. Subclasses of it provide implementations
+for various backends, currently GL or Software.
+
+### Layer
+A conceptual piece of content that can appear on screen and has some known
+position with respect to the viewport. The Layer class only is used on the
+main thread. This, along with LayerTreeHost, is the main API for the
+compositor.
+
+### LayerImpl
+The same as Layer, but on the compositor thread.
+
+### LayerTree
+
+### Occlusion Culling
+Avoiding work by skipping over things which are not visible due to being
+occluded (hidden from sight by other opaque things in front of them). Most
+commonly refers to skipping drawing (ie culling) of DrawQuads when other
+DrawQuads will be in front and occluding them.
+
+### Property Trees
+
+See also presentations on [Compositor Property Trees](https://docs.google.com/presentation/d/1V7gCqKR-edNdRDv0bDnJa_uEs6iARAU2h5WhgxHyejQ/preview)
+and [Blink Property Trees](https://docs.google.com/presentation/u/1/d/1ak7YVrJITGXxqQ7tyRbwOuXB1dsLJlfpgC4wP7lykeo/preview).
+
+### Display
+A controller class that takes CompositorFrames for each surface and draws them
+to a physical output.
+
+### Draw
+Filling pixels in a physical output (technically could be to an offscreen
+texture), but this is the final output of the display compositor.
+
+### DrawQuad
+A unit of work for drawing. Each DrawQuad has its own texture id, transform,
+offset, etc.
+
+### Shared Quad State
+A shared set of states used by multiple draw quads. DrawQuads that are linked to
+the same shared quad state will all use the same properties from it, with the
+addition of things found on their individual DrawQuad structures.
+
+### Render Pass
+A list of DrawQuads which will all be drawn together into the same render target
+(either a texture or physical output). Most times all DrawQuads are part of a
+single RenderPass. Additional RenderPasses are used for effects that require a
+set of DrawQuads to be drawn together into a buffer first, with the effect
+applied then to the buffer instead of each individual DrawQuad.
+
+### Render Surface
+Synonym for RenderPass now. Historically part of the Layer tree data structures,
+with a 1:1 mapping to RenderPasses. RenderSurfaceImpl is a legacy piece that
+remains.
+
+### Surface
+
+### Record
+
+### Raster
+
+### Paint
+
+### Pending CompositorFrame
+
+### Pending Tree
+The set of layers and property trees that is generated from a main frame (or
+BeginMainFrame, or commit). The pending tree exists to do raster work in the
+layer compositor without clobbering the active tree until it is done. This
+allows the active tree to be used in the meantime.
+
+### Composite
+To produce a single graphical output from multiple inputs. In practice, the
+layer compositor does raster from recordings and manages memory, performs
+composited effects such as scrolling, pinch, animations, producing a
+CompositorFrame. The display compositor does an actual "composite" to draw the
+final output into a single physical output.
+
+### Invalidation
+Invalidation is a unit of content update. Any content updates from
+Blink or ui must be accompanied by an invalidation to tell the compositor
+that a piece of content must be rerasterized. For example, if a 10x10
+div with a background color has its width increased by 5 pixels, then
+there will be a 5x10 invalidation (at least) for the new space covered
+by the larger div.
+
+Ideally, invalidations represent the minimum amount of content that must
+be rerastered from the previous frame. They are passed to the compositor
+via Layer::SetNeedsDisplay(Rect). Invalidation is tracked both to
+minimize the amount of raster work needed, but also to allow for
+partial raster of Tiles. Invalidations also eventually become damage.
+
+### Damage
+Damage is the equivalent of invalidation, but for the final display.
+As invalidation is the difference between two frames worth of content,
+damage is the difference between two CompositorFrames. Damage is
+tracked via the DamageTracker. This allows for partial swap, where
+only the parts of the final CompositorFrame that touch the screen
+are drawn, and only that drawn portion is swapped, which saves quite
+a bit of power for small bits of damage.
+
+Invalidation creates damage, in that if a piece of content updates, then
+that content invalidation creates damage on screen. Other things that
+cause damage are analogous operations to invalidations, but on Layers.
+For example, moving a Layer around, changing properties of Layers (e.g.
+opacity), and adding/removing/reordering Layers will all create damage
+(aka screen updates) but do not create invalidations (aka raster work).
+
+### Tiles
+An abstraction of a piece of content of a Layer. A tile may be
+rasterized or not. It may be known to be a solid color or not.
+A PictureLayerImpl indirectly owns a sparse set of Tiles to
+represent its rasterizable content. When tiles are invalidated,
+they are replaced with new tiles.
+
+### Prepare Tiles
+Prioritize and schedule needed tiles for raster. This is the entry point to a
+system that converts painting (raster sources / recording sources) into
+rasterized resources that live on tiles. This also kicks off any dependent image
+decodes for images that need to be decode for the raster to take place.
+
+### Device Scale Factor
+The scale at which we want to display content on the output device. For very
+high resolution monitors, everything would become too small if just presented
+1:1 with the pixels. So we use a larger number of physical pixels per logical
+pixels. This ratio is the device scale factor. 1 or 2 is the most common on
+ChromeOS. Values between 1 and 2 are common on Windows.
diff --git a/chromium/cc/animation/animation_host.cc b/chromium/cc/animation/animation_host.cc
index 80dfae1670c..d56e7585711 100644
--- a/chromium/cc/animation/animation_host.cc
+++ b/chromium/cc/animation/animation_host.cc
@@ -528,10 +528,12 @@ void AnimationHost::ImplOnlyScrollAnimationCreate(
ElementId element_id,
const gfx::ScrollOffset& target_offset,
const gfx::ScrollOffset& current_offset,
- base::TimeDelta delayed_by) {
+ base::TimeDelta delayed_by,
+ base::TimeDelta animation_start_offset) {
DCHECK(scroll_offset_animations_impl_);
scroll_offset_animations_impl_->ScrollAnimationCreate(
- element_id, target_offset, current_offset, delayed_by);
+ element_id, target_offset, current_offset, delayed_by,
+ animation_start_offset);
}
bool AnimationHost::ImplOnlyScrollAnimationUpdateTarget(
diff --git a/chromium/cc/animation/animation_host.h b/chromium/cc/animation/animation_host.h
index 5e4f8e077cb..31e45e69332 100644
--- a/chromium/cc/animation/animation_host.h
+++ b/chromium/cc/animation/animation_host.h
@@ -155,10 +155,12 @@ class CC_ANIMATION_EXPORT AnimationHost
bool HasAnyAnimation(ElementId element_id) const override;
bool HasTickingAnimationForTesting(ElementId element_id) const override;
- void ImplOnlyScrollAnimationCreate(ElementId element_id,
- const gfx::ScrollOffset& target_offset,
- const gfx::ScrollOffset& current_offset,
- base::TimeDelta delayed_by) override;
+ void ImplOnlyScrollAnimationCreate(
+ ElementId element_id,
+ const gfx::ScrollOffset& target_offset,
+ const gfx::ScrollOffset& current_offset,
+ base::TimeDelta delayed_by,
+ base::TimeDelta animation_start_offset) override;
bool ImplOnlyScrollAnimationUpdateTarget(
ElementId element_id,
const gfx::Vector2dF& scroll_delta,
diff --git a/chromium/cc/animation/animation_host_unittest.cc b/chromium/cc/animation/animation_host_unittest.cc
index 4ae691a64e2..fdaefc7ba09 100644
--- a/chromium/cc/animation/animation_host_unittest.cc
+++ b/chromium/cc/animation/animation_host_unittest.cc
@@ -87,7 +87,8 @@ TEST_F(AnimationHostTest, ImplOnlyScrollAnimationUpdateTargetIfDetached) {
gfx::ScrollOffset target_offset(0., 2.);
gfx::ScrollOffset current_offset(0., 1.);
host_impl_->ImplOnlyScrollAnimationCreate(element_id_, target_offset,
- current_offset, base::TimeDelta());
+ current_offset, base::TimeDelta(),
+ base::TimeDelta());
gfx::Vector2dF scroll_delta(0, 0.5);
gfx::ScrollOffset max_scroll_offset(0., 3.);
diff --git a/chromium/cc/animation/animation_player.cc b/chromium/cc/animation/animation_player.cc
index 634d64948ae..3174dcbdab0 100644
--- a/chromium/cc/animation/animation_player.cc
+++ b/chromium/cc/animation/animation_player.cc
@@ -374,6 +374,10 @@ bool AnimationPlayer::NotifyAnimationFinished(const AnimationEvent& event) {
}
}
+ // This is for the case when an animation is already removed on main thread,
+ // but the impl version of it sent a finished event and is now waiting for
+ // deletion. We would need to delete that animation during push properties.
+ SetNeedsPushProperties();
return false;
}
@@ -795,6 +799,21 @@ void AnimationPlayer::MarkFinishedAnimations(base::TimeTicks monotonic_time) {
animations_[i]->IsFinishedAt(monotonic_time)) {
animations_[i]->SetRunState(Animation::FINISHED, monotonic_time);
animation_finished = true;
+ SetNeedsPushProperties();
+ }
+ if (!animations_[i]->affects_active_elements() &&
+ !animations_[i]->affects_pending_elements()) {
+ switch (animations_[i]->run_state()) {
+ case Animation::WAITING_FOR_TARGET_AVAILABILITY:
+ case Animation::STARTING:
+ case Animation::RUNNING:
+ case Animation::PAUSED:
+ animations_[i]->SetRunState(Animation::FINISHED, monotonic_time);
+ animation_finished = true;
+ break;
+ default:
+ break;
+ }
}
}
@@ -814,11 +833,6 @@ void AnimationPlayer::ActivateAnimations() {
animations_[i]->set_affects_active_elements(
animations_[i]->affects_pending_elements());
}
- auto affects_no_elements = [](const std::unique_ptr<Animation>& animation) {
- return !animation->affects_active_elements() &&
- !animation->affects_pending_elements();
- };
- base::EraseIf(animations_, affects_no_elements);
if (animation_activated)
element_animations_->UpdateClientAnimationState();
@@ -1151,7 +1165,9 @@ static bool IsCompleted(Animation* animation,
if (animation->is_impl_only()) {
return (animation->run_state() == Animation::WAITING_FOR_DELETION);
} else {
- return !main_thread_player->GetAnimationById(animation->id());
+ Animation* main_thread_animation =
+ main_thread_player->GetAnimationById(animation->id());
+ return !main_thread_animation || main_thread_animation->is_finished();
}
}
diff --git a/chromium/cc/animation/animation_player_unittest.cc b/chromium/cc/animation/animation_player_unittest.cc
index 4f234a0f157..7b4b82d850f 100644
--- a/chromium/cc/animation/animation_player_unittest.cc
+++ b/chromium/cc/animation/animation_player_unittest.cc
@@ -172,7 +172,7 @@ TEST_F(AnimationPlayerTest, PropertiesMutate) {
time += base::TimeDelta::FromSecondsD(duration);
TickAnimationsTransferEvents(time, 3u);
- EXPECT_TRUE(CheckPlayerTimelineNeedsPushProperties(false));
+ EXPECT_TRUE(CheckPlayerTimelineNeedsPushProperties(true));
client_.ExpectOpacityPropertyMutated(element_id_, ElementListType::ACTIVE,
end_opacity);
@@ -265,8 +265,8 @@ TEST_F(AnimationPlayerTest, AttachTwoPlayersToOneLayer) {
EXPECT_TRUE(delegate1.finished());
EXPECT_TRUE(delegate2.finished());
- EXPECT_FALSE(player1->needs_push_properties());
- EXPECT_FALSE(player2->needs_push_properties());
+ EXPECT_TRUE(player1->needs_push_properties());
+ EXPECT_TRUE(player2->needs_push_properties());
client_.ExpectOpacityPropertyMutated(element_id_, ElementListType::ACTIVE,
end_opacity);
@@ -394,7 +394,7 @@ TEST_F(AnimationPlayerTest, SwitchToLayer) {
EXPECT_EQ(player_impl_->element_id(), element_id_);
EXPECT_TRUE(CheckPlayerTimelineNeedsPushProperties(false));
- const ElementId new_element_id(NextTestLayerId(), 0);
+ const ElementId new_element_id(NextTestLayerId());
player_->DetachElement();
player_->AttachElement(new_element_id);
diff --git a/chromium/cc/animation/element_animations_unittest.cc b/chromium/cc/animation/element_animations_unittest.cc
index 75e69c9b25a..8974943990b 100644
--- a/chromium/cc/animation/element_animations_unittest.cc
+++ b/chromium/cc/animation/element_animations_unittest.cc
@@ -2696,10 +2696,11 @@ TEST_F(ElementAnimationsTest, ObserverNotifiedWhenTransformAnimationChanges) {
PushProperties();
- // animations_impl hasn't yet ticked at/past the end of the animation.
- EXPECT_TRUE(client_impl_.GetHasPotentialTransformAnimation(
+ // Finished animations are pushed, but animations_impl hasn't yet ticked
+ // at/past the end of the animation.
+ EXPECT_FALSE(client_impl_.GetHasPotentialTransformAnimation(
element_id_, ElementListType::PENDING));
- EXPECT_TRUE(client_impl_.GetTransformIsCurrentlyAnimating(
+ EXPECT_FALSE(client_impl_.GetTransformIsCurrentlyAnimating(
element_id_, ElementListType::PENDING));
EXPECT_TRUE(client_impl_.GetHasPotentialTransformAnimation(
element_id_, ElementListType::ACTIVE));
@@ -2913,10 +2914,11 @@ TEST_F(ElementAnimationsTest, ObserverNotifiedWhenOpacityAnimationChanges) {
PushProperties();
- // animations_impl hasn't yet ticked at/past the end of the animation.
- EXPECT_TRUE(client_impl_.GetHasPotentialOpacityAnimation(
+ // Finished animations are pushed, but animations_impl hasn't yet ticked
+ // at/past the end of the animation.
+ EXPECT_FALSE(client_impl_.GetHasPotentialOpacityAnimation(
element_id_, ElementListType::PENDING));
- EXPECT_TRUE(client_impl_.GetOpacityIsCurrentlyAnimating(
+ EXPECT_FALSE(client_impl_.GetOpacityIsCurrentlyAnimating(
element_id_, ElementListType::PENDING));
EXPECT_TRUE(client_impl_.GetHasPotentialOpacityAnimation(
element_id_, ElementListType::ACTIVE));
@@ -3123,10 +3125,11 @@ TEST_F(ElementAnimationsTest, ObserverNotifiedWhenFilterAnimationChanges) {
PushProperties();
- // animations_impl hasn't yet ticked at/past the end of the animation.
- EXPECT_TRUE(client_impl_.GetHasPotentialFilterAnimation(
+ // Finished animations are pushed, but animations_impl hasn't yet ticked
+ // at/past the end of the animation.
+ EXPECT_FALSE(client_impl_.GetHasPotentialFilterAnimation(
element_id_, ElementListType::PENDING));
- EXPECT_TRUE(client_impl_.GetFilterIsCurrentlyAnimating(
+ EXPECT_FALSE(client_impl_.GetFilterIsCurrentlyAnimating(
element_id_, ElementListType::PENDING));
EXPECT_TRUE(client_impl_.GetHasPotentialFilterAnimation(
element_id_, ElementListType::ACTIVE));
@@ -3304,7 +3307,6 @@ TEST_F(ElementAnimationsTest, PushedDeletedAnimationWaitsForActivation) {
const int animation_id =
AddOpacityTransitionToPlayer(player_.get(), 1, 0.5f, 1.f, true);
-
PushProperties();
player_impl_->ActivateAnimations();
player_impl_->Tick(kInitialTickTime);
@@ -3342,8 +3344,20 @@ TEST_F(ElementAnimationsTest, PushedDeletedAnimationWaitsForActivation) {
client_impl_.GetOpacity(element_id_, ElementListType::ACTIVE));
player_impl_->ActivateAnimations();
+ events = CreateEventsForTesting();
+ player_impl_->UpdateState(true, events.get());
- // Activation should cause the animation to be deleted.
+ // After Activation the animation doesn't affect neither active nor pending
+ // thread. UpdateState for this animation would put the animation to wait for
+ // deletion state.
+ EXPECT_EQ(Animation::WAITING_FOR_DELETION,
+ player_impl_->GetAnimationById(animation_id)->run_state());
+ EXPECT_EQ(1u, events->events_.size());
+
+ // The animation is finished on impl thread, and main thread will delete it
+ // during commit.
+ player_->animation_host()->SetAnimationEvents(std::move(events));
+ PushProperties();
EXPECT_FALSE(player_impl_->has_any_animation());
}
@@ -3402,9 +3416,12 @@ TEST_F(ElementAnimationsTest, StartAnimationsAffectingDifferentObservers) {
player_impl_->ActivateAnimations();
- // The original animation should have been deleted, and the new animation
- // should now affect both elements.
- EXPECT_FALSE(player_impl_->GetAnimationById(first_animation_id));
+ // The original animation no longer affect either elements, and the new
+ // animation should now affect both elements.
+ EXPECT_FALSE(player_impl_->GetAnimationById(first_animation_id)
+ ->affects_pending_elements());
+ EXPECT_FALSE(player_impl_->GetAnimationById(first_animation_id)
+ ->affects_active_elements());
EXPECT_TRUE(player_impl_->GetAnimationById(second_animation_id)
->affects_pending_elements());
EXPECT_TRUE(player_impl_->GetAnimationById(second_animation_id)
@@ -3413,6 +3430,10 @@ TEST_F(ElementAnimationsTest, StartAnimationsAffectingDifferentObservers) {
player_impl_->Tick(kInitialTickTime + TimeDelta::FromMilliseconds(1000));
player_impl_->UpdateState(true, events.get());
+ // The original animation should be marked for waiting for deletion.
+ EXPECT_EQ(Animation::WAITING_FOR_DELETION,
+ player_impl_->GetAnimationById(first_animation_id)->run_state());
+
// The new animation should be running, and the active observer should have
// been ticked at the new animation's starting point.
EXPECT_EQ(Animation::RUNNING,
diff --git a/chromium/cc/animation/keyframed_animation_curve_unittest.cc b/chromium/cc/animation/keyframed_animation_curve_unittest.cc
index a7b0e345b99..c050404d714 100644
--- a/chromium/cc/animation/keyframed_animation_curve_unittest.cc
+++ b/chromium/cc/animation/keyframed_animation_curve_unittest.cc
@@ -535,6 +535,30 @@ TEST(KeyframedAnimationCurveTest, StepsTimingFunctionStepAtEnd) {
}
}
+// Tests a frames timing function.
+TEST(KeyframedAnimationCurveTest, FramesTimingFunction) {
+ std::unique_ptr<KeyframedFloatAnimationCurve> curve(
+ KeyframedFloatAnimationCurve::Create());
+ curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 0.f,
+ FramesTimingFunction::Create(5)));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 1.f, nullptr));
+
+ struct Expected {
+ double time;
+ float value;
+ } expectations[] = {
+ {0.0, 0.f}, {0.1999, 0.f}, {0.2001, 0.25f}, {0.3999, 0.25f},
+ {0.4001, 0.5f}, {0.5999, 0.5f}, {0.6001, 0.75f}, {0.7999, 0.75f},
+ {0.8001, 1.f}, {1.0, 1.f},
+ };
+ for (const auto& expectation : expectations) {
+ EXPECT_FLOAT_EQ(
+ expectation.value,
+ curve->GetValue(base::TimeDelta::FromSecondsD(expectation.time)));
+ }
+}
+
// Tests that animated bounds are computed as expected.
TEST(KeyframedAnimationCurveTest, AnimatedBounds) {
std::unique_ptr<KeyframedTransformAnimationCurve> curve(
@@ -818,13 +842,13 @@ TEST(KeyframedAnimationCurveTest, CurveTimingInputsOutsideZeroOneRange) {
// Tests that a step timing function works as expected for inputs outside of
// range [0,1]
-TEST(KeyframedAnimationCurveTest, StepsTimingInputsOutsideZeroOneRange) {
+TEST(KeyframedAnimationCurveTest, StepsTimingStartInputsOutsideZeroOneRange) {
std::unique_ptr<KeyframedFloatAnimationCurve> curve(
KeyframedFloatAnimationCurve::Create());
curve->AddKeyframe(
FloatKeyframe::Create(base::TimeDelta(), 0.f,
StepsTimingFunction::Create(
- 4, StepsTimingFunction::StepPosition::MIDDLE)));
+ 4, StepsTimingFunction::StepPosition::START)));
curve->AddKeyframe(
FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 2.f, nullptr));
// Curve timing function producing timing outputs outside of range [0,1].
@@ -832,9 +856,42 @@ TEST(KeyframedAnimationCurveTest, StepsTimingInputsOutsideZeroOneRange) {
CubicBezierTimingFunction::Create(0.5f, -0.5f, 0.5f, 1.5f));
EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.25f)));
+ EXPECT_FLOAT_EQ(2.5f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f)));
+}
+
+TEST(KeyframedAnimationCurveTest, StepsTimingEndInputsOutsideZeroOneRange) {
+ std::unique_ptr<KeyframedFloatAnimationCurve> curve(
+ KeyframedFloatAnimationCurve::Create());
+ curve->AddKeyframe(FloatKeyframe::Create(
+ base::TimeDelta(), 0.f,
+ StepsTimingFunction::Create(4, StepsTimingFunction::StepPosition::END)));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 2.f, nullptr));
+ // Curve timing function producing timing outputs outside of range [0,1].
+ curve->SetTimingFunction(
+ CubicBezierTimingFunction::Create(0.5f, -0.5f, 0.5f, 1.5f));
+
+ EXPECT_FLOAT_EQ(-0.5f, curve->GetValue(base::TimeDelta::FromSecondsD(0.25f)));
EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f)));
}
+// Tests that a frames timing function works as expected for inputs outside of
+// range [0,1]
+TEST(KeyframedAnimationCurveTest, FramesTimingInputsOutsideZeroOneRange) {
+ std::unique_ptr<KeyframedFloatAnimationCurve> curve(
+ KeyframedFloatAnimationCurve::Create());
+ curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 0.f,
+ FramesTimingFunction::Create(5)));
+ curve->AddKeyframe(
+ FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 2.f, nullptr));
+ // Curve timing function producing timing outputs outside of range [0,1].
+ curve->SetTimingFunction(
+ CubicBezierTimingFunction::Create(0.5f, -0.5f, 0.5f, 1.5f));
+
+ EXPECT_FLOAT_EQ(-0.5f, curve->GetValue(base::TimeDelta::FromSecondsD(0.25f)));
+ EXPECT_FLOAT_EQ(2.5f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f)));
+}
+
// Tests that an animation with a curve timing function and multiple keyframes
// works as expected.
TEST(KeyframedAnimationCurveTest, CurveTimingMultipleKeyframes) {
diff --git a/chromium/cc/animation/scroll_offset_animations_impl.cc b/chromium/cc/animation/scroll_offset_animations_impl.cc
index 71a96b429f5..512133cde53 100644
--- a/chromium/cc/animation/scroll_offset_animations_impl.cc
+++ b/chromium/cc/animation/scroll_offset_animations_impl.cc
@@ -36,7 +36,8 @@ void ScrollOffsetAnimationsImpl::ScrollAnimationCreate(
ElementId element_id,
const gfx::ScrollOffset& target_offset,
const gfx::ScrollOffset& current_offset,
- base::TimeDelta delayed_by) {
+ base::TimeDelta delayed_by,
+ base::TimeDelta animation_start_offset) {
std::unique_ptr<ScrollOffsetAnimationCurve> curve =
ScrollOffsetAnimationCurve::Create(
target_offset, CubicBezierTimingFunction::CreatePreset(
@@ -47,6 +48,7 @@ void ScrollOffsetAnimationsImpl::ScrollAnimationCreate(
std::unique_ptr<Animation> animation = Animation::Create(
std::move(curve), AnimationIdProvider::NextAnimationId(),
AnimationIdProvider::NextGroupId(), TargetProperty::SCROLL_OFFSET);
+ animation->set_time_offset(animation_start_offset);
animation->set_is_impl_only(true);
DCHECK(scroll_offset_animation_player_);
diff --git a/chromium/cc/animation/scroll_offset_animations_impl.h b/chromium/cc/animation/scroll_offset_animations_impl.h
index e6d402f925c..876e3b07bfe 100644
--- a/chromium/cc/animation/scroll_offset_animations_impl.h
+++ b/chromium/cc/animation/scroll_offset_animations_impl.h
@@ -31,10 +31,14 @@ class CC_ANIMATION_EXPORT ScrollOffsetAnimationsImpl
~ScrollOffsetAnimationsImpl() override;
+ // |delayed_by| shrinks the duration of the
+ // animation. |animation_start_offset| causes us to start the animation
+ // partway through.
void ScrollAnimationCreate(ElementId element_id,
const gfx::ScrollOffset& target_offset,
const gfx::ScrollOffset& current_offset,
- base::TimeDelta delayed_by);
+ base::TimeDelta delayed_by,
+ base::TimeDelta animation_start_offset);
bool ScrollAnimationUpdateTarget(ElementId element_id,
const gfx::Vector2dF& scroll_delta,
diff --git a/chromium/cc/animation/timing_function.cc b/chromium/cc/animation/timing_function.cc
index b7308bb31c9..0271c57bb44 100644
--- a/chromium/cc/animation/timing_function.cc
+++ b/chromium/cc/animation/timing_function.cc
@@ -109,8 +109,12 @@ float StepsTimingFunction::Velocity(double x) const {
double StepsTimingFunction::GetPreciseValue(double t) const {
const double steps = static_cast<double>(steps_);
- return MathUtil::ClampToRange(
- std::floor((steps * t) + GetStepsStartOffset()) / steps, 0.0, 1.0);
+ double current_step = std::floor((steps * t) + GetStepsStartOffset());
+ if (t >= 0 && current_step < 0)
+ current_step = 0;
+ if (t <= 1 && current_step > steps)
+ current_step = steps;
+ return current_step / steps;
}
float StepsTimingFunction::GetStepsStartOffset() const {
@@ -127,4 +131,41 @@ float StepsTimingFunction::GetStepsStartOffset() const {
}
}
+std::unique_ptr<FramesTimingFunction> FramesTimingFunction::Create(int frames) {
+ return base::WrapUnique(new FramesTimingFunction(frames));
+}
+
+FramesTimingFunction::FramesTimingFunction(int frames) : frames_(frames) {}
+
+FramesTimingFunction::~FramesTimingFunction() {}
+
+TimingFunction::Type FramesTimingFunction::GetType() const {
+ return Type::FRAMES;
+}
+
+float FramesTimingFunction::GetValue(double t) const {
+ return static_cast<float>(GetPreciseValue(t));
+}
+
+std::unique_ptr<TimingFunction> FramesTimingFunction::Clone() const {
+ return base::WrapUnique(new FramesTimingFunction(*this));
+}
+
+void FramesTimingFunction::Range(float* min, float* max) const {
+ *min = 0.0f;
+ *max = 1.0f;
+}
+
+float FramesTimingFunction::Velocity(double x) const {
+ return 0.0f;
+}
+
+double FramesTimingFunction::GetPreciseValue(double t) const {
+ const double frames = static_cast<double>(frames_);
+ double output_progress = std::floor(frames * t) / (frames - 1);
+ if (t <= 1 && output_progress > 1)
+ output_progress = 1;
+ return output_progress;
+}
+
} // namespace cc
diff --git a/chromium/cc/animation/timing_function.h b/chromium/cc/animation/timing_function.h
index 0f475e7624a..5ff8d3561bd 100644
--- a/chromium/cc/animation/timing_function.h
+++ b/chromium/cc/animation/timing_function.h
@@ -19,7 +19,7 @@ class CC_ANIMATION_EXPORT TimingFunction {
virtual ~TimingFunction();
// Note that LINEAR is a nullptr TimingFunction (for now).
- enum class Type { LINEAR, CUBIC_BEZIER, STEPS };
+ enum class Type { LINEAR, CUBIC_BEZIER, STEPS, FRAMES };
virtual Type GetType() const = 0;
virtual float GetValue(double t) const = 0;
@@ -101,6 +101,29 @@ class CC_ANIMATION_EXPORT StepsTimingFunction : public TimingFunction {
DISALLOW_ASSIGN(StepsTimingFunction);
};
+class CC_ANIMATION_EXPORT FramesTimingFunction : public TimingFunction {
+ public:
+ static std::unique_ptr<FramesTimingFunction> Create(int frames);
+ ~FramesTimingFunction() override;
+
+ // TimingFunction implementation.
+ Type GetType() const override;
+ float GetValue(double t) const override;
+ std::unique_ptr<TimingFunction> Clone() const override;
+ void Range(float* min, float* max) const override;
+ float Velocity(double time) const override;
+
+ int frames() const { return frames_; }
+ double GetPreciseValue(double t) const;
+
+ private:
+ explicit FramesTimingFunction(int frames);
+
+ int frames_;
+
+ DISALLOW_ASSIGN(FramesTimingFunction);
+};
+
} // namespace cc
#endif // CC_ANIMATION_TIMING_FUNCTION_H_
diff --git a/chromium/cc/base/BUILD.gn b/chromium/cc/base/BUILD.gn
index db70d19adb3..8b4eef21627 100644
--- a/chromium/cc/base/BUILD.gn
+++ b/chromium/cc/base/BUILD.gn
@@ -33,7 +33,6 @@ component("base") {
"list_container_helper.h",
"math_util.cc",
"math_util.h",
- "random_access_list_container.h",
"region.cc",
"region.h",
"render_surface_filters.cc",
diff --git a/chromium/cc/base/list_container.h b/chromium/cc/base/list_container.h
index cb386f9b343..93a6a67fc6d 100644
--- a/chromium/cc/base/list_container.h
+++ b/chromium/cc/base/list_container.h
@@ -26,28 +26,15 @@ namespace cc {
template <class BaseElementType>
class ListContainer {
public:
- ListContainer(ListContainer&& other) : helper_(sizeof(BaseElementType)) {
- helper_.data_.swap(other.helper_.data_);
- }
-
- // BaseElementType is the type of raw pointers this class hands out; however,
- // its derived classes might require different memory sizes.
- // max_size_for_derived_class the largest memory size required for all the
- // derived classes to use for allocation.
- explicit ListContainer(size_t max_size_for_derived_class)
- : helper_(max_size_for_derived_class) {}
-
- // This constructor omits input variable for max_size_for_derived_class. This
- // is used when there is no derived classes from BaseElementType we need to
- // worry about, and allocation size is just sizeof(BaseElementType).
- ListContainer() : helper_(sizeof(BaseElementType)) {}
-
// This constructor reserves the requested memory up front so only single
// allocation is needed. When num_of_elements_to_reserve_for is zero, use the
// default size.
- ListContainer(size_t max_size_for_derived_class,
+ ListContainer(size_t max_alignment,
+ size_t max_size_for_derived_class,
size_t num_of_elements_to_reserve_for)
- : helper_(max_size_for_derived_class, num_of_elements_to_reserve_for) {}
+ : helper_(max_alignment,
+ max_size_for_derived_class,
+ num_of_elements_to_reserve_for) {}
~ListContainer() {
for (Iterator i = begin(); i != end(); ++i) {
@@ -114,7 +101,8 @@ class ListContainer {
// Allocate().
template <typename DerivedElementType>
DerivedElementType* AllocateAndConstruct() {
- return new (helper_.Allocate(sizeof(DerivedElementType)))
+ return new (helper_.Allocate(ALIGNOF(DerivedElementType),
+ sizeof(DerivedElementType)))
DerivedElementType;
}
@@ -122,7 +110,8 @@ class ListContainer {
// Allocate().
template <typename DerivedElementType>
DerivedElementType* AllocateAndCopyFrom(const DerivedElementType* source) {
- return new (helper_.Allocate(sizeof(DerivedElementType)))
+ return new (helper_.Allocate(ALIGNOF(DerivedElementType),
+ sizeof(DerivedElementType)))
DerivedElementType(*source);
}
@@ -165,7 +154,8 @@ class ListContainer {
template <typename DerivedElementType>
DerivedElementType* AppendByMoving(DerivedElementType* item) {
size_t max_size_for_derived_class = helper_.MaxSizeForDerivedClass();
- void* new_item = helper_.Allocate(max_size_for_derived_class);
+ void* new_item = helper_.Allocate(ALIGNOF(DerivedElementType),
+ max_size_for_derived_class);
memcpy(new_item, static_cast<void*>(item), max_size_for_derived_class);
// Construct a new element in-place so it can be destructed safely.
new (item) DerivedElementType;
diff --git a/chromium/cc/base/list_container_helper.cc b/chromium/cc/base/list_container_helper.cc
index 9d8a0293a03..84ecd9bac40 100644
--- a/chromium/cc/base/list_container_helper.cc
+++ b/chromium/cc/base/list_container_helper.cc
@@ -11,6 +11,7 @@
#include "base/logging.h"
#include "base/macros.h"
+#include "base/memory/aligned_memory.h"
namespace {
const size_t kDefaultNumElementTypesToReserve = 32;
@@ -29,7 +30,7 @@ class ListContainerHelper::CharAllocator {
// This class holds the raw memory chunk, as well as information about its
// size and availability.
struct InnerList {
- std::unique_ptr<char[]> data;
+ std::unique_ptr<char[], base::AlignedFreeDeleter> data;
// The number of elements in total the memory can hold. The difference
// between capacity and size is the how many more elements this list can
// hold.
@@ -56,7 +57,7 @@ class ListContainerHelper::CharAllocator {
--capacity;
}
- void InsertBefore(char** position, size_t count) {
+ void InsertBefore(size_t alignment, char** position, size_t count) {
DCHECK_LE(*position, LastElement() + step);
DCHECK_GE(*position, Begin());
@@ -66,7 +67,8 @@ class ListContainerHelper::CharAllocator {
capacity = size;
// Allocate the new data and update the iterator's pointer.
- std::unique_ptr<char[]> new_data(new char[size * step]);
+ std::unique_ptr<char[], base::AlignedFreeDeleter> new_data(
+ static_cast<char*>(base::AlignedAlloc(size * step, alignment)));
size_t position_offset = *position - Begin();
*position = new_data.get() + position_offset;
@@ -75,7 +77,7 @@ class ListContainerHelper::CharAllocator {
// Copy the data after the inserted segment.
memcpy(new_data.get() + position_offset + count * step,
data.get() + position_offset, old_size * step - position_offset);
- new_data.swap(data);
+ data = std::move(new_data);
}
bool IsEmpty() const { return !size; }
@@ -102,20 +104,16 @@ class ListContainerHelper::CharAllocator {
DISALLOW_COPY_AND_ASSIGN(InnerList);
};
- explicit CharAllocator(size_t element_size)
- : element_size_(element_size),
- size_(0),
- last_list_index_(0),
- last_list_(nullptr) {
- AllocateNewList(kDefaultNumElementTypesToReserve);
- last_list_ = storage_[last_list_index_].get();
- }
-
- CharAllocator(size_t element_size, size_t element_count)
- : element_size_(element_size),
+ CharAllocator(size_t alignment, size_t element_size, size_t element_count)
+ // base::AlignedAlloc does not accept alignment less than sizeof(void*).
+ : alignment_(std::max(sizeof(void*), alignment)),
+ element_size_(element_size),
size_(0),
last_list_index_(0),
last_list_(nullptr) {
+ // If this fails, then alignment of elements after the first could be wrong,
+ // and we need to pad sizes to fix that.
+ DCHECK_EQ(element_size % alignment, 0u);
AllocateNewList(element_count > 0 ? element_count
: kDefaultNumElementTypesToReserve);
last_list_ = storage_[last_list_index_].get();
@@ -138,6 +136,7 @@ class ListContainerHelper::CharAllocator {
return last_list_->AddElement();
}
+ size_t alignment() const { return alignment_; }
size_t element_size() const { return element_size_; }
size_t list_count() const { return storage_.size(); }
size_t size() const { return size_; }
@@ -203,8 +202,8 @@ class ListContainerHelper::CharAllocator {
for (size_t i = 1; i < count; ++i)
Allocate();
} else {
- storage_[position->vector_index]->InsertBefore(&position->item_iterator,
- count);
+ storage_[position->vector_index]->InsertBefore(
+ alignment_, &position->item_iterator, count);
size_ += count;
}
}
@@ -244,11 +243,13 @@ class ListContainerHelper::CharAllocator {
new_list->capacity = list_size;
new_list->size = 0;
new_list->step = element_size_;
- new_list->data.reset(new char[list_size * element_size_]);
+ new_list->data.reset(static_cast<char*>(
+ base::AlignedAlloc(list_size * element_size_, alignment_)));
storage_.push_back(std::move(new_list));
}
std::vector<std::unique_ptr<InnerList>> storage_;
+ const size_t alignment_;
const size_t element_size_;
// The number of elements in the list.
@@ -341,12 +342,11 @@ ListContainerHelper::PositionInCharAllocator::ReverseIncrement() {
// ListContainerHelper
////////////////////////////////////////////
-ListContainerHelper::ListContainerHelper(size_t max_size_for_derived_class)
- : data_(new CharAllocator(max_size_for_derived_class)) {}
-
-ListContainerHelper::ListContainerHelper(size_t max_size_for_derived_class,
+ListContainerHelper::ListContainerHelper(size_t alignment,
+ size_t max_size_for_derived_class,
size_t num_of_elements_to_reserve_for)
- : data_(new CharAllocator(max_size_for_derived_class,
+ : data_(new CharAllocator(alignment,
+ max_size_for_derived_class,
num_of_elements_to_reserve_for)) {}
ListContainerHelper::~ListContainerHelper() {}
@@ -456,7 +456,9 @@ ListContainerHelper::Iterator ListContainerHelper::IteratorAt(size_t index) {
original_index);
}
-void* ListContainerHelper::Allocate(size_t size_of_actual_element_in_bytes) {
+void* ListContainerHelper::Allocate(size_t alignment,
+ size_t size_of_actual_element_in_bytes) {
+ DCHECK_LE(alignment, data_->alignment());
DCHECK_LE(size_of_actual_element_in_bytes, data_->element_size());
return data_->Allocate();
}
diff --git a/chromium/cc/base/list_container_helper.h b/chromium/cc/base/list_container_helper.h
index ce98c1ec4ef..c79cf1f1884 100644
--- a/chromium/cc/base/list_container_helper.h
+++ b/chromium/cc/base/list_container_helper.h
@@ -22,12 +22,9 @@ class CC_BASE_EXPORT ListContainerHelper final {
template <typename T>
friend class ListContainer;
- template <typename T>
- friend class RandomAccessListContainer;
-
- explicit ListContainerHelper(size_t max_size_for_derived_class);
- ListContainerHelper(size_t max_size_for_derived_class,
- size_t num_of_elements_to_reserve_for);
+ explicit ListContainerHelper(size_t alignment,
+ size_t max_size_for_derived_class,
+ size_t num_of_elements_to_reserve_for);
~ListContainerHelper();
// This class deals only with char* and void*. It does allocation and passing
@@ -170,7 +167,7 @@ class CC_BASE_EXPORT ListContainerHelper final {
size_t AvailableSizeWithoutAnotherAllocationForTesting() const;
// Hands out memory location for an element at the end of data structure.
- void* Allocate(size_t size_of_actual_element_in_bytes);
+ void* Allocate(size_t alignment, size_t size_of_actual_element_in_bytes);
std::unique_ptr<CharAllocator> data_;
diff --git a/chromium/cc/base/list_container_unittest.cc b/chromium/cc/base/list_container_unittest.cc
index 13630252959..31ef300b923 100644
--- a/chromium/cc/base/list_container_unittest.cc
+++ b/chromium/cc/base/list_container_unittest.cc
@@ -51,17 +51,20 @@ class DerivedElement3 : public DerivedElement {
};
const size_t kLargestDerivedElementSize = sizeof(DerivedElement3);
-
-size_t LargestDerivedElementSize() {
- static_assert(sizeof(DerivedElement1) <= kLargestDerivedElementSize,
- "Largest Derived Element size needs update. DerivedElement1 is "
- "currently largest.");
- static_assert(sizeof(DerivedElement2) <= kLargestDerivedElementSize,
- "Largest Derived Element size needs update. DerivedElement2 is "
- "currently largest.");
-
- return kLargestDerivedElementSize;
-}
+const size_t kLargestDerivedElementAlign = ALIGNOF(DerivedElement3);
+
+static_assert(sizeof(DerivedElement1) <= kLargestDerivedElementSize,
+ "Largest Derived Element size needs update. DerivedElement1 is "
+ "currently largest.");
+static_assert(sizeof(DerivedElement2) <= kLargestDerivedElementSize,
+ "Largest Derived Element size needs update. DerivedElement2 is "
+ "currently largest.");
+static_assert(ALIGNOF(DerivedElement1) <= kLargestDerivedElementSize,
+ "Largest Derived Element align needs update. DerivedElement1 is "
+ "currently largest.");
+static_assert(ALIGNOF(DerivedElement2) <= kLargestDerivedElementSize,
+ "Largest Derived Element align needs update. DerivedElement2 is "
+ "currently largest.");
// Element class having no derived classes.
class NonDerivedElement {
@@ -132,10 +135,13 @@ class MockDerivedElementSubclass : public MockDerivedElement {
};
const size_t kCurrentLargestDerivedElementSize =
- std::max(LargestDerivedElementSize(), sizeof(MockDerivedElementSubclass));
+ std::max(kLargestDerivedElementSize, sizeof(MockDerivedElementSubclass));
+const size_t kCurrentLargestDerivedElementAlign =
+ std::max(kLargestDerivedElementAlign, ALIGNOF(MockDerivedElementSubclass));
TEST(ListContainerTest, ConstructorCalledInAllocateAndConstruct) {
- ListContainer<DerivedElement> list(kCurrentLargestDerivedElementSize);
+ ListContainer<DerivedElement> list(kCurrentLargestDerivedElementAlign,
+ kCurrentLargestDerivedElementSize, 0);
size_t size = 2;
SimpleDerivedElementConstructMagicNumberOne* de_1 =
@@ -152,7 +158,8 @@ TEST(ListContainerTest, ConstructorCalledInAllocateAndConstruct) {
}
TEST(ListContainerTest, DestructorCalled) {
- ListContainer<DerivedElement> list(kCurrentLargestDerivedElementSize);
+ ListContainer<DerivedElement> list(kCurrentLargestDerivedElementAlign,
+ kCurrentLargestDerivedElementSize, 0);
size_t size = 1;
MockDerivedElement* de_1 = list.AllocateAndConstruct<MockDerivedElement>();
@@ -163,7 +170,8 @@ TEST(ListContainerTest, DestructorCalled) {
}
TEST(ListContainerTest, DestructorCalledOnceWhenClear) {
- ListContainer<DerivedElement> list(kCurrentLargestDerivedElementSize);
+ ListContainer<DerivedElement> list(kCurrentLargestDerivedElementAlign,
+ kCurrentLargestDerivedElementSize, 0);
size_t size = 1;
MockDerivedElement* de_1 = list.AllocateAndConstruct<MockDerivedElement>();
@@ -186,7 +194,8 @@ TEST(ListContainerTest, DestructorCalledOnceWhenClear) {
TEST(ListContainerTest, ClearDoesNotMalloc) {
const size_t reserve = 10;
- ListContainer<DerivedElement> list(kCurrentLargestDerivedElementSize,
+ ListContainer<DerivedElement> list(kCurrentLargestDerivedElementAlign,
+ kCurrentLargestDerivedElementSize,
reserve);
// Memory from the initial inner list that should be re-used after clear().
@@ -218,7 +227,8 @@ TEST(ListContainerTest, ClearDoesNotMalloc) {
}
TEST(ListContainerTest, ReplaceExistingElement) {
- ListContainer<DerivedElement> list(kCurrentLargestDerivedElementSize);
+ ListContainer<DerivedElement> list(kCurrentLargestDerivedElementAlign,
+ kCurrentLargestDerivedElementSize, 0);
size_t size = 1;
MockDerivedElement* de_1 = list.AllocateAndConstruct<MockDerivedElement>();
@@ -244,7 +254,8 @@ TEST(ListContainerTest, ReplaceExistingElement) {
}
TEST(ListContainerTest, DestructorCalledOnceWhenErase) {
- ListContainer<DerivedElement> list(kCurrentLargestDerivedElementSize);
+ ListContainer<DerivedElement> list(kCurrentLargestDerivedElementAlign,
+ kCurrentLargestDerivedElementSize, 0);
size_t size = 1;
MockDerivedElement* de_1 = list.AllocateAndConstruct<MockDerivedElement>();
@@ -266,7 +277,8 @@ TEST(ListContainerTest, DestructorCalledOnceWhenErase) {
}
TEST(ListContainerTest, SimpleIndexAccessNonDerivedElement) {
- ListContainer<NonDerivedElement> list;
+ ListContainer<NonDerivedElement> list(ALIGNOF(NonDerivedElement),
+ sizeof(NonDerivedElement), 0);
size_t size = 3;
NonDerivedElement* nde_1 = list.AllocateAndConstruct<NonDerivedElement>();
@@ -282,7 +294,8 @@ TEST(ListContainerTest, SimpleIndexAccessNonDerivedElement) {
}
TEST(ListContainerTest, SimpleInsertionNonDerivedElement) {
- ListContainer<NonDerivedElement> list;
+ ListContainer<NonDerivedElement> list(ALIGNOF(NonDerivedElement),
+ sizeof(NonDerivedElement), 0);
size_t size = 3;
NonDerivedElement* nde_1 = list.AllocateAndConstruct<NonDerivedElement>();
@@ -295,7 +308,8 @@ TEST(ListContainerTest, SimpleInsertionNonDerivedElement) {
}
TEST(ListContainerTest, SimpleInsertionAndClearNonDerivedElement) {
- ListContainer<NonDerivedElement> list;
+ ListContainer<NonDerivedElement> list(ALIGNOF(NonDerivedElement),
+ sizeof(NonDerivedElement), 0);
EXPECT_TRUE(list.empty());
EXPECT_EQ(0u, list.size());
@@ -315,7 +329,8 @@ TEST(ListContainerTest, SimpleInsertionAndClearNonDerivedElement) {
}
TEST(ListContainerTest, SimpleInsertionClearAndInsertAgainNonDerivedElement) {
- ListContainer<NonDerivedElement> list;
+ ListContainer<NonDerivedElement> list(ALIGNOF(NonDerivedElement),
+ sizeof(NonDerivedElement), 0);
EXPECT_TRUE(list.empty());
EXPECT_EQ(0u, list.size());
@@ -347,7 +362,8 @@ TEST(ListContainerTest, SimpleInsertionClearAndInsertAgainNonDerivedElement) {
// for, ListContainer can still perform like normal vector.
TEST(ListContainerTest,
SimpleInsertionTriggerMoreThanOneAllocationNonDerivedElement) {
- ListContainer<NonDerivedElement> list(sizeof(NonDerivedElement), 2);
+ ListContainer<NonDerivedElement> list(ALIGNOF(NonDerivedElement),
+ sizeof(NonDerivedElement), 2);
std::vector<NonDerivedElement*> nde_list;
size_t size = 10;
for (size_t i = 0; i < size; ++i) {
@@ -369,7 +385,8 @@ TEST(ListContainerTest,
// Constructor sets the allocation size to 2. Every time ListContainer needs
// to allocate again, it doubles allocation size. In this test, 10 elements is
// needed, thus ListContainerShould allocate spaces 2, 4 and 8 elements.
- ListContainer<NonDerivedElement> list(sizeof(NonDerivedElement), 2);
+ ListContainer<NonDerivedElement> list(ALIGNOF(NonDerivedElement),
+ sizeof(NonDerivedElement), 2);
std::vector<NonDerivedElement*> nde_list;
size_t size = 10;
for (size_t i = 0; i < size; ++i) {
@@ -449,7 +466,8 @@ TEST(ListContainerTest,
}
TEST(ListContainerTest, SimpleIterationNonDerivedElement) {
- ListContainer<NonDerivedElement> list;
+ ListContainer<NonDerivedElement> list(ALIGNOF(NonDerivedElement),
+ sizeof(NonDerivedElement), 0);
std::vector<NonDerivedElement*> nde_list;
size_t size = 10;
for (size_t i = 0; i < size; ++i) {
@@ -484,7 +502,8 @@ TEST(ListContainerTest, SimpleIterationNonDerivedElement) {
}
TEST(ListContainerTest, SimpleConstIteratorIterationNonDerivedElement) {
- ListContainer<NonDerivedElement> list;
+ ListContainer<NonDerivedElement> list(ALIGNOF(NonDerivedElement),
+ sizeof(NonDerivedElement), 0);
std::vector<const NonDerivedElement*> nde_list;
size_t size = 10;
for (size_t i = 0; i < size; ++i) {
@@ -526,7 +545,8 @@ TEST(ListContainerTest, SimpleConstIteratorIterationNonDerivedElement) {
}
TEST(ListContainerTest, SimpleReverseInsertionNonDerivedElement) {
- ListContainer<NonDerivedElement> list;
+ ListContainer<NonDerivedElement> list(ALIGNOF(NonDerivedElement),
+ sizeof(NonDerivedElement), 0);
std::vector<NonDerivedElement*> nde_list;
size_t size = 10;
for (size_t i = 0; i < size; ++i) {
@@ -556,7 +576,8 @@ TEST(ListContainerTest, SimpleReverseInsertionNonDerivedElement) {
}
TEST(ListContainerTest, SimpleDeletion) {
- ListContainer<DerivedElement> list(kCurrentLargestDerivedElementSize);
+ ListContainer<DerivedElement> list(kCurrentLargestDerivedElementAlign,
+ kCurrentLargestDerivedElementSize, 0);
std::vector<SimpleDerivedElement*> sde_list;
int size = 10;
for (int i = 0; i < size; ++i) {
@@ -578,7 +599,8 @@ TEST(ListContainerTest, SimpleDeletion) {
TEST(ListContainerTest, DeletionAllInAllocation) {
const size_t kReserve = 10;
- ListContainer<DerivedElement> list(kCurrentLargestDerivedElementSize,
+ ListContainer<DerivedElement> list(kCurrentLargestDerivedElementAlign,
+ kCurrentLargestDerivedElementSize,
kReserve);
std::vector<SimpleDerivedElement*> sde_list;
// Add enough elements to cause another allocation.
@@ -604,7 +626,8 @@ TEST(ListContainerTest, DeletionAllInAllocation) {
TEST(ListContainerTest, DeletionAllInAllocationReversed) {
const size_t kReserve = 10;
- ListContainer<DerivedElement> list(kCurrentLargestDerivedElementSize,
+ ListContainer<DerivedElement> list(kCurrentLargestDerivedElementAlign,
+ kCurrentLargestDerivedElementSize,
kReserve);
std::vector<SimpleDerivedElement*> sde_list;
// Add enough elements to cause another allocation.
@@ -660,7 +683,8 @@ TEST(ListContainerTest, DeletionAllInAllocationReversed) {
}
TEST(ListContainerTest, DeletionWhileIterating) {
- ListContainer<SimpleDerivedElement> list(kCurrentLargestDerivedElementSize);
+ ListContainer<SimpleDerivedElement> list(
+ kCurrentLargestDerivedElementAlign, kCurrentLargestDerivedElementSize, 0);
for (int i = 0; i < 4; ++i)
list.AllocateAndConstruct<SimpleDerivedElement>()->set_value(i);
@@ -684,7 +708,8 @@ TEST(ListContainerTest, DeletionWhileIterating) {
}
TEST(ListContainerTest, InsertBeforeBegin) {
- ListContainer<DerivedElement> list(kCurrentLargestDerivedElementSize);
+ ListContainer<DerivedElement> list(kCurrentLargestDerivedElementAlign,
+ kCurrentLargestDerivedElementSize, 0);
std::vector<SimpleDerivedElement*> sde_list;
const int size = 4;
for (int i = 0; i < size; ++i) {
@@ -713,7 +738,8 @@ TEST(ListContainerTest, InsertBeforeBegin) {
}
TEST(ListContainerTest, InsertBeforeEnd) {
- ListContainer<DerivedElement> list(kCurrentLargestDerivedElementSize);
+ ListContainer<DerivedElement> list(kCurrentLargestDerivedElementAlign,
+ kCurrentLargestDerivedElementSize, 0);
std::vector<SimpleDerivedElement*> sde_list;
const int size = 4;
for (int i = 0; i < size; ++i) {
@@ -742,7 +768,8 @@ TEST(ListContainerTest, InsertBeforeEnd) {
}
TEST(ListContainerTest, InsertBeforeEmpty) {
- ListContainer<DerivedElement> list(kCurrentLargestDerivedElementSize);
+ ListContainer<DerivedElement> list(kCurrentLargestDerivedElementAlign,
+ kCurrentLargestDerivedElementSize, 0);
const int count = 3;
ListContainer<DerivedElement>::Iterator iter =
@@ -764,7 +791,8 @@ TEST(ListContainerTest, InsertBeforeEmpty) {
}
TEST(ListContainerTest, InsertBeforeMany) {
- ListContainer<DerivedElement> list(kCurrentLargestDerivedElementSize);
+ ListContainer<DerivedElement> list(kCurrentLargestDerivedElementAlign,
+ kCurrentLargestDerivedElementSize, 0);
std::vector<SimpleDerivedElement*> sde_list;
// Create a partial list of 1,...,99.
int initial_list[] = {
@@ -810,7 +838,8 @@ TEST(ListContainerTest, InsertBeforeMany) {
}
TEST(ListContainerTest, SimpleManipulationWithIndexSimpleDerivedElement) {
- ListContainer<DerivedElement> list(kCurrentLargestDerivedElementSize);
+ ListContainer<DerivedElement> list(kCurrentLargestDerivedElementAlign,
+ kCurrentLargestDerivedElementSize, 0);
std::vector<SimpleDerivedElement*> de_list;
int size = 10;
for (int i = 0; i < size; ++i) {
@@ -832,7 +861,8 @@ TEST(ListContainerTest, SimpleManipulationWithIndexSimpleDerivedElement) {
TEST(ListContainerTest,
SimpleManipulationWithIndexMoreThanOneAllocationSimpleDerivedElement) {
- ListContainer<DerivedElement> list(LargestDerivedElementSize(), 2);
+ ListContainer<DerivedElement> list(kLargestDerivedElementAlign,
+ kLargestDerivedElementSize, 2);
std::vector<SimpleDerivedElement*> de_list;
int size = 10;
for (int i = 0; i < size; ++i) {
@@ -854,7 +884,8 @@ TEST(ListContainerTest,
TEST(ListContainerTest,
SimpleIterationAndReverseIterationWithIndexNonDerivedElement) {
- ListContainer<NonDerivedElement> list;
+ ListContainer<NonDerivedElement> list(ALIGNOF(NonDerivedElement),
+ sizeof(NonDerivedElement), 0);
std::vector<NonDerivedElement*> nde_list;
size_t size = 10;
for (size_t i = 0; i < size; ++i) {
@@ -900,7 +931,8 @@ TEST(ListContainerTest, RemoveLastDestruction) {
// We keep an explicit instance count to make sure that the destructors are
// indeed getting called.
int counter = 0;
- ListContainer<InstanceCounter> list(sizeof(InstanceCounter), 1);
+ ListContainer<InstanceCounter> list(ALIGNOF(InstanceCounter),
+ sizeof(InstanceCounter), 1);
EXPECT_EQ(0, counter);
EXPECT_EQ(0u, list.size());
@@ -944,7 +976,7 @@ TEST(ListContainerTest, RemoveLastIteration) {
struct SmallStruct {
char dummy[16];
};
- ListContainer<SmallStruct> list(sizeof(SmallStruct), 1);
+ ListContainer<SmallStruct> list(ALIGNOF(SmallStruct), sizeof(SmallStruct), 1);
std::vector<SmallStruct*> pointers;
// Utilities which keep these two lists in sync and check that their iteration
@@ -990,7 +1022,8 @@ TEST(ListContainerTest, RemoveLastIteration) {
}
TEST(ListContainerTest, AppendByMovingSameList) {
- ListContainer<SimpleDerivedElement> list(kCurrentLargestDerivedElementSize);
+ ListContainer<SimpleDerivedElement> list(
+ kCurrentLargestDerivedElementAlign, kCurrentLargestDerivedElementSize, 0);
list.AllocateAndConstruct<SimpleDerivedElementConstructMagicNumberOne>();
list.AppendByMoving(list.front());
@@ -1008,8 +1041,10 @@ TEST(ListContainerTest, AppendByMovingSameList) {
}
TEST(ListContainerTest, AppendByMovingDoesNotDestruct) {
- ListContainer<DerivedElement> list_1(kCurrentLargestDerivedElementSize);
- ListContainer<DerivedElement> list_2(kCurrentLargestDerivedElementSize);
+ ListContainer<DerivedElement> list_1(kCurrentLargestDerivedElementAlign,
+ kCurrentLargestDerivedElementSize, 0);
+ ListContainer<DerivedElement> list_2(kCurrentLargestDerivedElementAlign,
+ kCurrentLargestDerivedElementSize, 0);
MockDerivedElement* mde_1 = list_1.AllocateAndConstruct<MockDerivedElement>();
// Make sure destructor isn't called during AppendByMoving.
@@ -1021,8 +1056,10 @@ TEST(ListContainerTest, AppendByMovingDoesNotDestruct) {
}
TEST(ListContainerTest, AppendByMovingReturnsMovedPointer) {
- ListContainer<SimpleDerivedElement> list_1(kCurrentLargestDerivedElementSize);
- ListContainer<SimpleDerivedElement> list_2(kCurrentLargestDerivedElementSize);
+ ListContainer<SimpleDerivedElement> list_1(
+ kCurrentLargestDerivedElementAlign, kCurrentLargestDerivedElementSize, 0);
+ ListContainer<SimpleDerivedElement> list_2(
+ kCurrentLargestDerivedElementAlign, kCurrentLargestDerivedElementSize, 0);
SimpleDerivedElement* simple_element =
list_1.AllocateAndConstruct<SimpleDerivedElement>();
@@ -1036,9 +1073,9 @@ TEST(ListContainerTest, AppendByMovingReturnsMovedPointer) {
TEST(ListContainerTest, AppendByMovingReplacesSourceWithNewDerivedElement) {
ListContainer<SimpleDerivedElementConstructMagicNumberOne> list_1(
- kCurrentLargestDerivedElementSize);
+ kCurrentLargestDerivedElementAlign, kCurrentLargestDerivedElementSize, 0);
ListContainer<SimpleDerivedElementConstructMagicNumberTwo> list_2(
- kCurrentLargestDerivedElementSize);
+ kCurrentLargestDerivedElementAlign, kCurrentLargestDerivedElementSize, 0);
list_1.AllocateAndConstruct<SimpleDerivedElementConstructMagicNumberOne>();
EXPECT_EQ(kMagicNumberToUseForSimpleDerivedElementOne,
@@ -1106,7 +1143,8 @@ TEST(ListContainerTest, AppendByMovingLongAndSimpleDerivedElements) {
"LongSimpleDerivedElement should be smaller than the maximum "
"DerivedElement size.");
- ListContainer<SimpleDerivedElement> list(kCurrentLargestDerivedElementSize);
+ ListContainer<SimpleDerivedElement> list(
+ kCurrentLargestDerivedElementAlign, kCurrentLargestDerivedElementSize, 0);
list.AllocateAndConstruct<LongSimpleDerivedElementConstructMagicNumber>();
list.AllocateAndConstruct<SimpleDerivedElementConstructMagicNumberOne>();
@@ -1136,9 +1174,11 @@ TEST(ListContainerTest, AppendByMovingLongAndSimpleDerivedElements) {
}
TEST(ListContainerTest, Swap) {
- ListContainer<SimpleDerivedElement> list_1(kCurrentLargestDerivedElementSize);
+ ListContainer<SimpleDerivedElement> list_1(
+ kCurrentLargestDerivedElementAlign, kCurrentLargestDerivedElementSize, 0);
list_1.AllocateAndConstruct<SimpleDerivedElementConstructMagicNumberOne>();
- ListContainer<SimpleDerivedElement> list_2(kCurrentLargestDerivedElementSize);
+ ListContainer<SimpleDerivedElement> list_2(
+ kCurrentLargestDerivedElementAlign, kCurrentLargestDerivedElementSize, 0);
list_2.AllocateAndConstruct<SimpleDerivedElementConstructMagicNumberTwo>();
list_2.AllocateAndConstruct<SimpleDerivedElementConstructMagicNumberThree>();
@@ -1181,24 +1221,25 @@ TEST(ListContainerTest, GetCapacityInBytes) {
// memory, due to the exponential growth strategy).
const size_t max_waste_factor = 8;
- ListContainer<DerivedElement> list(LargestDerivedElementSize(),
+ ListContainer<DerivedElement> list(kLargestDerivedElementAlign,
+ kLargestDerivedElementSize,
initial_capacity);
// The capacity should grow with the list.
for (int i = 0; i < iterations; i++) {
size_t capacity = list.GetCapacityInBytes();
- ASSERT_GE(capacity, list.size() * LargestDerivedElementSize());
+ ASSERT_GE(capacity, list.size() * kLargestDerivedElementSize);
ASSERT_LE(capacity, std::max(list.size(), upper_bound_on_min_capacity) *
- max_waste_factor * LargestDerivedElementSize());
+ max_waste_factor * kLargestDerivedElementSize);
list.AllocateAndConstruct<DerivedElement1>();
}
// The capacity should shrink with the list.
for (int i = 0; i < iterations; i++) {
size_t capacity = list.GetCapacityInBytes();
- ASSERT_GE(capacity, list.size() * LargestDerivedElementSize());
+ ASSERT_GE(capacity, list.size() * kLargestDerivedElementSize);
ASSERT_LE(capacity, std::max(list.size(), upper_bound_on_min_capacity) *
- max_waste_factor * LargestDerivedElementSize());
+ max_waste_factor * kLargestDerivedElementSize);
list.RemoveLast();
}
}
diff --git a/chromium/cc/base/math_util.cc b/chromium/cc/base/math_util.cc
index 262f6586dba..53dde152d57 100644
--- a/chromium/cc/base/math_util.cc
+++ b/chromium/cc/base/math_util.cc
@@ -588,6 +588,12 @@ gfx::Vector2dF MathUtil::ComputeTransform2dScaleComponents(
return gfx::Vector2dF(x_scale, y_scale);
}
+float MathUtil::ComputeApproximateMaxScale(const gfx::Transform& transform) {
+ gfx::Vector3dF unit(1, 1, 0);
+ transform.TransformVector(&unit);
+ return std::max(std::abs(unit.x()), std::abs(unit.y()));
+}
+
float MathUtil::SmallestAngleBetweenVectors(const gfx::Vector2dF& v1,
const gfx::Vector2dF& v2) {
double dot_product = gfx::DotProduct(v1, v2) / v1.Length() / v2.Length();
@@ -817,7 +823,7 @@ ScopedSubnormalFloatDisabler::~ScopedSubnormalFloatDisabler() {
#endif
}
-bool MathUtil::IsNearlyTheSameForTesting(float left, float right) {
+bool MathUtil::IsFloatNearlyTheSame(float left, float right) {
return IsNearlyTheSame(left, right);
}
diff --git a/chromium/cc/base/math_util.h b/chromium/cc/base/math_util.h
index 7bccfea3718..f2c3784b97b 100644
--- a/chromium/cc/base/math_util.h
+++ b/chromium/cc/base/math_util.h
@@ -219,6 +219,10 @@ class CC_BASE_EXPORT MathUtil {
static gfx::Vector2dF ComputeTransform2dScaleComponents(const gfx::Transform&,
float fallbackValue);
+ // Returns an approximate max scale value of the transform even if it has
+ // perspective. Prefer to use ComputeTransform2dScaleComponents if there is no
+ // perspective, since it can produce more accurate results.
+ static float ComputeApproximateMaxScale(const gfx::Transform& transform);
// Makes a rect that has the same relationship to input_outer_rect as
// scale_inner_rect has to scale_outer_rect. scale_inner_rect should be
@@ -296,7 +300,7 @@ class CC_BASE_EXPORT MathUtil {
// Returns vector that y axis (0,1,0) transforms to under given transform.
static gfx::Vector3dF GetYAxis(const gfx::Transform& transform);
- static bool IsNearlyTheSameForTesting(float left, float right);
+ static bool IsFloatNearlyTheSame(float left, float right);
static bool IsNearlyTheSameForTesting(const gfx::PointF& l,
const gfx::PointF& r);
static bool IsNearlyTheSameForTesting(const gfx::Point3F& l,
diff --git a/chromium/cc/base/math_util_unittest.cc b/chromium/cc/base/math_util_unittest.cc
index 86afb34b68b..ce765c741ff 100644
--- a/chromium/cc/base/math_util_unittest.cc
+++ b/chromium/cc/base/math_util_unittest.cc
@@ -457,9 +457,9 @@ TEST(MathUtilTest, RoundDownUnderflow) {
}
#define EXPECT_SIMILAR_VALUE(x, y) \
- EXPECT_TRUE(MathUtil::IsNearlyTheSameForTesting(x, y))
+ EXPECT_TRUE(MathUtil::IsFloatNearlyTheSame(x, y))
#define EXPECT_DISSIMILAR_VALUE(x, y) \
- EXPECT_FALSE(MathUtil::IsNearlyTheSameForTesting(x, y))
+ EXPECT_FALSE(MathUtil::IsFloatNearlyTheSame(x, y))
// Arbitrary point that shouldn't be different from zero.
static const float zeroish = 1.0e-11f;
diff --git a/chromium/cc/base/random_access_list_container.h b/chromium/cc/base/random_access_list_container.h
deleted file mode 100644
index 34eb6990824..00000000000
--- a/chromium/cc/base/random_access_list_container.h
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_BASE_RANDOM_ACCESS_LIST_CONTAINER_H_
-#define CC_BASE_RANDOM_ACCESS_LIST_CONTAINER_H_
-
-#include <stddef.h>
-
-#include <vector>
-
-#include "base/logging.h"
-#include "cc/base/list_container_helper.h"
-
-namespace cc {
-
-// RandomAccessListContainer is a container similar to ListContainer (see
-// list_container.h), but it allows random access into its elements via
-// operator[]. In order to have efficient support for random access, some
-// functionality is not available for RandomAccessListContainers, such as
-// insert/deletes in the middle of the list.
-template <class BaseElementType>
-class RandomAccessListContainer {
- public:
- // BaseElementType is the type of raw pointers this class hands out; however,
- // its derived classes might require different memory sizes.
- // max_size_for_derived_class the largest memory size required for all the
- // derived classes to use for allocation.
- explicit RandomAccessListContainer(size_t max_size_for_derived_class)
- : helper_(max_size_for_derived_class) {}
-
- // This constructor reserves the requested memory up front so only a single
- // allocation is needed. When num_of_elements_to_reserve_for is zero, use the
- // default size.
- RandomAccessListContainer(size_t max_size_for_derived_class,
- size_t num_of_elements_to_reserve_for)
- : helper_(max_size_for_derived_class, num_of_elements_to_reserve_for) {
- items_.reserve(num_of_elements_to_reserve_for);
- }
-
- ~RandomAccessListContainer() {
- for (BaseElementType* item : items_)
- item->~BaseElementType();
- }
-
- void clear() {
- for (BaseElementType* item : items_)
- item->~BaseElementType();
- helper_.clear();
- items_.clear();
- }
-
- bool empty() const { return helper_.empty(); }
- size_t size() const { return helper_.size(); }
- size_t GetCapacityInBytes() const { return helper_.GetCapacityInBytes(); }
-
- template <typename DerivedElementType>
- DerivedElementType* AllocateAndConstruct() {
- auto* value =
- new (helper_.Allocate(sizeof(DerivedElementType))) DerivedElementType;
- items_.push_back(value);
- return value;
- }
-
- void RemoveLast() {
- items_.back()->~BaseElementType();
- items_.pop_back();
- helper_.RemoveLast();
- }
-
- const BaseElementType* operator[](size_t index) const {
- DCHECK_GE(index, 0u);
- DCHECK_LT(index, items_.size());
- return items_[index];
- }
-
- BaseElementType* operator[](size_t index) {
- DCHECK_GE(index, 0u);
- DCHECK_LT(index, items_.size());
- return items_[index];
- }
-
- // Note that although BaseElementType objects can change, the pointer itself
- // (in the vector) cannot. So this class only supports a const iterator.
- using ConstIterator = typename std::vector<BaseElementType*>::const_iterator;
- ConstIterator begin() const { return items_.begin(); }
- ConstIterator end() const { return items_.end(); }
-
- private:
- ListContainerHelper helper_;
- std::vector<BaseElementType*> items_;
-};
-
-} // namespace cc
-
-#endif // CC_BASE_RANDOM_ACCESS_LIST_CONTAINER_H_
diff --git a/chromium/cc/base/random_access_list_container_unittest.cc b/chromium/cc/base/random_access_list_container_unittest.cc
deleted file mode 100644
index c02ca784aef..00000000000
--- a/chromium/cc/base/random_access_list_container_unittest.cc
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/base/random_access_list_container.h"
-
-#include <stddef.h>
-
-#include <algorithm>
-#include <vector>
-
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace cc {
-namespace {
-
-class Base {
- public:
- virtual ~Base() {}
- int get_value() const { return value_; }
-
- protected:
- explicit Base(int value) : value_(value) {}
-
- int value_;
-};
-
-const int kMagicNumberOne = 1;
-const int kMagicNumberTwo = 2;
-const int kMagicNumberThree = 3;
-
-class Derived1 : public Base {
- public:
- Derived1() : Base(kMagicNumberOne) {}
-};
-
-class Derived2 : public Base {
- public:
- Derived2() : Base(kMagicNumberTwo) {}
-};
-
-class Derived3 : public Base {
- public:
- Derived3() : Base(kMagicNumberThree) {}
-};
-
-size_t LargestDerivedElementSize() {
- static_assert(sizeof(Derived1) >= sizeof(Derived2),
- "Derived2 is larger than Derived1");
- static_assert(sizeof(Derived1) >= sizeof(Derived3),
- "Derived3 is larger than Derived1");
- return sizeof(Derived1);
-}
-
-TEST(RandomAccessListContainerTest, RandomAccess) {
- RandomAccessListContainer<Base> list(LargestDerivedElementSize(), 1);
-
- list.AllocateAndConstruct<Derived1>();
- list.AllocateAndConstruct<Derived2>();
- list.AllocateAndConstruct<Derived3>();
- list.AllocateAndConstruct<Derived1>();
- list.AllocateAndConstruct<Derived2>();
- list.AllocateAndConstruct<Derived3>();
-
- EXPECT_EQ(kMagicNumberOne, list[0]->get_value());
- EXPECT_EQ(kMagicNumberTwo, list[1]->get_value());
- EXPECT_EQ(kMagicNumberThree, list[2]->get_value());
- EXPECT_EQ(kMagicNumberOne, list[3]->get_value());
- EXPECT_EQ(kMagicNumberTwo, list[4]->get_value());
- EXPECT_EQ(kMagicNumberThree, list[5]->get_value());
-
- list.RemoveLast();
- list.RemoveLast();
- list.RemoveLast();
-
- EXPECT_EQ(kMagicNumberOne, list[0]->get_value());
- EXPECT_EQ(kMagicNumberTwo, list[1]->get_value());
- EXPECT_EQ(kMagicNumberThree, list[2]->get_value());
-
- list.AllocateAndConstruct<Derived3>();
- list.AllocateAndConstruct<Derived2>();
- list.AllocateAndConstruct<Derived1>();
-
- EXPECT_EQ(kMagicNumberOne, list[0]->get_value());
- EXPECT_EQ(kMagicNumberTwo, list[1]->get_value());
- EXPECT_EQ(kMagicNumberThree, list[2]->get_value());
- EXPECT_EQ(kMagicNumberThree, list[3]->get_value());
- EXPECT_EQ(kMagicNumberTwo, list[4]->get_value());
- EXPECT_EQ(kMagicNumberOne, list[5]->get_value());
-}
-
-TEST(RandomAccessListContainerTest, Clear) {
- RandomAccessListContainer<Base> list(LargestDerivedElementSize(), 1);
-
- list.AllocateAndConstruct<Derived1>();
- list.AllocateAndConstruct<Derived2>();
-
- EXPECT_EQ(kMagicNumberOne, list[0]->get_value());
- EXPECT_EQ(kMagicNumberTwo, list[1]->get_value());
-
- list.clear();
- list.AllocateAndConstruct<Derived3>();
-
- EXPECT_EQ(kMagicNumberThree, list[0]->get_value());
-}
-
-} // namespace
-} // namespace cc
diff --git a/chromium/cc/base/resource_id.h b/chromium/cc/base/resource_id.h
index 2b25ea55fee..5ae6189cfe7 100644
--- a/chromium/cc/base/resource_id.h
+++ b/chromium/cc/base/resource_id.h
@@ -6,12 +6,13 @@
#define CC_BASE_RESOURCE_ID_H_
#include <stdint.h>
-#include <unordered_set>
+
+#include "base/containers/flat_set.h"
namespace cc {
using ResourceId = uint32_t;
-using ResourceIdSet = std::unordered_set<ResourceId>;
+using ResourceIdSet = base::flat_set<ResourceId>;
} // namespace cc
diff --git a/chromium/cc/base/rtree.cc b/chromium/cc/base/rtree.cc
index 1cb0f997cd0..0859fcc3d13 100644
--- a/chromium/cc/base/rtree.cc
+++ b/chromium/cc/base/rtree.cc
@@ -23,11 +23,8 @@ RTree::Node* RTree::AllocateNodeAtLevel(int level) {
// We don't allow reallocations, since that would invalidate references to
// existing nodes, so verify that capacity > size.
DCHECK_GT(nodes_.capacity(), nodes_.size());
- nodes_.emplace_back();
- Node& node = nodes_.back();
- node.num_children = 0;
- node.level = level;
- return &node;
+ nodes_.emplace_back(level);
+ return &nodes_.back();
}
RTree::Branch RTree::BuildRecursive(std::vector<Branch>* branches, int level) {
@@ -112,9 +109,11 @@ RTree::Branch RTree::BuildRecursive(std::vector<Branch>* branches, int level) {
return BuildRecursive(branches, level + 1);
}
-void RTree::Search(const gfx::Rect& query, std::vector<size_t>* results) const {
+std::vector<size_t> RTree::Search(const gfx::Rect& query) const {
+ std::vector<size_t> results;
if (num_data_elements_ > 0 && query.Intersects(root_.bounds))
- SearchRecursive(root_.subtree, query, results);
+ SearchRecursive(root_.subtree, query, &results);
+ return results;
}
void RTree::SearchRecursive(Node* node,
diff --git a/chromium/cc/base/rtree.h b/chromium/cc/base/rtree.h
index 3a19c29ac3d..3d4d742c93e 100644
--- a/chromium/cc/base/rtree.h
+++ b/chromium/cc/base/rtree.h
@@ -40,6 +40,16 @@ class CC_BASE_EXPORT RTree {
RTree();
~RTree();
+ // Constructs the rtree from a given container of gfx::Rects. Queries using
+ // Search will then return indices into this container.
+ template <typename Container>
+ void Build(const Container& items) {
+ Build(items, [](const gfx::Rect& bounds) { return bounds; });
+ }
+
+ // Build helper that takes a container and a function used to get gfx::Rect
+ // from each item. That is, "bounds_getter(items[i]);" should return a
+ // gfx::Rect representing the bounds of items[i] for each i.
template <typename Container, typename Functor>
void Build(const Container& items, const Functor& bounds_getter) {
DCHECK_EQ(0u, num_data_elements_);
@@ -52,10 +62,7 @@ class CC_BASE_EXPORT RTree {
if (bounds.IsEmpty())
continue;
- branches.push_back(Branch());
- Branch& branch = branches.back();
- branch.bounds = bounds;
- branch.index = i;
+ branches.emplace_back(i, bounds);
}
num_data_elements_ = branches.size();
@@ -89,13 +96,11 @@ class CC_BASE_EXPORT RTree {
static_cast<size_t>(kMinChildren));
}
- template <typename Container>
- void Build(const Container& items) {
- Build(items, [](const gfx::Rect& bounds) { return bounds; });
- }
-
- void Search(const gfx::Rect& query, std::vector<size_t>* results) const;
+ // Given a query rect, returns sorted indices of elements that were used to
+ // construct this rtree.
+ std::vector<size_t> Search(const gfx::Rect& query) const;
+ // Returns the total bounds of all items in this rtree.
gfx::Rect GetBounds() const;
private:
@@ -115,12 +120,18 @@ class CC_BASE_EXPORT RTree {
size_t index;
};
gfx::Rect bounds;
+
+ Branch() {}
+ Branch(size_t index, const gfx::Rect& bounds)
+ : index(index), bounds(bounds) {}
};
struct Node {
uint16_t num_children;
uint16_t level;
Branch children[kMaxChildren];
+
+ explicit Node(uint16_t level) : num_children(0), level(level) {}
};
void SearchRecursive(Node* root,
diff --git a/chromium/cc/base/rtree_perftest.cc b/chromium/cc/base/rtree_perftest.cc
index d18d0f66fdf..22445338d8e 100644
--- a/chromium/cc/base/rtree_perftest.cc
+++ b/chromium/cc/base/rtree_perftest.cc
@@ -15,6 +15,14 @@ static const int kTimeLimitMillis = 2000;
static const int kWarmupRuns = 5;
static const int kTimeCheckInterval = 10;
+template <typename Container>
+size_t Accumulate(const Container& container) {
+ size_t result = 0;
+ for (size_t index : container)
+ result += index;
+ return result;
+}
+
class RTreePerfTest : public testing::Test {
public:
RTreePerfTest()
@@ -50,8 +58,7 @@ class RTreePerfTest : public testing::Test {
timer_.Reset();
do {
- std::vector<size_t> results;
- rtree.Search(queries[query_index], &results);
+ Accumulate(rtree.Search(queries[query_index]));
query_index = (query_index + 1) % queries.size();
timer_.NextLap();
} while (!timer_.HasTimeLimitExpired());
diff --git a/chromium/cc/base/rtree_unittest.cc b/chromium/cc/base/rtree_unittest.cc
index 7b13f352c03..487d0c4f9c2 100644
--- a/chromium/cc/base/rtree_unittest.cc
+++ b/chromium/cc/base/rtree_unittest.cc
@@ -35,22 +35,20 @@ TEST(RTreeTest, NoOverlap) {
RTree rtree;
rtree.Build(rects);
- std::vector<size_t> results;
- rtree.Search(gfx::Rect(0, 0, 50, 50), &results);
+ std::vector<size_t> results = rtree.Search(gfx::Rect(0, 0, 50, 50));
ASSERT_EQ(2500u, results.size());
+ // Note that the results have to be sorted.
for (size_t i = 0; i < 2500; ++i) {
ASSERT_EQ(results[i], i);
}
- results.clear();
- rtree.Search(gfx::Rect(0, 0, 50, 49), &results);
+ results = rtree.Search(gfx::Rect(0, 0, 50, 49));
ASSERT_EQ(2450u, results.size());
for (size_t i = 0; i < 2450; ++i) {
ASSERT_EQ(results[i], i);
}
- results.clear();
- rtree.Search(gfx::Rect(5, 6, 1, 1), &results);
+ results = rtree.Search(gfx::Rect(5, 6, 1, 1));
ASSERT_EQ(1u, results.size());
EXPECT_EQ(6u * 50 + 5u, results[0]);
}
@@ -66,21 +64,49 @@ TEST(RTreeTest, Overlap) {
RTree rtree;
rtree.Build(rects);
- std::vector<size_t> results;
- rtree.Search(gfx::Rect(0, 0, 1, 1), &results);
+ std::vector<size_t> results = rtree.Search(gfx::Rect(0, 0, 1, 1));
ASSERT_EQ(2500u, results.size());
+ // Both the checks for the elements assume elements are sorted.
for (size_t i = 0; i < 2500; ++i) {
ASSERT_EQ(results[i], i);
}
- results.clear();
- rtree.Search(gfx::Rect(0, 49, 1, 1), &results);
+ results = rtree.Search(gfx::Rect(0, 49, 1, 1));
ASSERT_EQ(50u, results.size());
for (size_t i = 0; i < 50; ++i) {
EXPECT_EQ(results[i], 2450u + i);
}
}
+static void VerifySorted(const std::vector<size_t>& results) {
+ for (size_t i = 1; i < results.size(); ++i) {
+ ASSERT_LT(results[i - 1], results[i]);
+ }
+}
+
+TEST(RTreeTest, SortedResults) {
+ // This test verifies that all queries return sorted elements.
+ std::vector<gfx::Rect> rects;
+ for (int y = 0; y < 50; ++y) {
+ for (int x = 0; x < 50; ++x) {
+ rects.push_back(gfx::Rect(x, y, 1, 1));
+ rects.push_back(gfx::Rect(x, y, 2, 2));
+ rects.push_back(gfx::Rect(x, y, 3, 3));
+ }
+ }
+
+ RTree rtree;
+ rtree.Build(rects);
+
+ for (int y = 0; y < 50; ++y) {
+ for (int x = 0; x < 50; ++x) {
+ VerifySorted(rtree.Search(gfx::Rect(x, y, 1, 1)));
+ VerifySorted(rtree.Search(gfx::Rect(x, y, 50, 1)));
+ VerifySorted(rtree.Search(gfx::Rect(x, y, 1, 50)));
+ }
+ }
+}
+
TEST(RTreeTest, GetBoundsEmpty) {
RTree rtree;
ASSERT_EQ(gfx::Rect(), rtree.GetBounds());
diff --git a/chromium/cc/base/simple_enclosed_region.cc b/chromium/cc/base/simple_enclosed_region.cc
index 50e905bb68c..d3f3385cb9c 100644
--- a/chromium/cc/base/simple_enclosed_region.cc
+++ b/chromium/cc/base/simple_enclosed_region.cc
@@ -9,6 +9,7 @@
#include "base/logging.h"
#include "cc/base/region.h"
+#include "ui/gfx/geometry/rect.h"
namespace cc {
@@ -124,10 +125,22 @@ void SimpleEnclosedRegion::Union(const gfx::Rect& new_rect) {
}
rect_.SetRect(left, top, right - left, bottom - top);
-
+ int64_t rect_area = static_cast<int64_t>(rect_.width()) * rect_.height();
gfx::Rect adjusted_new_rect(
new_left, new_top, new_right - new_left, new_bottom - new_top);
- if (RectIsLargerArea(adjusted_new_rect, rect_))
+ int64_t adjust_new_rect_area =
+ static_cast<int64_t>(adjusted_new_rect.width()) *
+ adjusted_new_rect.height();
+ gfx::Rect overlap = gfx::IntersectRects(rect_, adjusted_new_rect);
+ int64_t overlap_area =
+ static_cast<int64_t>(overlap.width()) * overlap.height();
+
+ // Based on the assumption that as we compute occlusion, each step is
+ // more likely to be occluded by things added to this region more recently due
+ // to the way we build scenes with overlapping elements adjacent to each other
+ // in the Z order. So, the area of the new rect has a weight of 2 in the
+ // weighted area calculation.
+ if (adjust_new_rect_area * 2 > rect_area + overlap_area)
rect_ = adjusted_new_rect;
}
diff --git a/chromium/cc/base/simple_enclosed_region_unittest.cc b/chromium/cc/base/simple_enclosed_region_unittest.cc
index ca3ad619874..66f3f877362 100644
--- a/chromium/cc/base/simple_enclosed_region_unittest.cc
+++ b/chromium/cc/base/simple_enclosed_region_unittest.cc
@@ -337,80 +337,134 @@ TEST(SimpleEnclosedRegionTest, Union) {
r.Union(gfx::Rect(2, 3, 9, 10));
EXPECT_TRUE(ExpectRegionEq(gfx::Rect(2, 3, 9, 10), r));
- // Union with a smaller disjoint rect is ignored.
- r.Union(gfx::Rect(20, 21, 9, 9));
- EXPECT_TRUE(ExpectRegionEq(gfx::Rect(2, 3, 9, 10), r));
+ // Union with a second disjoint rect with area larger than half of the first
+ // one.
+ // +---+ +--+
+ // | | | |
+ // +---+ +--+
+ r.Union(gfx::Rect(20, 20, 6, 10));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(20, 20, 6, 10), r));
- // Union with a smaller overlapping rect is ignored.
- r.Union(gfx::Rect(3, 4, 9, 9));
- EXPECT_TRUE(ExpectRegionEq(gfx::Rect(2, 3, 9, 10), r));
+ // Union with a second disjoint rect with area smaller than half of the first
+ // one.
+ // +----+ +--+
+ // | | +--+
+ // +----+
+ r.Union(gfx::Rect(2, 3, 3, 3));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(20, 20, 6, 10), r));
- // Union with an equal sized rect can be either one.
- r.Union(gfx::Rect(4, 4, 9, 10));
- EXPECT_EQ(1u, r.GetRegionComplexity());
- EXPECT_TRUE(r.bounds() == gfx::Rect(2, 3, 9, 10) ||
- r.bounds() == gfx::Rect(4, 4, 9, 10));
+ // Union with a second disjoint rect with area larger than the first one.
+ // +---+ +-------+
+ // | | | |
+ // +---+ +-------+
+ r.Union(gfx::Rect(2, 3, 15, 15));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(2, 3, 15, 15), r));
- // Union with a larger disjoint rect is taken.
- r.Union(gfx::Rect(20, 21, 12, 13));
- EXPECT_TRUE(ExpectRegionEq(gfx::Rect(20, 21, 12, 13), r));
+ // Union with rect which extends from the first one:
+ // +----------+
+ // | 1 | 2 |
+ // +-----+----+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Union(gfx::Rect(20, 10, 5, 10));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 15, 10), r));
- // Union with a larger overlapping rect is taken.
- r.Union(gfx::Rect(19, 19, 12, 14));
- EXPECT_TRUE(ExpectRegionEq(gfx::Rect(19, 19, 12, 14), r));
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Union(gfx::Rect(10, 5, 10, 5));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 5, 10, 15), r));
- // True also when the rect covers one edge of the existing region.
r = gfx::Rect(10, 10, 10, 10);
- r.Union(gfx::Rect(12, 7, 9, 16));
- EXPECT_TRUE(ExpectRegionEq(gfx::Rect(12, 7, 9, 16), r));
+ r.Union(gfx::Rect(5, 10, 5, 10));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(5, 10, 15, 10), r));
r = gfx::Rect(10, 10, 10, 10);
- r.Union(gfx::Rect(9, 7, 9, 16));
- EXPECT_TRUE(ExpectRegionEq(gfx::Rect(9, 7, 9, 16), r));
+ r.Union(gfx::Rect(10, 20, 10, 5));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 10, 15), r));
+ // Union with rect which overlaps and extends from the first one:
+ // +----+--+---+
+ // | 1 | |2 |
+ // | | | |
+ // +----+--+---+
r = gfx::Rect(10, 10, 10, 10);
- r.Union(gfx::Rect(7, 12, 16, 9));
- EXPECT_TRUE(ExpectRegionEq(gfx::Rect(7, 12, 16, 9), r));
+ r.Union(gfx::Rect(10, 2, 10, 10));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 2, 10, 18), r));
r = gfx::Rect(10, 10, 10, 10);
- r.Union(gfx::Rect(7, 9, 16, 9));
- EXPECT_TRUE(ExpectRegionEq(gfx::Rect(7, 9, 16, 9), r));
+ r.Union(gfx::Rect(2, 10, 10, 10));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(2, 10, 18, 10), r));
- // But if the existing region can be expanded to make a larger rect, then it
- // will. Union area is 9*12 = 108. By merging, we make a rect with an area of
- // 10*11 = 110. The resulting rect is expanded as far as possible while
- // remaining enclosed in the Union.
r = gfx::Rect(10, 10, 10, 10);
- r.Union(gfx::Rect(12, 9, 9, 12));
- EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 11, 10), r));
+ r.Union(gfx::Rect(10, 18, 10, 10));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 10, 18), r));
r = gfx::Rect(10, 10, 10, 10);
- r.Union(gfx::Rect(9, 9, 9, 12));
- EXPECT_TRUE(ExpectRegionEq(gfx::Rect(9, 10, 11, 10), r));
+ r.Union(gfx::Rect(18, 10, 10, 10));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 18, 10), r));
+ // Union with a second rect which overlaps with the first one and
+ // area(rect 1) + area(overlap) > area(rect 2)*2 and
+ // area(rect 1) < area(rect 2)*2.
+ // +---+
+ // +---|+ 2|
+ // | +---+
+ // | 1 |
+ // +----+ (same figure for next test case.)
r = gfx::Rect(10, 10, 10, 10);
- r.Union(gfx::Rect(9, 12, 12, 9));
- EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 10, 11), r));
+ r.Union(gfx::Rect(14, 12, 8, 7));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 10, 10), r));
r = gfx::Rect(10, 10, 10, 10);
- r.Union(gfx::Rect(9, 9, 12, 9));
- EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 9, 10, 11), r));
+ r.Union(gfx::Rect(11, 9, 8, 7));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 10, 10), r));
- r = gfx::Rect(12, 9, 9, 12);
- r.Union(gfx::Rect(10, 10, 10, 10));
- EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 11, 10), r));
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Union(gfx::Rect(9, 12, 8, 7));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 10, 10), r));
+
+ r = gfx::Rect(10, 10, 10, 10);
+ r.Union(gfx::Rect(13, 11, 8, 7));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 10, 10), r));
- r = gfx::Rect(9, 9, 9, 12);
- r.Union(gfx::Rect(10, 10, 10, 10));
- EXPECT_TRUE(ExpectRegionEq(gfx::Rect(9, 10, 11, 10), r));
+ // Union with a second rect which overlaps with the first one and
+ // area(rect 1) + area(overlap) < area(rect 2)*2 and
+ // area(rect 1) > area(rect 2).
+ r = gfx::Rect(10, 10, 5, 5);
+ r.Union(gfx::Rect(7, 7, 4, 4));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(7, 7, 4, 4), r));
+
+ r = gfx::Rect(10, 10, 5, 5);
+ r.Union(gfx::Rect(14, 7, 4, 4));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(14, 7, 4, 4), r));
+
+ r = gfx::Rect(10, 10, 5, 5);
+ r.Union(gfx::Rect(7, 14, 4, 4));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(7, 14, 4, 4), r));
+
+ r = gfx::Rect(10, 10, 5, 5);
+ r.Union(gfx::Rect(14, 14, 4, 4));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(14, 14, 4, 4), r));
+
+ // Union with a second rect which overlaps with the first one and the new
+ // unioned rect should combine both rect.
+ // +---+-+-----------+
+ // | 1| | 2 |
+ // | +-|-----------+
+ // +-----+
+ r = gfx::Rect(10, 10, 5, 5);
+ r.Union(gfx::Rect(5, 11, 7, 4));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(5, 11, 10, 4), r));
+
+ r = gfx::Rect(10, 10, 5, 5);
+ r.Union(gfx::Rect(13, 10, 7, 4));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 10, 4), r));
- r = gfx::Rect(9, 12, 12, 9);
- r.Union(gfx::Rect(10, 10, 10, 10));
- EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 10, 11), r));
+ r = gfx::Rect(10, 10, 5, 5);
+ r.Union(gfx::Rect(10, 12, 4, 7));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 10, 4, 9), r));
- r = gfx::Rect(9, 9, 12, 9);
- r.Union(gfx::Rect(10, 10, 10, 10));
- EXPECT_TRUE(ExpectRegionEq(gfx::Rect(10, 9, 10, 11), r));
+ r = gfx::Rect(10, 10, 5, 5);
+ r.Union(gfx::Rect(11, 11, 4, 7));
+ EXPECT_TRUE(ExpectRegionEq(gfx::Rect(11, 10, 4, 8), r));
}
TEST(SimpleEnclosedRegionTest, Subtract) {
diff --git a/chromium/cc/base/switches.cc b/chromium/cc/base/switches.cc
index 1c562c9b4d7..f4aff0cf2cf 100644
--- a/chromium/cc/base/switches.cc
+++ b/chromium/cc/base/switches.cc
@@ -43,10 +43,6 @@ const char kSlowDownRasterScaleFactor[] = "slow-down-raster-scale-factor";
// Compress tile textures for GPUs supporting it.
const char kEnableTileCompression[] = "enable-tile-compression";
-// Convert rasterization and compositing inputs to the output color space
-// before operating on them.
-const char kEnableColorCorrectRendering[] = "enable-color-correct-rendering";
-
// Enables the GPU benchmarking extension
const char kEnableGpuBenchmarking[] = "enable-gpu-benchmarking";
@@ -58,7 +54,7 @@ const char kEnableSurfaceSynchronization[] = "enable-surface-synchronization";
// Renders a border around compositor layers to help debug and study
// layer compositing.
const char kShowCompositedLayerBorders[] = "show-composited-layer-borders";
-const char kUIShowCompositedLayerBorders[] = "ui-show-layer-borders";
+const char kUIShowCompositedLayerBorders[] = "ui-show-composited-layer-borders";
const char kCompositedRenderPassBorders[] = "renderpass";
const char kCompositedSurfaceBorders[] = "surface";
const char kCompositedLayerBorders[] = "layer";
@@ -117,5 +113,10 @@ const char kCCLayerTreeTestLongTimeout[] = "cc-layer-tree-test-long-timeout";
// Makes pixel tests write their output instead of read it.
const char kCCRebaselinePixeltests[] = "cc-rebaseline-pixeltests";
+// Disable re-use of non-exact resources to fulfill ResourcePool requests.
+// Intended only for use in layout or pixel tests to reduce noise.
+const char kDisallowNonExactResourceReuse[] =
+ "disallow-non-exact-resource-reuse";
+
} // namespace switches
} // namespace cc
diff --git a/chromium/cc/base/switches.h b/chromium/cc/base/switches.h
index 81177019bdb..3f58249334a 100644
--- a/chromium/cc/base/switches.h
+++ b/chromium/cc/base/switches.h
@@ -28,7 +28,6 @@ CC_BASE_EXPORT extern const char kStrictLayerPropertyChangeChecking[];
CC_BASE_EXPORT extern const char kEnableTileCompression[];
// Switches for both the renderer and ui compositors.
-CC_BASE_EXPORT extern const char kEnableColorCorrectRendering[];
CC_BASE_EXPORT extern const char kEnableGpuBenchmarking[];
CC_BASE_EXPORT extern const char kEnableSurfaceSynchronization[];
@@ -53,10 +52,11 @@ CC_BASE_EXPORT extern const char kCompositedRenderPassBorders[];
CC_BASE_EXPORT extern const char kCompositedSurfaceBorders[];
CC_BASE_EXPORT extern const char kCompositedLayerBorders[];
-// Unit test related.
+// Test related.
CC_BASE_EXPORT extern const char kCCLayerTreeTestNoTimeout[];
CC_BASE_EXPORT extern const char kCCLayerTreeTestLongTimeout[];
CC_BASE_EXPORT extern const char kCCRebaselinePixeltests[];
+CC_BASE_EXPORT extern const char kDisallowNonExactResourceReuse[];
} // namespace switches
} // namespace cc
diff --git a/chromium/cc/benchmarks/rasterize_and_record_benchmark.cc b/chromium/cc/benchmarks/rasterize_and_record_benchmark.cc
index 6314fdef87e..c19dac1e6d3 100644
--- a/chromium/cc/benchmarks/rasterize_and_record_benchmark.cc
+++ b/chromium/cc/benchmarks/rasterize_and_record_benchmark.cc
@@ -139,6 +139,7 @@ void RasterizeAndRecordBenchmark::RunOnLayer(PictureLayer* layer) {
return;
ContentLayerClient* painter = layer->client();
+ RecordingSource recording_source;
for (int mode_index = 0; mode_index < RecordingSource::RECORDING_MODE_COUNT;
mode_index++) {
@@ -158,11 +159,8 @@ void RasterizeAndRecordBenchmark::RunOnLayer(PictureLayer* layer) {
do {
display_list = painter->PaintContentsToDisplayList(painting_control);
- if (display_list->ShouldBeAnalyzedForSolidColor()) {
- gfx::Size layer_size = layer->paint_properties().bounds;
- skia::AnalysisCanvas canvas(layer_size.width(), layer_size.height());
- display_list->Raster(&canvas, nullptr, gfx::Rect(layer_size), 1.f);
- }
+ recording_source.UpdateDisplayItemList(
+ display_list, painter->GetApproximateUnsharedMemoryUsage());
if (memory_used) {
// Verify we are recording the same thing each time.
diff --git a/chromium/cc/benchmarks/unittest_only_benchmark.h b/chromium/cc/benchmarks/unittest_only_benchmark.h
index 277c4274dba..da95605dcc3 100644
--- a/chromium/cc/benchmarks/unittest_only_benchmark.h
+++ b/chromium/cc/benchmarks/unittest_only_benchmark.h
@@ -6,6 +6,7 @@
#define CC_BENCHMARKS_UNITTEST_ONLY_BENCHMARK_H_
#include "base/memory/weak_ptr.h"
+#include "base/single_thread_task_runner.h"
#include "cc/benchmarks/micro_benchmark.h"
namespace cc {
diff --git a/chromium/cc/blink/web_display_item_list_impl.cc b/chromium/cc/blink/web_display_item_list_impl.cc
index 889566b24ab..c1c47de0c9b 100644
--- a/chromium/cc/blink/web_display_item_list_impl.cc
+++ b/chromium/cc/blink/web_display_item_list_impl.cc
@@ -23,6 +23,7 @@
#include "third_party/skia/include/core/SkMatrix44.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/safe_integer_conversions.h"
+#include "ui/gfx/skia_util.h"
#include "ui/gfx/transform.h"
namespace cc_blink {
@@ -41,9 +42,10 @@ WebDisplayItemListImpl::WebDisplayItemListImpl(
void WebDisplayItemListImpl::AppendDrawingItem(
const blink::WebRect& visual_rect,
- sk_sp<const cc::PaintRecord> record) {
+ sk_sp<const cc::PaintRecord> record,
+ const blink::WebRect& record_bounds) {
display_item_list_->CreateAndAppendDrawingItem<cc::DrawingDisplayItem>(
- visual_rect, std::move(record));
+ visual_rect, std::move(record), gfx::RectToSkRect(record_bounds));
}
void WebDisplayItemListImpl::AppendClipItem(
diff --git a/chromium/cc/blink/web_display_item_list_impl.h b/chromium/cc/blink/web_display_item_list_impl.h
index b540f1cd563..e3fa9b87920 100644
--- a/chromium/cc/blink/web_display_item_list_impl.h
+++ b/chromium/cc/blink/web_display_item_list_impl.h
@@ -41,7 +41,8 @@ class WebDisplayItemListImpl : public blink::WebDisplayItemList {
// blink::WebDisplayItemList implementation.
void AppendDrawingItem(const blink::WebRect& visual_rect,
- sk_sp<const cc::PaintRecord> record) override;
+ sk_sp<const cc::PaintRecord> record,
+ const blink::WebRect& record_bounds) override;
void AppendClipItem(
const blink::WebRect& clip_rect,
const blink::WebVector<SkRRect>& rounded_clip_rects) override;
diff --git a/chromium/cc/blink/web_image_layer_impl.cc b/chromium/cc/blink/web_image_layer_impl.cc
index f9ab77718d8..7c965e79e71 100644
--- a/chromium/cc/blink/web_image_layer_impl.cc
+++ b/chromium/cc/blink/web_image_layer_impl.cc
@@ -22,11 +22,12 @@ blink::WebLayer* WebImageLayerImpl::Layer() {
return layer_.get();
}
-void WebImageLayerImpl::SetImage(const SkImage* image) {
- static_cast<cc::PictureImageLayer*>(layer_->layer())
- ->SetImage(sk_ref_sp(image));
+void WebImageLayerImpl::SetImage(cc::PaintImage image) {
static_cast<WebLayerImplFixedBounds*>(layer_.get())
- ->SetFixedBounds(gfx::Size(image->width(), image->height()));
+ ->SetFixedBounds(
+ gfx::Size(image.sk_image()->width(), image.sk_image()->height()));
+ static_cast<cc::PictureImageLayer*>(layer_->layer())
+ ->SetImage(std::move(image));
}
void WebImageLayerImpl::SetNearestNeighbor(bool nearest_neighbor) {
diff --git a/chromium/cc/blink/web_image_layer_impl.h b/chromium/cc/blink/web_image_layer_impl.h
index a6c3452e410..934bdfa1d97 100644
--- a/chromium/cc/blink/web_image_layer_impl.h
+++ b/chromium/cc/blink/web_image_layer_impl.h
@@ -9,6 +9,7 @@
#include "base/macros.h"
#include "cc/blink/cc_blink_export.h"
+#include "cc/paint/paint_image.h"
#include "third_party/WebKit/public/platform/WebImageLayer.h"
namespace cc_blink {
@@ -22,7 +23,7 @@ class WebImageLayerImpl : public blink::WebImageLayer {
// blink::WebImageLayer implementation.
blink::WebLayer* Layer() override;
- void SetImage(const SkImage* image) override;
+ void SetImage(cc::PaintImage image) override;
void SetNearestNeighbor(bool nearest_neighbor) override;
private:
diff --git a/chromium/cc/blink/web_layer_impl.cc b/chromium/cc/blink/web_layer_impl.cc
index e44d007e6ea..5526a70f430 100644
--- a/chromium/cc/blink/web_layer_impl.cc
+++ b/chromium/cc/blink/web_layer_impl.cc
@@ -299,10 +299,12 @@ WebVector<WebRect> WebLayerImpl::NonFastScrollableRegion() const {
return result;
}
-void WebLayerImpl::SetTouchEventHandlerRegion(const WebVector<WebRect>& rects) {
+void WebLayerImpl::SetTouchEventHandlerRegion(
+ const WebVector<blink::WebTouchInfo>& touch_info) {
cc::Region region;
- for (size_t i = 0; i < rects.size(); ++i)
- region.Union(rects[i]);
+ for (size_t i = 0; i < touch_info.size(); ++i)
+ region.Union(touch_info[i].rect);
+ // TODO(xidachen): set the touch action bit for the region.
layer_->SetTouchEventHandlerRegion(region);
}
diff --git a/chromium/cc/blink/web_layer_impl.h b/chromium/cc/blink/web_layer_impl.h
index 573bd2ff393..2cb948e4291 100644
--- a/chromium/cc/blink/web_layer_impl.h
+++ b/chromium/cc/blink/web_layer_impl.h
@@ -106,7 +106,7 @@ class CC_BLINK_EXPORT WebLayerImpl : public NON_EXPORTED_BASE(blink::WebLayer) {
const blink::WebVector<blink::WebRect>& region) override;
blink::WebVector<blink::WebRect> NonFastScrollableRegion() const override;
void SetTouchEventHandlerRegion(
- const blink::WebVector<blink::WebRect>& region) override;
+ const blink::WebVector<blink::WebTouchInfo>& touch_info) override;
blink::WebVector<blink::WebRect> TouchEventHandlerRegion() const override;
void SetIsContainerForFixedPositionLayers(bool is_container) override;
bool IsContainerForFixedPositionLayers() const override;
diff --git a/chromium/cc/blink/web_scrollbar_layer_impl.cc b/chromium/cc/blink/web_scrollbar_layer_impl.cc
index 2a3f2a12f17..0db9d0f5c5d 100644
--- a/chromium/cc/blink/web_scrollbar_layer_impl.cc
+++ b/chromium/cc/blink/web_scrollbar_layer_impl.cc
@@ -14,6 +14,7 @@
#include "cc/layers/painted_scrollbar_layer.h"
#include "cc/layers/scrollbar_layer_interface.h"
#include "cc/layers/solid_color_scrollbar_layer.h"
+#include "cc/trees/element_id.h"
using cc::PaintedOverlayScrollbarLayer;
using cc::PaintedScrollbarLayer;
@@ -41,12 +42,12 @@ WebScrollbarLayerImpl::WebScrollbarLayerImpl(
base::MakeUnique<ScrollbarImpl>(std::move(scrollbar),
painter,
std::move(geometry)),
- cc::Layer::INVALID_ID))
+ cc::ElementId()))
: new WebLayerImpl(PaintedScrollbarLayer::Create(
base::MakeUnique<ScrollbarImpl>(std::move(scrollbar),
painter,
std::move(geometry)),
- cc::Layer::INVALID_ID))) {}
+ cc::ElementId()))) {}
WebScrollbarLayerImpl::WebScrollbarLayerImpl(
blink::WebScrollbar::Orientation orientation,
@@ -58,7 +59,7 @@ WebScrollbarLayerImpl::WebScrollbarLayerImpl(
thumb_thickness,
track_start,
is_left_side_vertical_scrollbar,
- cc::Layer::INVALID_ID))) {}
+ cc::ElementId()))) {}
WebScrollbarLayerImpl::~WebScrollbarLayerImpl() {
}
@@ -69,9 +70,13 @@ blink::WebLayer* WebScrollbarLayerImpl::Layer() {
void WebScrollbarLayerImpl::SetScrollLayer(blink::WebLayer* layer) {
cc::Layer* scroll_layer =
- layer ? static_cast<WebLayerImpl*>(layer)->layer() : 0;
- layer_->layer()->ToScrollbarLayer()->SetScrollLayer(
- scroll_layer ? scroll_layer->id() : cc::Layer::INVALID_ID);
+ layer ? static_cast<WebLayerImpl*>(layer)->layer() : nullptr;
+ layer_->layer()->ToScrollbarLayer()->SetScrollElementId(
+ scroll_layer ? scroll_layer->element_id() : cc::ElementId());
+}
+
+void WebScrollbarLayerImpl::SetElementId(const cc::ElementId& element_id) {
+ layer_->SetElementId(element_id);
}
} // namespace cc_blink
diff --git a/chromium/cc/blink/web_scrollbar_layer_impl.h b/chromium/cc/blink/web_scrollbar_layer_impl.h
index 952277635c0..e8e0fe438aa 100644
--- a/chromium/cc/blink/web_scrollbar_layer_impl.h
+++ b/chromium/cc/blink/web_scrollbar_layer_impl.h
@@ -39,6 +39,8 @@ class WebScrollbarLayerImpl : public blink::WebScrollbarLayer {
blink::WebLayer* Layer() override;
void SetScrollLayer(blink::WebLayer* layer) override;
+ void SetElementId(const cc::ElementId&) override;
+
private:
std::unique_ptr<WebLayerImpl> layer_;
diff --git a/chromium/cc/debug/debug_colors.cc b/chromium/cc/debug/debug_colors.cc
index db0fbd70287..89e3d0bc3bb 100644
--- a/chromium/cc/debug/debug_colors.cc
+++ b/chromium/cc/debug/debug_colors.cc
@@ -78,7 +78,7 @@ SkColor DebugColors::HighResTileBorderColor() {
return SkColorSetARGB(100, 80, 200, 200);
}
int DebugColors::HighResTileBorderWidth(float device_scale_factor) {
- return Scale(1, device_scale_factor);
+ return Scale(3, device_scale_factor);
}
// Low-res tile borders are purple.
diff --git a/chromium/cc/input/browser_controls_offset_manager.h b/chromium/cc/input/browser_controls_offset_manager.h
index 88e76fa113d..ae4d9e4268f 100644
--- a/chromium/cc/input/browser_controls_offset_manager.h
+++ b/chromium/cc/input/browser_controls_offset_manager.h
@@ -8,7 +8,6 @@
#include <memory>
#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "cc/input/browser_controls_state.h"
#include "cc/layers/layer_impl.h"
@@ -20,8 +19,7 @@ namespace cc {
class BrowserControlsOffsetManagerClient;
// Manages the position of the browser controls.
-class CC_EXPORT BrowserControlsOffsetManager
- : public base::SupportsWeakPtr<BrowserControlsOffsetManager> {
+class CC_EXPORT BrowserControlsOffsetManager {
public:
enum AnimationDirection { NO_ANIMATION, SHOWING_CONTROLS, HIDING_CONTROLS };
diff --git a/chromium/cc/input/main_thread_scrolling_reason.h b/chromium/cc/input/main_thread_scrolling_reason.h
index a8c586eee95..e7d88471aff 100644
--- a/chromium/cc/input/main_thread_scrolling_reason.h
+++ b/chromium/cc/input/main_thread_scrolling_reason.h
@@ -44,7 +44,8 @@ struct MainThreadScrollingReason {
kHasBorderRadius = 1 << 19,
kHasClipRelatedProperty = 1 << 20,
kHasBoxShadowFromNonRootLayer = 1 << 21,
- kNonCompositedReasonsLast = 21,
+ kIsNotStackingContextAndLCDText = 1 << 22,
+ kNonCompositedReasonsLast = 22,
// Transient scrolling reasons. These are computed for each scroll begin.
kNonFastScrollableRegion = 1 << 5,
@@ -59,13 +60,14 @@ struct MainThreadScrollingReason {
// New flags should increment this number but it should never be decremented
// because the values are used in UMA histograms. It should also be noted
// that it excludes the kNotScrollingOnMain value.
- kMainThreadScrollingReasonCount = 22,
+ kMainThreadScrollingReasonCount = 23,
};
static const uint32_t kNonCompositedReasons =
kHasOpacityAndLCDText | kHasTransformAndLCDText |
kBackgroundNotOpaqueInRectAndLCDText | kHasBorderRadius |
- kHasClipRelatedProperty | kHasBoxShadowFromNonRootLayer;
+ kHasClipRelatedProperty | kHasBoxShadowFromNonRootLayer |
+ kIsNotStackingContextAndLCDText;
// Returns true if the given MainThreadScrollingReason can be set by the main
// thread.
@@ -140,6 +142,8 @@ struct MainThreadScrollingReason {
tracedValue->AppendString("Has clip related property");
if (reasons & MainThreadScrollingReason::kHasBoxShadowFromNonRootLayer)
tracedValue->AppendString("Has box shadow from non-root layer");
+ if (reasons & MainThreadScrollingReason::kIsNotStackingContextAndLCDText)
+ tracedValue->AppendString("Is not stacking context and LCD text");
// Transient scrolling reasons.
if (reasons & MainThreadScrollingReason::kNonFastScrollableRegion)
diff --git a/chromium/cc/input/scrollbar_animation_controller.cc b/chromium/cc/input/scrollbar_animation_controller.cc
index 8fb3c25a48b..6234d3ce53f 100644
--- a/chromium/cc/input/scrollbar_animation_controller.cc
+++ b/chromium/cc/input/scrollbar_animation_controller.cc
@@ -13,86 +13,82 @@ namespace cc {
std::unique_ptr<ScrollbarAnimationController>
ScrollbarAnimationController::CreateScrollbarAnimationControllerAndroid(
- int scroll_layer_id,
+ ElementId scroll_element_id,
ScrollbarAnimationControllerClient* client,
base::TimeDelta fade_delay,
- base::TimeDelta fade_out_resize_delay,
- base::TimeDelta fade_duration) {
- return base::WrapUnique(
- new ScrollbarAnimationController(scroll_layer_id, client, fade_delay,
- fade_out_resize_delay, fade_duration));
+ base::TimeDelta fade_duration,
+ float initial_opacity) {
+ return base::WrapUnique(new ScrollbarAnimationController(
+ scroll_element_id, client, fade_delay, fade_duration, initial_opacity));
}
std::unique_ptr<ScrollbarAnimationController>
ScrollbarAnimationController::CreateScrollbarAnimationControllerAuraOverlay(
- int scroll_layer_id,
+ ElementId scroll_element_id,
ScrollbarAnimationControllerClient* client,
base::TimeDelta fade_delay,
- base::TimeDelta fade_out_resize_delay,
base::TimeDelta fade_duration,
- base::TimeDelta thinning_duration) {
+ base::TimeDelta thinning_duration,
+ float initial_opacity) {
return base::WrapUnique(new ScrollbarAnimationController(
- scroll_layer_id, client, fade_delay, fade_out_resize_delay,
- fade_duration, thinning_duration));
+ scroll_element_id, client, fade_delay, fade_duration, thinning_duration,
+ initial_opacity));
}
ScrollbarAnimationController::ScrollbarAnimationController(
- int scroll_layer_id,
+ ElementId scroll_element_id,
ScrollbarAnimationControllerClient* client,
base::TimeDelta fade_delay,
- base::TimeDelta fade_out_resize_delay,
- base::TimeDelta fade_duration)
+ base::TimeDelta fade_duration,
+ float initial_opacity)
: client_(client),
fade_delay_(fade_delay),
- fade_out_resize_delay_(fade_out_resize_delay),
fade_duration_(fade_duration),
- need_trigger_scrollbar_show_(false),
+ need_trigger_scrollbar_fade_in_(false),
is_animating_(false),
animation_change_(NONE),
- scroll_layer_id_(scroll_layer_id),
+ scroll_element_id_(scroll_element_id),
currently_scrolling_(false),
show_in_fast_scroll_(false),
- opacity_(0.0f),
+ opacity_(initial_opacity),
show_scrollbars_on_scroll_gesture_(false),
need_thinning_animation_(false),
- weak_factory_(this) {
- ApplyOpacityToScrollbars(0.0f);
-}
+ is_mouse_down_(false),
+ weak_factory_(this) {}
ScrollbarAnimationController::ScrollbarAnimationController(
- int scroll_layer_id,
+ ElementId scroll_element_id,
ScrollbarAnimationControllerClient* client,
base::TimeDelta fade_delay,
- base::TimeDelta fade_out_resize_delay,
base::TimeDelta fade_duration,
- base::TimeDelta thinning_duration)
+ base::TimeDelta thinning_duration,
+ float initial_opacity)
: client_(client),
fade_delay_(fade_delay),
- fade_out_resize_delay_(fade_out_resize_delay),
fade_duration_(fade_duration),
- need_trigger_scrollbar_show_(false),
+ need_trigger_scrollbar_fade_in_(false),
is_animating_(false),
animation_change_(NONE),
- scroll_layer_id_(scroll_layer_id),
+ scroll_element_id_(scroll_element_id),
currently_scrolling_(false),
show_in_fast_scroll_(false),
- opacity_(0.0f),
+ opacity_(initial_opacity),
show_scrollbars_on_scroll_gesture_(true),
need_thinning_animation_(true),
+ is_mouse_down_(false),
weak_factory_(this) {
vertical_controller_ = SingleScrollbarAnimationControllerThinning::Create(
- scroll_layer_id, ScrollbarOrientation::VERTICAL, client,
+ scroll_element_id, ScrollbarOrientation::VERTICAL, client,
thinning_duration);
horizontal_controller_ = SingleScrollbarAnimationControllerThinning::Create(
- scroll_layer_id, ScrollbarOrientation::HORIZONTAL, client,
+ scroll_element_id, ScrollbarOrientation::HORIZONTAL, client,
thinning_duration);
- ApplyOpacityToScrollbars(0.0f);
}
ScrollbarAnimationController::~ScrollbarAnimationController() {}
ScrollbarSet ScrollbarAnimationController::Scrollbars() const {
- return client_->ScrollbarsFor(scroll_layer_id_);
+ return client_->ScrollbarsFor(scroll_element_id_);
}
SingleScrollbarAnimationControllerThinning&
@@ -108,6 +104,7 @@ ScrollbarAnimationController::GetScrollbarAnimationController(
void ScrollbarAnimationController::StartAnimation() {
DCHECK(animation_change_ != NONE);
delayed_scrollbar_animation_.Cancel();
+ need_trigger_scrollbar_fade_in_ = false;
is_animating_ = true;
last_awaken_time_ = base::TimeTicks();
client_->SetNeedsAnimateForScrollbarAnimation();
@@ -115,23 +112,20 @@ void ScrollbarAnimationController::StartAnimation() {
void ScrollbarAnimationController::StopAnimation() {
delayed_scrollbar_animation_.Cancel();
+ need_trigger_scrollbar_fade_in_ = false;
is_animating_ = false;
animation_change_ = NONE;
}
void ScrollbarAnimationController::PostDelayedAnimation(
- AnimationChange animation_change,
- bool on_resize) {
+ AnimationChange animation_change) {
animation_change_ = animation_change;
-
- base::TimeDelta delay = on_resize ? fade_out_resize_delay_ : fade_delay_;
-
delayed_scrollbar_animation_.Cancel();
delayed_scrollbar_animation_.Reset(
base::Bind(&ScrollbarAnimationController::StartAnimation,
weak_factory_.GetWeakPtr()));
client_->PostDelayedScrollbarAnimationTask(
- delayed_scrollbar_animation_.callback(), delay);
+ delayed_scrollbar_animation_.callback(), fade_delay_);
}
bool ScrollbarAnimationController::Animate(base::TimeTicks now) {
@@ -196,7 +190,7 @@ void ScrollbarAnimationController::DidScrollEnd() {
return;
if (has_scrolled)
- PostDelayedAnimation(FADE_OUT, false);
+ PostDelayedAnimation(FADE_OUT);
}
void ScrollbarAnimationController::DidScrollUpdate() {
@@ -213,7 +207,7 @@ void ScrollbarAnimationController::DidScrollUpdate() {
// We don't fade out scrollbar if they need thinning animation and mouse is
// near.
if (!need_thinning_animation_ || !MouseIsNearAnyScrollbar())
- PostDelayedAnimation(FADE_OUT, false);
+ PostDelayedAnimation(FADE_OUT);
} else {
show_in_fast_scroll_ = true;
}
@@ -230,39 +224,46 @@ void ScrollbarAnimationController::WillUpdateScroll() {
}
void ScrollbarAnimationController::DidRequestShowFromMainThread() {
- // TODO(skobes): Call DidScrollUpdate here (suppressed for crbug.com/706927).
+ DidScrollUpdate();
}
-void ScrollbarAnimationController::DidResize() {
- StopAnimation();
- Show();
+void ScrollbarAnimationController::DidMouseDown() {
+ if (!need_thinning_animation_)
+ return;
- // As an optimization, we avoid spamming fade delay tasks during active fast
- // scrolls.
- if (!currently_scrolling_) {
- PostDelayedAnimation(FADE_OUT, true);
- } else {
- show_in_fast_scroll_ = true;
- }
-}
+ is_mouse_down_ = true;
-void ScrollbarAnimationController::DidMouseDown() {
- if (!need_thinning_animation_ || ScrollbarsHidden())
+ if (ScrollbarsHidden()) {
+ if (need_trigger_scrollbar_fade_in_) {
+ delayed_scrollbar_animation_.Cancel();
+ need_trigger_scrollbar_fade_in_ = false;
+ }
return;
+ }
vertical_controller_->DidMouseDown();
horizontal_controller_->DidMouseDown();
}
void ScrollbarAnimationController::DidMouseUp() {
- if (!need_thinning_animation_ || !Captured())
+ if (!need_thinning_animation_)
return;
+ is_mouse_down_ = false;
+
+ if (!Captured()) {
+ if (MouseIsNearAnyScrollbar() && ScrollbarsHidden()) {
+ PostDelayedAnimation(FADE_IN);
+ need_trigger_scrollbar_fade_in_ = true;
+ }
+ return;
+ }
+
vertical_controller_->DidMouseUp();
horizontal_controller_->DidMouseUp();
- if (!MouseIsNearAnyScrollbar())
- PostDelayedAnimation(FADE_OUT, false);
+ if (!MouseIsNearAnyScrollbar() && !ScrollbarsHidden())
+ PostDelayedAnimation(FADE_OUT);
}
void ScrollbarAnimationController::DidMouseLeave() {
@@ -273,34 +274,39 @@ void ScrollbarAnimationController::DidMouseLeave() {
horizontal_controller_->DidMouseLeave();
delayed_scrollbar_animation_.Cancel();
- need_trigger_scrollbar_show_ = false;
+ need_trigger_scrollbar_fade_in_ = false;
if (ScrollbarsHidden() || Captured())
return;
- PostDelayedAnimation(FADE_OUT, false);
+ PostDelayedAnimation(FADE_OUT);
}
-void ScrollbarAnimationController::DidMouseMoveNear(
- ScrollbarOrientation orientation,
- float distance) {
+void ScrollbarAnimationController::DidMouseMove(
+ const gfx::PointF& device_viewport_point) {
if (!need_thinning_animation_)
return;
- bool need_trigger_scrollbar_show_before = need_trigger_scrollbar_show_;
+ bool need_trigger_scrollbar_fade_in_before = need_trigger_scrollbar_fade_in_;
- GetScrollbarAnimationController(orientation).DidMouseMoveNear(distance);
+ vertical_controller_->DidMouseMove(device_viewport_point);
+ horizontal_controller_->DidMouseMove(device_viewport_point);
- need_trigger_scrollbar_show_ =
- CalcNeedTriggerScrollbarShow(orientation, distance);
-
- if (Captured())
+ if (Captured()) {
+ DCHECK(!ScrollbarsHidden());
return;
+ }
if (ScrollbarsHidden()) {
- if (need_trigger_scrollbar_show_before != need_trigger_scrollbar_show_) {
- if (need_trigger_scrollbar_show_) {
- PostDelayedAnimation(FADE_IN, false);
+ // Do not fade in scrollbar when user interacting with the content below
+ // scrollbar.
+ if (is_mouse_down_)
+ return;
+ need_trigger_scrollbar_fade_in_ = MouseIsNearAnyScrollbar();
+ if (need_trigger_scrollbar_fade_in_before !=
+ need_trigger_scrollbar_fade_in_) {
+ if (need_trigger_scrollbar_fade_in_) {
+ PostDelayedAnimation(FADE_IN);
} else {
delayed_scrollbar_animation_.Cancel();
}
@@ -310,47 +316,36 @@ void ScrollbarAnimationController::DidMouseMoveNear(
Show();
StopAnimation();
} else if (!is_animating_) {
- PostDelayedAnimation(FADE_OUT, false);
+ PostDelayedAnimation(FADE_OUT);
}
}
}
-bool ScrollbarAnimationController::CalcNeedTriggerScrollbarShow(
- ScrollbarOrientation orientation,
- float distance) const {
+bool ScrollbarAnimationController::MouseIsOverScrollbarThumb(
+ ScrollbarOrientation orientation) const {
DCHECK(need_thinning_animation_);
-
- if (vertical_controller_->mouse_is_over_scrollbar() ||
- horizontal_controller_->mouse_is_over_scrollbar())
- return true;
-
- for (ScrollbarLayerImplBase* scrollbar : Scrollbars()) {
- if (scrollbar->orientation() != orientation)
- continue;
-
- if (distance < kMouseMoveDistanceToTriggerFadeIn)
- return true;
- }
-
- return false;
+ return GetScrollbarAnimationController(orientation)
+ .mouse_is_over_scrollbar_thumb();
}
-bool ScrollbarAnimationController::MouseIsOverScrollbar(
+bool ScrollbarAnimationController::MouseIsNearScrollbarThumb(
ScrollbarOrientation orientation) const {
DCHECK(need_thinning_animation_);
- return GetScrollbarAnimationController(orientation).mouse_is_over_scrollbar();
+ return GetScrollbarAnimationController(orientation)
+ .mouse_is_near_scrollbar_thumb();
}
bool ScrollbarAnimationController::MouseIsNearScrollbar(
ScrollbarOrientation orientation) const {
DCHECK(need_thinning_animation_);
- return GetScrollbarAnimationController(orientation).mouse_is_near_scrollbar();
+ return GetScrollbarAnimationController(orientation)
+ .mouse_is_near_scrollbar_track();
}
bool ScrollbarAnimationController::MouseIsNearAnyScrollbar() const {
DCHECK(need_thinning_animation_);
- return vertical_controller_->mouse_is_near_scrollbar() ||
- horizontal_controller_->mouse_is_near_scrollbar();
+ return vertical_controller_->mouse_is_near_scrollbar_track() ||
+ horizontal_controller_->mouse_is_near_scrollbar_track();
}
bool ScrollbarAnimationController::ScrollbarsHidden() const {
@@ -359,7 +354,8 @@ bool ScrollbarAnimationController::ScrollbarsHidden() const {
bool ScrollbarAnimationController::Captured() const {
DCHECK(need_thinning_animation_);
- return vertical_controller_->captured() || horizontal_controller_->captured();
+ return GetScrollbarAnimationController(VERTICAL).captured() ||
+ GetScrollbarAnimationController(HORIZONTAL).captured();
}
void ScrollbarAnimationController::Show() {
@@ -369,8 +365,7 @@ void ScrollbarAnimationController::Show() {
void ScrollbarAnimationController::ApplyOpacityToScrollbars(float opacity) {
for (ScrollbarLayerImplBase* scrollbar : Scrollbars()) {
- if (!scrollbar->is_overlay_scrollbar())
- continue;
+ DCHECK(scrollbar->is_overlay_scrollbar());
float effective_opacity = scrollbar->CanScrollOrientation() ? opacity : 0;
scrollbar->SetOverlayScrollbarLayerOpacityAnimated(effective_opacity);
}
diff --git a/chromium/cc/input/scrollbar_animation_controller.h b/chromium/cc/input/scrollbar_animation_controller.h
index 60676d95044..64bf2b6ac06 100644
--- a/chromium/cc/input/scrollbar_animation_controller.h
+++ b/chromium/cc/input/scrollbar_animation_controller.h
@@ -23,7 +23,7 @@ class CC_EXPORT ScrollbarAnimationControllerClient {
virtual void SetNeedsRedrawForScrollbarAnimation() = 0;
virtual void SetNeedsAnimateForScrollbarAnimation() = 0;
virtual void DidChangeScrollbarVisibility() = 0;
- virtual ScrollbarSet ScrollbarsFor(int scroll_layer_id) const = 0;
+ virtual ScrollbarSet ScrollbarsFor(ElementId scroll_element_id) const = 0;
protected:
virtual ~ScrollbarAnimationControllerClient() {}
@@ -41,22 +41,22 @@ class CC_EXPORT ScrollbarAnimationController {
// animation.
static std::unique_ptr<ScrollbarAnimationController>
CreateScrollbarAnimationControllerAndroid(
- int scroll_layer_id,
+ ElementId scroll_element_id,
ScrollbarAnimationControllerClient* client,
base::TimeDelta fade_delay,
- base::TimeDelta fade_out_resize_delay,
- base::TimeDelta fade_duration);
+ base::TimeDelta fade_duration,
+ float initial_opacity);
// ScrollbarAnimationController for Desktop Overlay Scrollbar. It has show &
// fade out animation and thinning animation.
static std::unique_ptr<ScrollbarAnimationController>
CreateScrollbarAnimationControllerAuraOverlay(
- int scroll_layer_id,
+ ElementId scroll_element_id,
ScrollbarAnimationControllerClient* client,
base::TimeDelta fade_delay,
- base::TimeDelta fade_out_resize_delay,
base::TimeDelta fade_duration,
- base::TimeDelta thinning_duration);
+ base::TimeDelta thinning_duration,
+ float initial_opacity);
~ScrollbarAnimationController();
@@ -72,46 +72,45 @@ class CC_EXPORT ScrollbarAnimationController {
// Effect both Android and Aura Overlay Scrollbar.
void DidScrollUpdate();
- // DidResize expects to be called when clip layer size changed or scroll layer
- // size changed.
- void DidResize();
-
void DidScrollBegin();
void DidScrollEnd();
void DidMouseDown();
void DidMouseUp();
void DidMouseLeave();
- void DidMouseMoveNear(ScrollbarOrientation, float);
+ void DidMouseMove(const gfx::PointF& device_viewport_point);
// Called when Blink wants to show the scrollbars (via
// ScrollableArea::showOverlayScrollbars).
void DidRequestShowFromMainThread();
- bool MouseIsOverScrollbar(ScrollbarOrientation orientation) const;
+ // These methods are public for testing.
+ bool MouseIsOverScrollbarThumb(ScrollbarOrientation orientation) const;
+ bool MouseIsNearScrollbarThumb(ScrollbarOrientation orientation) const;
bool MouseIsNearScrollbar(ScrollbarOrientation orientation) const;
bool MouseIsNearAnyScrollbar() const;
+ ScrollbarSet Scrollbars() const;
+
static constexpr float kMouseMoveDistanceToTriggerFadeIn = 30.0f;
private:
// Describes whether the current animation should FadeIn or FadeOut.
enum AnimationChange { NONE, FADE_IN, FADE_OUT };
- ScrollbarAnimationController(int scroll_layer_id,
+ ScrollbarAnimationController(ElementId scroll_element_id,
ScrollbarAnimationControllerClient* client,
base::TimeDelta fade_delay,
- base::TimeDelta fade_out_resize_delay,
- base::TimeDelta fade_duration);
+ base::TimeDelta fade_duration,
+ float initial_opacity);
- ScrollbarAnimationController(int scroll_layer_id,
+ ScrollbarAnimationController(ElementId scroll_element_id,
ScrollbarAnimationControllerClient* client,
base::TimeDelta fade_delay,
- base::TimeDelta fade_out_resize_delay,
base::TimeDelta fade_duration,
- base::TimeDelta thinning_duration);
+ base::TimeDelta thinning_duration,
+ float initial_opacity);
- ScrollbarSet Scrollbars() const;
SingleScrollbarAnimationControllerThinning& GetScrollbarAnimationController(
ScrollbarOrientation) const;
@@ -125,13 +124,10 @@ class CC_EXPORT ScrollbarAnimationController {
void Show();
- void PostDelayedAnimation(AnimationChange animation_change, bool on_resize);
+ void PostDelayedAnimation(AnimationChange animation_change);
bool Captured() const;
- bool CalcNeedTriggerScrollbarShow(ScrollbarOrientation orientation,
- float distance) const;
-
void ApplyOpacityToScrollbars(float opacity);
ScrollbarAnimationControllerClient* client_;
@@ -139,16 +135,15 @@ class CC_EXPORT ScrollbarAnimationController {
base::TimeTicks last_awaken_time_;
base::TimeDelta fade_delay_;
- base::TimeDelta fade_out_resize_delay_;
base::TimeDelta fade_duration_;
- bool need_trigger_scrollbar_show_;
+ bool need_trigger_scrollbar_fade_in_;
bool is_animating_;
AnimationChange animation_change_;
- const int scroll_layer_id_;
+ const ElementId scroll_element_id_;
bool currently_scrolling_;
bool show_in_fast_scroll_;
@@ -158,6 +153,9 @@ class CC_EXPORT ScrollbarAnimationController {
const bool show_scrollbars_on_scroll_gesture_;
const bool need_thinning_animation_;
+
+ bool is_mouse_down_;
+
std::unique_ptr<SingleScrollbarAnimationControllerThinning>
vertical_controller_;
std::unique_ptr<SingleScrollbarAnimationControllerThinning>
diff --git a/chromium/cc/input/scrollbar_animation_controller_unittest.cc b/chromium/cc/input/scrollbar_animation_controller_unittest.cc
index ebb22757703..e7e4926c3e5 100644
--- a/chromium/cc/input/scrollbar_animation_controller_unittest.cc
+++ b/chromium/cc/input/scrollbar_animation_controller_unittest.cc
@@ -23,11 +23,11 @@ namespace {
const float kIdleThicknessScale =
SingleScrollbarAnimationControllerThinning::kIdleThicknessScale;
-const float kDefaultMouseMoveDistanceToTriggerAnimation =
- SingleScrollbarAnimationControllerThinning::
- kDefaultMouseMoveDistanceToTriggerAnimation;
const float kMouseMoveDistanceToTriggerFadeIn =
ScrollbarAnimationController::kMouseMoveDistanceToTriggerFadeIn;
+const float kMouseMoveDistanceToTriggerExpand =
+ SingleScrollbarAnimationControllerThinning::
+ kMouseMoveDistanceToTriggerExpand;
const int kThumbThickness = 10;
class MockScrollbarAnimationControllerClient
@@ -44,8 +44,8 @@ class MockScrollbarAnimationControllerClient
}
void SetNeedsRedrawForScrollbarAnimation() override {}
void SetNeedsAnimateForScrollbarAnimation() override {}
- ScrollbarSet ScrollbarsFor(int scroll_layer_id) const override {
- return host_impl_->ScrollbarsFor(scroll_layer_id);
+ ScrollbarSet ScrollbarsFor(ElementId scroll_element_id) const override {
+ return host_impl_->ScrollbarsFor(scroll_element_id);
}
MOCK_METHOD0(DidChangeScrollbarVisibility, void());
@@ -71,7 +71,6 @@ class ScrollbarAnimationControllerAuraOverlayTest : public testing::Test {
protected:
const base::TimeDelta kFadeDelay = base::TimeDelta::FromSeconds(4);
- const base::TimeDelta kResizeFadeOutDelay = base::TimeDelta::FromSeconds(5);
const base::TimeDelta kFadeDuration = base::TimeDelta::FromSeconds(3);
const base::TimeDelta kThinningDuration = base::TimeDelta::FromSeconds(2);
@@ -81,10 +80,13 @@ class ScrollbarAnimationControllerAuraOverlayTest : public testing::Test {
std::unique_ptr<LayerImpl> clip =
LayerImpl::Create(host_impl_.active_tree(), 2);
clip_layer_ = clip.get();
+ scroll_layer->SetElementId(
+ LayerIdToElementIdForTesting(scroll_layer->id()));
scroll_layer->SetScrollClipLayer(clip_layer_->id());
LayerImpl* scroll_layer_ptr = scroll_layer.get();
const int kTrackStart = 0;
+ const int kTrackLength = 100;
const bool kIsLeftSideVerticalScrollbar = false;
const bool kIsOverlayScrollbar = true;
@@ -92,10 +94,12 @@ class ScrollbarAnimationControllerAuraOverlayTest : public testing::Test {
SolidColorScrollbarLayerImpl::Create(
host_impl_.active_tree(), 3, HORIZONTAL, kThumbThickness,
kTrackStart, kIsLeftSideVerticalScrollbar, kIsOverlayScrollbar);
+ h_scrollbar->test_properties()->opacity = 0.0f;
std::unique_ptr<SolidColorScrollbarLayerImpl> v_scrollbar =
SolidColorScrollbarLayerImpl::Create(
host_impl_.active_tree(), 4, VERTICAL, kThumbThickness, kTrackStart,
kIsLeftSideVerticalScrollbar, kIsOverlayScrollbar);
+ v_scrollbar->test_properties()->opacity = 0.0f;
v_scrollbar_layer_ = v_scrollbar.get();
h_scrollbar_layer_ = h_scrollbar.get();
@@ -104,18 +108,48 @@ class ScrollbarAnimationControllerAuraOverlayTest : public testing::Test {
clip_layer_->test_properties()->AddChild(std::move(scroll_layer));
host_impl_.active_tree()->SetRootLayerForTesting(std::move(clip));
- v_scrollbar_layer_->SetScrollLayerId(scroll_layer_ptr->id());
- h_scrollbar_layer_->SetScrollLayerId(scroll_layer_ptr->id());
+ v_scrollbar_layer_->SetBounds(gfx::Size(kThumbThickness, kTrackLength));
+ v_scrollbar_layer_->SetPosition(gfx::PointF(90, 0));
+ v_scrollbar_layer_->SetScrollElementId(scroll_layer_ptr->element_id());
v_scrollbar_layer_->test_properties()->opacity_can_animate = true;
+
+ h_scrollbar_layer_->SetBounds(gfx::Size(kTrackLength, kThumbThickness));
+ h_scrollbar_layer_->SetPosition(gfx::PointF(0, 90));
+ h_scrollbar_layer_->SetScrollElementId(scroll_layer_ptr->element_id());
h_scrollbar_layer_->test_properties()->opacity_can_animate = true;
+
clip_layer_->SetBounds(gfx::Size(100, 100));
scroll_layer_ptr->SetBounds(gfx::Size(200, 200));
host_impl_.active_tree()->BuildLayerListAndPropertyTreesForTesting();
scrollbar_controller_ = ScrollbarAnimationController::
CreateScrollbarAnimationControllerAuraOverlay(
- scroll_layer_ptr->id(), &client_, kFadeDelay,
- kResizeFadeOutDelay, kFadeDuration, kThinningDuration);
+ scroll_layer_ptr->element_id(), &client_, kFadeDelay, kFadeDuration,
+ kThinningDuration, 0.0f);
+ v_scrollbar_layer_->SetCurrentPos(0);
+ h_scrollbar_layer_->SetCurrentPos(0);
+ }
+
+ // Return a point with given offset from the top-left of vertical scrollbar.
+ gfx::PointF NearVerticalScrollbarBegin(float offset_x, float offset_y) {
+ gfx::PointF p(90, 0);
+ p.Offset(offset_x, offset_y);
+ return p;
+ }
+
+ // Return a point with given offset from the bottom-left of vertical
+ // scrollbar.
+ gfx::PointF NearVerticalScrollbarEnd(float offset_x, float offset_y) {
+ gfx::PointF p(90, 90);
+ p.Offset(offset_x, offset_y);
+ return p;
+ }
+
+ // Return a point with given offset from the top-left of horizontal scrollbar.
+ gfx::PointF NearHorizontalScrollbarBegin(float offset_x, float offset_y) {
+ gfx::PointF p(0, 90);
+ p.Offset(offset_x, offset_y);
+ return p;
}
FakeImplTaskRunnerProvider task_runner_provider_;
@@ -257,8 +291,70 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
EXPECT_TRUE(scrollbar_controller_->ScrollbarsHidden());
}
-// Scroll content. Move the mouse near the scrollbar and confirm it becomes
-// thick. Ensure it remains visible as long as the mouse is near the scrollbar.
+// Scroll content. Move the mouse near the scrollbar track but not near thumb
+// and confirm it stay thin. Move the mouse near the scrollbar thumb and
+// confirm it becomes thick.
+TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
+ MoveNearTrackThenNearThumb) {
+ base::TimeTicks time;
+ time += base::TimeDelta::FromSeconds(1);
+
+ scrollbar_controller_->DidScrollBegin();
+ scrollbar_controller_->DidScrollUpdate();
+ scrollbar_controller_->DidScrollEnd();
+
+ // An fade out animation should have been enqueued.
+ EXPECT_EQ(kFadeDelay, client_.delay());
+ EXPECT_FALSE(client_.start_fade().is_null());
+ EXPECT_FALSE(client_.start_fade().IsCancelled());
+
+ // Now move the mouse near the vertical scrollbar track. This should cancel
+ // the currently queued fading animation and stay scrollbar thin.
+ scrollbar_controller_->DidMouseMove(NearVerticalScrollbarEnd(-1, 0));
+ ExpectScrollbarsOpacity(1);
+ EXPECT_FLOAT_EQ(kIdleThicknessScale,
+ v_scrollbar_layer_->thumb_thickness_scale_factor());
+ EXPECT_FLOAT_EQ(kIdleThicknessScale,
+ h_scrollbar_layer_->thumb_thickness_scale_factor());
+ EXPECT_TRUE(client_.start_fade().IsCancelled());
+
+ scrollbar_controller_->Animate(time);
+ time += kThinningDuration;
+ scrollbar_controller_->Animate(time);
+
+ EXPECT_FLOAT_EQ(kIdleThicknessScale,
+ v_scrollbar_layer_->thumb_thickness_scale_factor());
+ EXPECT_FLOAT_EQ(kIdleThicknessScale,
+ h_scrollbar_layer_->thumb_thickness_scale_factor());
+
+ scrollbar_controller_->DidMouseMove(NearVerticalScrollbarBegin(-1, 0));
+ scrollbar_controller_->Animate(time);
+ time += kThinningDuration;
+ scrollbar_controller_->Animate(time);
+
+ EXPECT_FLOAT_EQ(1, v_scrollbar_layer_->thumb_thickness_scale_factor());
+ EXPECT_FLOAT_EQ(kIdleThicknessScale,
+ h_scrollbar_layer_->thumb_thickness_scale_factor());
+
+ scrollbar_controller_->DidMouseMove(NearVerticalScrollbarEnd(-1, 0));
+ EXPECT_FLOAT_EQ(1, v_scrollbar_layer_->thumb_thickness_scale_factor());
+ EXPECT_FLOAT_EQ(kIdleThicknessScale,
+ h_scrollbar_layer_->thumb_thickness_scale_factor());
+ EXPECT_TRUE(client_.start_fade().IsCancelled());
+
+ scrollbar_controller_->Animate(time);
+ time += kThinningDuration;
+ scrollbar_controller_->Animate(time);
+
+ EXPECT_FLOAT_EQ(kIdleThicknessScale,
+ v_scrollbar_layer_->thumb_thickness_scale_factor());
+ EXPECT_FLOAT_EQ(kIdleThicknessScale,
+ h_scrollbar_layer_->thumb_thickness_scale_factor());
+}
+
+// Scroll content. Move the mouse near the scrollbar thumb and confirm it
+// becomes thick. Ensure it remains visible as long as the mouse is near the
+// scrollbar.
TEST_F(ScrollbarAnimationControllerAuraOverlayTest, MoveNearAndDontFadeOut) {
base::TimeTicks time;
time += base::TimeDelta::FromSeconds(1);
@@ -272,9 +368,9 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, MoveNearAndDontFadeOut) {
EXPECT_FALSE(client_.start_fade().is_null());
EXPECT_FALSE(client_.start_fade().IsCancelled());
- // Now move the mouse near the scrollbar. This should cancel the currently
- // queued fading animation and start animating thickness.
- scrollbar_controller_->DidMouseMoveNear(VERTICAL, 1);
+ // Now move the mouse near the vertical scrollbar thumb. This should cancel
+ // the currently queued fading animation and start animating thickness.
+ scrollbar_controller_->DidMouseMove(NearVerticalScrollbarBegin(-1, 0));
ExpectScrollbarsOpacity(1);
EXPECT_FLOAT_EQ(kIdleThicknessScale,
v_scrollbar_layer_->thumb_thickness_scale_factor());
@@ -313,9 +409,9 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, MoveOverAndDontFadeOut) {
EXPECT_FALSE(client_.start_fade().is_null());
EXPECT_FALSE(client_.start_fade().IsCancelled());
- // Now move the mouse over the scrollbar. This should cancel the currently
- // queued fading animation and start animating thickness.
- scrollbar_controller_->DidMouseMoveNear(VERTICAL, 0);
+ // Now move the mouse over the vertical scrollbar thumb. This should cancel
+ // the currently queued fading animation and start animating thickness.
+ scrollbar_controller_->DidMouseMove(NearVerticalScrollbarBegin(0, 0));
ExpectScrollbarsOpacity(1);
EXPECT_FLOAT_EQ(kIdleThicknessScale,
v_scrollbar_layer_->thumb_thickness_scale_factor());
@@ -354,9 +450,9 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
EXPECT_EQ(kFadeDelay, client_.delay());
EXPECT_FALSE(client_.start_fade().is_null());
- // Now move the mouse over the scrollbar and capture it. It should become
- // thick without need for an animation.
- scrollbar_controller_->DidMouseMoveNear(VERTICAL, 0);
+ // Now move the mouse over the vertical scrollbar thumb and capture it. It
+ // should become thick without need for an animation.
+ scrollbar_controller_->DidMouseMove(NearVerticalScrollbarBegin(0, 0));
scrollbar_controller_->DidMouseDown();
ExpectScrollbarsOpacity(1);
EXPECT_FLOAT_EQ(1, v_scrollbar_layer_->thumb_thickness_scale_factor());
@@ -382,9 +478,9 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
EXPECT_EQ(kFadeDelay, client_.delay());
EXPECT_FALSE(client_.start_fade().is_null());
- // Now move the mouse over the scrollbar and capture it. It should become
- // thick without need for an animation.
- scrollbar_controller_->DidMouseMoveNear(VERTICAL, 0);
+ // Now move the mouse over the vertical scrollbar and capture it. It should
+ // become thick without need for an animation.
+ scrollbar_controller_->DidMouseMove(NearVerticalScrollbarBegin(0, 0));
scrollbar_controller_->DidMouseDown();
ExpectScrollbarsOpacity(1);
EXPECT_FLOAT_EQ(1, v_scrollbar_layer_->thumb_thickness_scale_factor());
@@ -397,8 +493,8 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
// Then move mouse away, The fade out animation should have been cleared or
// cancelled.
- scrollbar_controller_->DidMouseMoveNear(
- VERTICAL, kDefaultMouseMoveDistanceToTriggerAnimation);
+ scrollbar_controller_->DidMouseMove(
+ NearVerticalScrollbarBegin(-kMouseMoveDistanceToTriggerExpand, 0));
EXPECT_TRUE(client_.start_fade().is_null() ||
client_.start_fade().IsCancelled());
@@ -419,8 +515,9 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, DontFadeWhileCaptured) {
EXPECT_FALSE(client_.start_fade().is_null());
EXPECT_FALSE(client_.start_fade().IsCancelled());
- // Now move the mouse over the scrollbar and animate it until it's thick.
- scrollbar_controller_->DidMouseMoveNear(VERTICAL, 0);
+ // Now move the mouse over the vertical scrollbar thumb and animate it until
+ // it's thick.
+ scrollbar_controller_->DidMouseMove(NearVerticalScrollbarBegin(0, 0));
scrollbar_controller_->Animate(time);
time += kThinningDuration;
scrollbar_controller_->Animate(time);
@@ -456,8 +553,8 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, FadeAfterReleasedFar) {
EXPECT_FALSE(client_.start_fade().is_null());
EXPECT_FALSE(client_.start_fade().IsCancelled());
- // Now move the mouse over the scrollbar and capture it.
- scrollbar_controller_->DidMouseMoveNear(VERTICAL, 0);
+ // Now move the mouse over the vertical scrollbar thumb and capture it.
+ scrollbar_controller_->DidMouseMove(NearVerticalScrollbarBegin(0, 0));
scrollbar_controller_->DidMouseDown();
ExpectScrollbarsOpacity(1);
EXPECT_FLOAT_EQ(1, v_scrollbar_layer_->thumb_thickness_scale_factor());
@@ -470,8 +567,8 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, FadeAfterReleasedFar) {
client_.start_fade().IsCancelled());
// Now move the mouse away from the scrollbar and release it.
- scrollbar_controller_->DidMouseMoveNear(
- VERTICAL, kDefaultMouseMoveDistanceToTriggerAnimation);
+ scrollbar_controller_->DidMouseMove(
+ NearVerticalScrollbarBegin(-kMouseMoveDistanceToTriggerFadeIn, 0));
scrollbar_controller_->DidMouseUp();
scrollbar_controller_->Animate(time);
@@ -507,8 +604,8 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, DontFadeAfterReleasedNear) {
EXPECT_FALSE(client_.start_fade().is_null());
EXPECT_FALSE(client_.start_fade().IsCancelled());
- // Now move the mouse over the scrollbar and capture it.
- scrollbar_controller_->DidMouseMoveNear(VERTICAL, 0);
+ // Now move the mouse over the vertical scrollbar thumb and capture it.
+ scrollbar_controller_->DidMouseMove(NearVerticalScrollbarBegin(0, 0));
scrollbar_controller_->DidMouseDown();
ExpectScrollbarsOpacity(1);
EXPECT_FLOAT_EQ(1, v_scrollbar_layer_->thumb_thickness_scale_factor());
@@ -554,9 +651,9 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
scrollbar_controller_->Animate(time);
ExpectScrollbarsOpacity(.5f);
- // Now move the mouse near the scrollbar. It should reset opacity to 1
- // instantly and start animating to thick.
- scrollbar_controller_->DidMouseMoveNear(VERTICAL, 1);
+ // Now move the mouse near the vertical scrollbar thumb. It should reset
+ // opacity to 1 instantly and start animating to thick.
+ scrollbar_controller_->DidMouseMove(NearVerticalScrollbarBegin(0, 0));
ExpectScrollbarsOpacity(1);
EXPECT_FLOAT_EQ(kIdleThicknessScale,
v_scrollbar_layer_->thumb_thickness_scale_factor());
@@ -593,9 +690,9 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, TestCantCaptureWhenFaded) {
scrollbar_controller_->Animate(time);
ExpectScrollbarsOpacity(0);
- // Move mouse over the scrollbar. It shouldn't thicken the scrollbar since
- // it's completely faded out.
- scrollbar_controller_->DidMouseMoveNear(VERTICAL, 0);
+ // Move mouse over the vertical scrollbar thumb. It shouldn't thicken the
+ // scrollbar since it's completely faded out.
+ scrollbar_controller_->DidMouseMove(NearVerticalScrollbarBegin(0, 0));
scrollbar_controller_->Animate(time);
time += kThinningDuration;
scrollbar_controller_->Animate(time);
@@ -615,13 +712,28 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, TestCantCaptureWhenFaded) {
h_scrollbar_layer_->thumb_thickness_scale_factor());
EXPECT_TRUE(client_.start_fade().is_null());
- // Similarly, releasing the scrollbar should have no effect.
+ // Similarly, releasing the scrollbar should have no effect but trigger a fade
+ // in.
scrollbar_controller_->DidMouseUp();
ExpectScrollbarsOpacity(0);
EXPECT_FLOAT_EQ(1, v_scrollbar_layer_->thumb_thickness_scale_factor());
EXPECT_FLOAT_EQ(kIdleThicknessScale,
h_scrollbar_layer_->thumb_thickness_scale_factor());
- EXPECT_TRUE(client_.start_fade().is_null());
+
+ // An fade in animation should have been enqueued.
+ EXPECT_FALSE(client_.start_fade().is_null());
+ EXPECT_FALSE(client_.start_fade().IsCancelled());
+ EXPECT_EQ(kFadeDelay, client_.delay());
+
+ // Play the delay animation.
+ client_.start_fade().Run();
+ EXPECT_TRUE(client_.start_fade().IsCancelled());
+
+ scrollbar_controller_->Animate(time);
+ time += kFadeDuration;
+ scrollbar_controller_->Animate(time);
+
+ EXPECT_FALSE(scrollbar_controller_->ScrollbarsHidden());
}
// Initiate a scroll when the pointer is already near the scrollbar. It should
@@ -630,7 +742,7 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, ScrollWithMouseNear) {
base::TimeTicks time;
time += base::TimeDelta::FromSeconds(1);
- scrollbar_controller_->DidMouseMoveNear(VERTICAL, 1);
+ scrollbar_controller_->DidMouseMove(NearVerticalScrollbarBegin(-1, 0));
scrollbar_controller_->Animate(time);
time += kThinningDuration;
@@ -693,27 +805,6 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
EXPECT_EQ(kFadeDelay, client_.delay());
}
-// Make sure that if the scroll update is as a result of a resize, we use the
-// resize delay time instead of the default one.
-TEST_F(ScrollbarAnimationControllerAuraOverlayTest, ResizeFadeDuration) {
- ASSERT_TRUE(client_.delay().is_zero());
-
- scrollbar_controller_->DidResize();
- EXPECT_FALSE(client_.start_fade().is_null());
- EXPECT_EQ(kResizeFadeOutDelay, client_.delay());
-
- client_.delay() = base::TimeDelta();
-
- // We should use the gesture delay rather than the resize delay if we're in a
- // gesture scroll, even if it is resizing.
- scrollbar_controller_->DidScrollBegin();
- scrollbar_controller_->DidResize();
- scrollbar_controller_->DidScrollEnd();
-
- EXPECT_FALSE(client_.start_fade().is_null());
- EXPECT_EQ(kFadeDelay, client_.delay());
-}
-
// Tests that the fade effect is animated.
TEST_F(ScrollbarAnimationControllerAuraOverlayTest, FadeAnimated) {
base::TimeTicks time;
@@ -804,8 +895,8 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, MouseNearEach) {
scrollbar_controller_->DidScrollUpdate();
scrollbar_controller_->DidScrollEnd();
- // Near vertical scrollbar
- scrollbar_controller_->DidMouseMoveNear(VERTICAL, 1);
+ // Near vertical scrollbar.
+ scrollbar_controller_->DidMouseMove(NearVerticalScrollbarBegin(-1, 0));
scrollbar_controller_->Animate(time);
ExpectScrollbarsOpacity(1);
EXPECT_FLOAT_EQ(kIdleThicknessScale,
@@ -822,7 +913,7 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, MouseNearEach) {
h_scrollbar_layer_->thumb_thickness_scale_factor());
// Subsequent moves within the nearness threshold should not change anything.
- scrollbar_controller_->DidMouseMoveNear(VERTICAL, 2);
+ scrollbar_controller_->DidMouseMove(NearVerticalScrollbarBegin(-2, 0));
scrollbar_controller_->Animate(time);
time += base::TimeDelta::FromSeconds(10);
scrollbar_controller_->Animate(time);
@@ -832,8 +923,8 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, MouseNearEach) {
h_scrollbar_layer_->thumb_thickness_scale_factor());
// Now move away from bar.
- scrollbar_controller_->DidMouseMoveNear(
- VERTICAL, kDefaultMouseMoveDistanceToTriggerAnimation);
+ scrollbar_controller_->DidMouseMove(
+ NearVerticalScrollbarBegin(-kMouseMoveDistanceToTriggerExpand, 0));
scrollbar_controller_->Animate(time);
time += kThinningDuration;
scrollbar_controller_->Animate(time);
@@ -844,7 +935,7 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, MouseNearEach) {
h_scrollbar_layer_->thumb_thickness_scale_factor());
// Near horizontal scrollbar
- scrollbar_controller_->DidMouseMoveNear(HORIZONTAL, 2);
+ scrollbar_controller_->DidMouseMove(NearHorizontalScrollbarBegin(0, -1));
scrollbar_controller_->Animate(time);
ExpectScrollbarsOpacity(1);
EXPECT_FLOAT_EQ(kIdleThicknessScale,
@@ -861,7 +952,7 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, MouseNearEach) {
EXPECT_FLOAT_EQ(1, h_scrollbar_layer_->thumb_thickness_scale_factor());
// Subsequent moves within the nearness threshold should not change anything.
- scrollbar_controller_->DidMouseMoveNear(HORIZONTAL, 1);
+ scrollbar_controller_->DidMouseMove(NearHorizontalScrollbarBegin(0, -2));
scrollbar_controller_->Animate(time);
time += base::TimeDelta::FromSeconds(10);
scrollbar_controller_->Animate(time);
@@ -871,8 +962,8 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, MouseNearEach) {
EXPECT_FLOAT_EQ(1, h_scrollbar_layer_->thumb_thickness_scale_factor());
// Now move away from bar.
- scrollbar_controller_->DidMouseMoveNear(
- HORIZONTAL, kDefaultMouseMoveDistanceToTriggerAnimation);
+ scrollbar_controller_->DidMouseMove(
+ NearHorizontalScrollbarBegin(0, -kMouseMoveDistanceToTriggerExpand));
scrollbar_controller_->Animate(time);
time += kThinningDuration;
scrollbar_controller_->Animate(time);
@@ -897,9 +988,12 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, MouseNearBoth) {
scrollbar_controller_->DidScrollUpdate();
scrollbar_controller_->DidScrollEnd();
+ // Move scrollbar thumb to the end of track.
+ v_scrollbar_layer_->SetCurrentPos(100);
+ h_scrollbar_layer_->SetCurrentPos(100);
+
// Near both Scrollbar
- scrollbar_controller_->DidMouseMoveNear(VERTICAL, 1);
- scrollbar_controller_->DidMouseMoveNear(HORIZONTAL, 1);
+ scrollbar_controller_->DidMouseMove(NearVerticalScrollbarEnd(-1, -1));
scrollbar_controller_->Animate(time);
ExpectScrollbarsOpacity(1);
EXPECT_FLOAT_EQ(kIdleThicknessScale,
@@ -928,7 +1022,7 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
scrollbar_controller_->DidScrollEnd();
// Near vertical scrollbar.
- scrollbar_controller_->DidMouseMoveNear(VERTICAL, 1);
+ scrollbar_controller_->DidMouseMove(NearVerticalScrollbarBegin(-1, 0));
scrollbar_controller_->Animate(time);
ExpectScrollbarsOpacity(1);
EXPECT_FLOAT_EQ(kIdleThicknessScale,
@@ -946,9 +1040,8 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
h_scrollbar_layer_->thumb_thickness_scale_factor());
// Away vertical scrollbar and near horizontal scrollbar.
- scrollbar_controller_->DidMouseMoveNear(
- VERTICAL, kDefaultMouseMoveDistanceToTriggerAnimation);
- scrollbar_controller_->DidMouseMoveNear(HORIZONTAL, 1);
+ scrollbar_controller_->DidMouseMove(gfx::PointF(0, 0));
+ scrollbar_controller_->DidMouseMove(NearHorizontalScrollbarBegin(0, -1));
scrollbar_controller_->Animate(time);
// Vertical scrollbar animate to thin. horizontal scrollbar animate to
@@ -961,8 +1054,7 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
EXPECT_FLOAT_EQ(1, h_scrollbar_layer_->thumb_thickness_scale_factor());
// Away horizontal scrollbar.
- scrollbar_controller_->DidMouseMoveNear(
- HORIZONTAL, kDefaultMouseMoveDistanceToTriggerAnimation);
+ scrollbar_controller_->DidMouseMove(gfx::PointF(0, 0));
scrollbar_controller_->Animate(time);
// Horizontal scrollbar animate to thin.
@@ -986,7 +1078,7 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, MouseLeaveFadeOut) {
time += base::TimeDelta::FromSeconds(1);
// Move mouse near scrollbar.
- scrollbar_controller_->DidMouseMoveNear(VERTICAL, 1);
+ scrollbar_controller_->DidMouseMove(NearVerticalScrollbarBegin(-1, 0));
// Scroll to make the scrollbars visible.
scrollbar_controller_->DidScrollBegin();
@@ -1011,9 +1103,9 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest, BasicMouseHoverFadeIn) {
base::TimeTicks time;
time += base::TimeDelta::FromSeconds(1);
- // Move mouse hover the fade in scrollbar region of scrollbar.
- scrollbar_controller_->DidMouseMoveNear(
- VERTICAL, kMouseMoveDistanceToTriggerFadeIn - 1);
+ // Move mouse over the fade in region of scrollbar.
+ scrollbar_controller_->DidMouseMove(
+ NearVerticalScrollbarBegin(-kMouseMoveDistanceToTriggerFadeIn + 1, 0));
// An fade in animation should have been enqueued.
EXPECT_FALSE(client_.start_fade().is_null());
@@ -1045,9 +1137,9 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
base::TimeTicks time;
time += base::TimeDelta::FromSeconds(1);
- // Move mouse hover the fade in scrollbar region of scrollbar.
- scrollbar_controller_->DidMouseMoveNear(
- VERTICAL, kMouseMoveDistanceToTriggerFadeIn - 1);
+ // Move mouse over the fade in region of scrollbar.
+ scrollbar_controller_->DidMouseMove(
+ NearVerticalScrollbarBegin(-kMouseMoveDistanceToTriggerFadeIn + 1, 0));
// An fade in animation should have been enqueued.
EXPECT_FALSE(client_.start_fade().is_null());
@@ -1055,10 +1147,10 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
EXPECT_EQ(kFadeDelay, client_.delay());
base::Closure& fade = client_.start_fade();
- // Move mouse still hover the fade in scrollbar region of scrollbar should not
+ // Move mouse still hover the fade in region of scrollbar should not
// post a new fade in.
- scrollbar_controller_->DidMouseMoveNear(
- VERTICAL, kMouseMoveDistanceToTriggerFadeIn - 2);
+ scrollbar_controller_->DidMouseMove(
+ NearVerticalScrollbarBegin(-kMouseMoveDistanceToTriggerFadeIn + 2, 0));
EXPECT_TRUE(fade.Equals(client_.start_fade()));
}
@@ -1070,9 +1162,9 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
base::TimeTicks time;
time += base::TimeDelta::FromSeconds(1);
- // Move mouse hover the fade in scrollbar region of scrollbar.
- scrollbar_controller_->DidMouseMoveNear(
- VERTICAL, kMouseMoveDistanceToTriggerFadeIn - 1);
+ // Move mouse over the fade in region of scrollbar.
+ scrollbar_controller_->DidMouseMove(
+ NearVerticalScrollbarBegin(-kMouseMoveDistanceToTriggerFadeIn + 1, 0));
// An fade in animation should have been enqueued.
EXPECT_FALSE(client_.start_fade().is_null());
@@ -1080,8 +1172,9 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
EXPECT_EQ(kFadeDelay, client_.delay());
// Move mouse far away,delay fade in should be canceled.
- scrollbar_controller_->DidMouseMoveNear(VERTICAL,
- kMouseMoveDistanceToTriggerFadeIn);
+ scrollbar_controller_->DidMouseMove(
+ NearVerticalScrollbarBegin(-kMouseMoveDistanceToTriggerFadeIn, 0));
+
EXPECT_TRUE(client_.start_fade().is_null() ||
client_.start_fade().IsCancelled());
}
@@ -1093,9 +1186,9 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
base::TimeTicks time;
time += base::TimeDelta::FromSeconds(1);
- // Move mouse hover the fade in scrollbar region of scrollbar.
- scrollbar_controller_->DidMouseMoveNear(
- VERTICAL, kMouseMoveDistanceToTriggerFadeIn - 1);
+ // Move mouse over the fade in region of scrollbar.
+ scrollbar_controller_->DidMouseMove(
+ NearVerticalScrollbarBegin(-kMouseMoveDistanceToTriggerFadeIn + 1, 0));
// An fade in animation should have been enqueued.
EXPECT_FALSE(client_.start_fade().is_null());
@@ -1107,9 +1200,9 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
EXPECT_TRUE(client_.start_fade().is_null() ||
client_.start_fade().IsCancelled());
- // Move mouse hover the fade in scrollbar region of scrollbar.
- scrollbar_controller_->DidMouseMoveNear(
- VERTICAL, kMouseMoveDistanceToTriggerFadeIn - 1);
+ // Move mouse over the fade in region of scrollbar.
+ scrollbar_controller_->DidMouseMove(
+ NearVerticalScrollbarBegin(-kMouseMoveDistanceToTriggerFadeIn + 1, 0));
// An fade in animation should have been enqueued.
EXPECT_FALSE(client_.start_fade().is_null());
@@ -1127,6 +1220,94 @@ TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
EXPECT_FALSE(scrollbar_controller_->ScrollbarsHidden());
}
+// Make sure mouse down will cancel hover fade in timer, then mouse move with
+// press will not trigger hover fade in, mouse release near will trigger new
+// hover fade in.
+TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
+ MouseHoverThenMouseDownShouldCancelFadeInThenReleaseNearShouldFadeIn) {
+ base::TimeTicks time;
+ time += base::TimeDelta::FromSeconds(1);
+
+ // Move mouse over the fade in region of scrollbar.
+ scrollbar_controller_->DidMouseMove(
+ NearVerticalScrollbarBegin(-kMouseMoveDistanceToTriggerFadeIn + 1, 0));
+
+ // An fade in animation should have been enqueued.
+ EXPECT_FALSE(client_.start_fade().is_null());
+ EXPECT_FALSE(client_.start_fade().IsCancelled());
+ EXPECT_EQ(kFadeDelay, client_.delay());
+
+ // Mouse down,delay fade in should be canceled.
+ scrollbar_controller_->DidMouseDown();
+ EXPECT_TRUE(client_.start_fade().is_null() ||
+ client_.start_fade().IsCancelled());
+
+ // Move mouse hover the fade in region of scrollbar with press.
+ scrollbar_controller_->DidMouseMove(
+ NearVerticalScrollbarBegin(-kMouseMoveDistanceToTriggerFadeIn + 1, 0));
+
+ // Should not have delay fade animation.
+ EXPECT_TRUE(client_.start_fade().is_null() ||
+ client_.start_fade().IsCancelled());
+
+ // Mouse up.
+ scrollbar_controller_->DidMouseUp();
+
+ // An fade in animation should have been enqueued.
+ EXPECT_FALSE(client_.start_fade().is_null());
+ EXPECT_FALSE(client_.start_fade().IsCancelled());
+ EXPECT_EQ(kFadeDelay, client_.delay());
+
+ // Play the delay animation.
+ client_.start_fade().Run();
+ EXPECT_TRUE(client_.start_fade().IsCancelled());
+
+ scrollbar_controller_->Animate(time);
+ time += kFadeDuration;
+ scrollbar_controller_->Animate(time);
+
+ EXPECT_FALSE(scrollbar_controller_->ScrollbarsHidden());
+}
+
+// Make sure mouse down will cancel hover fade in timer, then mouse move with
+// press will not trigger hover fade in, mouse release far will not trigger new
+// hover fade in.
+TEST_F(ScrollbarAnimationControllerAuraOverlayTest,
+ MouseReleaseFarShouldNotFadeIn) {
+ base::TimeTicks time;
+ time += base::TimeDelta::FromSeconds(1);
+
+ // Move mouse over the fade in region of scrollbar.
+ scrollbar_controller_->DidMouseMove(
+ NearVerticalScrollbarBegin(-kMouseMoveDistanceToTriggerFadeIn + 1, 0));
+
+ // An fade in animation should have been enqueued.
+ EXPECT_FALSE(client_.start_fade().is_null());
+ EXPECT_FALSE(client_.start_fade().IsCancelled());
+ EXPECT_EQ(kFadeDelay, client_.delay());
+
+ // Mouse down,delay fade in should be canceled.
+ scrollbar_controller_->DidMouseDown();
+ EXPECT_TRUE(client_.start_fade().is_null() ||
+ client_.start_fade().IsCancelled());
+
+ // Move mouse far from hover the fade in region of scrollbar with
+ // press.
+ scrollbar_controller_->DidMouseMove(
+ NearVerticalScrollbarBegin(-kMouseMoveDistanceToTriggerFadeIn, 0));
+
+ // Should not have delay fade animation.
+ EXPECT_TRUE(client_.start_fade().is_null() ||
+ client_.start_fade().IsCancelled());
+
+ // Mouse up.
+ scrollbar_controller_->DidMouseUp();
+
+ // Should not have delay fade animation.
+ EXPECT_TRUE(client_.start_fade().is_null() ||
+ client_.start_fade().IsCancelled());
+}
+
class ScrollbarAnimationControllerAndroidTest
: public testing::Test,
public ScrollbarAnimationControllerClient {
@@ -1147,8 +1328,8 @@ class ScrollbarAnimationControllerAndroidTest
void SetNeedsAnimateForScrollbarAnimation() override {
did_request_animate_ = true;
}
- ScrollbarSet ScrollbarsFor(int scroll_layer_id) const override {
- return host_impl_.ScrollbarsFor(scroll_layer_id);
+ ScrollbarSet ScrollbarsFor(ElementId scroll_element_id) const override {
+ return host_impl_.ScrollbarsFor(scroll_element_id);
}
void DidChangeScrollbarVisibility() override {}
@@ -1164,26 +1345,31 @@ class ScrollbarAnimationControllerAndroidTest
SolidColorScrollbarLayerImpl::Create(
host_impl_.active_tree(), 2, orientation(), kThumbThickness,
kTrackStart, kIsLeftSideVerticalScrollbar, kIsOverlayScrollbar);
+ scrollbar->test_properties()->opacity = 0.0f;
scrollbar_layer_ = scrollbar.get();
scrollbar_layer_->test_properties()->opacity_can_animate = true;
std::unique_ptr<LayerImpl> clip =
LayerImpl::Create(host_impl_.active_tree(), 3);
clip_layer_ = clip.get();
+ scroll_layer->SetElementId(
+ LayerIdToElementIdForTesting(scroll_layer->id()));
+
scroll_layer->SetScrollClipLayer(clip_layer_->id());
LayerImpl* scroll_layer_ptr = scroll_layer.get();
scroll_layer->test_properties()->AddChild(std::move(scrollbar));
clip->test_properties()->AddChild(std::move(scroll_layer));
host_impl_.active_tree()->SetRootLayerForTesting(std::move(clip));
- scrollbar_layer_->SetScrollLayerId(scroll_layer_ptr->id());
+ scrollbar_layer_->SetScrollElementId(scroll_layer_ptr->element_id());
clip_layer_->SetBounds(gfx::Size(100, 100));
scroll_layer_ptr->SetBounds(gfx::Size(200, 200));
host_impl_.active_tree()->BuildLayerListAndPropertyTreesForTesting();
scrollbar_controller_ =
ScrollbarAnimationController::CreateScrollbarAnimationControllerAndroid(
- scroll_layer_ptr->id(), this, base::TimeDelta::FromSeconds(2),
- base::TimeDelta::FromSeconds(5), base::TimeDelta::FromSeconds(3));
+ scroll_layer_ptr->element_id(), this,
+ base::TimeDelta::FromSeconds(2), base::TimeDelta::FromSeconds(3),
+ 0.0f);
}
virtual ScrollbarOrientation orientation() const { return HORIZONTAL; }
@@ -1207,24 +1393,6 @@ class VerticalScrollbarAnimationControllerAndroidTest
ScrollbarOrientation orientation() const override { return VERTICAL; }
};
-TEST_F(ScrollbarAnimationControllerAndroidTest, DelayAnimationOnResize) {
- scrollbar_layer_->SetOverlayScrollbarLayerOpacityAnimated(0.f);
- // We should use the gesture delay rather than the resize delay if we're in a
- // gesture scroll, even if it is resizing.
- scrollbar_controller_->DidScrollBegin();
- scrollbar_controller_->DidResize();
- scrollbar_controller_->DidScrollEnd();
- // Normal Animation delay of 2 seconds.
- EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
- EXPECT_EQ(delay_, base::TimeDelta::FromSeconds(2));
-
- scrollbar_layer_->SetOverlayScrollbarLayerOpacityAnimated(0.f);
- scrollbar_controller_->DidResize();
- // Delay animation on resize to 5 seconds.
- EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
- EXPECT_EQ(delay_, base::TimeDelta::FromSeconds(5));
-}
-
TEST_F(ScrollbarAnimationControllerAndroidTest, HiddenInBegin) {
scrollbar_layer_->SetOverlayScrollbarLayerOpacityAnimated(0.f);
scrollbar_controller_->Animate(base::TimeTicks());
diff --git a/chromium/cc/input/scroller_size_metrics.h b/chromium/cc/input/scroller_size_metrics.h
new file mode 100644
index 00000000000..c805934522e
--- /dev/null
+++ b/chromium/cc/input/scroller_size_metrics.h
@@ -0,0 +1,20 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_INPUT_SCROLLER_SIZE_METRICS_H_
+#define CC_INPUT_SCROLLER_SIZE_METRICS_H_
+
+namespace cc {
+
+// Use the two constants to add scroller size related UMA metrics.
+// The goal of the metrics is to find the frequency of scrollers of
+// different sizes that get scrolled. This experiment is aiming at small
+// scrollers therefore the big ones, e.g. larger than 400px * 500px, will get
+// capped into one bucket.
+static constexpr int kScrollerSizeLargestBucket = 200000;
+static constexpr int kScrollerSizeBucketCount = 50;
+
+} // namespace cc
+
+#endif // CC_INPUT_SCROLLER_SIZE_METRICS_H_
diff --git a/chromium/cc/input/single_scrollbar_animation_controller_thinning.cc b/chromium/cc/input/single_scrollbar_animation_controller_thinning.cc
index d09dd054310..0515aaff879 100644
--- a/chromium/cc/input/single_scrollbar_animation_controller_thinning.cc
+++ b/chromium/cc/input/single_scrollbar_animation_controller_thinning.cc
@@ -15,34 +15,69 @@
namespace cc {
+namespace {
+
+float DistanceToScrollbarPart(const gfx::PointF& device_viewport_point,
+ const ScrollbarLayerImplBase& scrollbar,
+ const ScrollbarPart part) {
+ gfx::RectF rect;
+ if (part == ScrollbarPart::THUMB) {
+ rect = gfx::RectF(gfx::Rect(scrollbar.ComputeExpandedThumbQuadRect()));
+ } else {
+ rect = gfx::RectF(gfx::Rect(scrollbar.bounds()));
+ }
+
+ gfx::RectF device_viewport_rect =
+ MathUtil::MapClippedRect(scrollbar.ScreenSpaceTransform(), rect);
+
+ return device_viewport_rect.ManhattanDistanceToPoint(device_viewport_point) /
+ scrollbar.layer_tree_impl()->device_scale_factor();
+}
+
+} // namespace
+
std::unique_ptr<SingleScrollbarAnimationControllerThinning>
SingleScrollbarAnimationControllerThinning::Create(
- int scroll_layer_id,
+ ElementId scroll_element_id,
ScrollbarOrientation orientation,
ScrollbarAnimationControllerClient* client,
base::TimeDelta thinning_duration) {
return base::WrapUnique(new SingleScrollbarAnimationControllerThinning(
- scroll_layer_id, orientation, client, thinning_duration));
+ scroll_element_id, orientation, client, thinning_duration));
}
SingleScrollbarAnimationControllerThinning::
SingleScrollbarAnimationControllerThinning(
- int scroll_layer_id,
+ ElementId scroll_element_id,
ScrollbarOrientation orientation,
ScrollbarAnimationControllerClient* client,
base::TimeDelta thinning_duration)
: client_(client),
is_animating_(false),
- scroll_layer_id_(scroll_layer_id),
+ scroll_element_id_(scroll_element_id),
orientation_(orientation),
captured_(false),
- mouse_is_over_scrollbar_(false),
- mouse_is_near_scrollbar_(false),
+ mouse_is_over_scrollbar_thumb_(false),
+ mouse_is_near_scrollbar_thumb_(false),
+ mouse_is_near_scrollbar_track_(false),
thickness_change_(NONE),
thinning_duration_(thinning_duration) {
ApplyThumbThicknessScale(kIdleThicknessScale);
}
+ScrollbarLayerImplBase*
+SingleScrollbarAnimationControllerThinning::GetScrollbar() const {
+ for (ScrollbarLayerImplBase* scrollbar :
+ client_->ScrollbarsFor(scroll_element_id_)) {
+ DCHECK(scrollbar->is_overlay_scrollbar());
+
+ if (scrollbar->orientation() == orientation_)
+ return scrollbar;
+ }
+
+ return nullptr;
+}
+
bool SingleScrollbarAnimationControllerThinning::Animate(base::TimeTicks now) {
if (!is_animating_)
return false;
@@ -92,7 +127,7 @@ void SingleScrollbarAnimationControllerThinning::StopAnimation() {
}
void SingleScrollbarAnimationControllerThinning::DidMouseDown() {
- if (!mouse_is_over_scrollbar_)
+ if (!mouse_is_over_scrollbar_thumb_)
return;
StopAnimation();
@@ -107,7 +142,7 @@ void SingleScrollbarAnimationControllerThinning::DidMouseUp() {
captured_ = false;
StopAnimation();
- if (!mouse_is_near_scrollbar_) {
+ if (!mouse_is_near_scrollbar_thumb_) {
thickness_change_ = DECREASE;
StartAnimation();
} else {
@@ -116,11 +151,12 @@ void SingleScrollbarAnimationControllerThinning::DidMouseUp() {
}
void SingleScrollbarAnimationControllerThinning::DidMouseLeave() {
- if (!mouse_is_over_scrollbar_ && !mouse_is_near_scrollbar_)
+ if (!mouse_is_over_scrollbar_thumb_ && !mouse_is_near_scrollbar_thumb_)
return;
- mouse_is_over_scrollbar_ = false;
- mouse_is_near_scrollbar_ = false;
+ mouse_is_over_scrollbar_thumb_ = false;
+ mouse_is_near_scrollbar_thumb_ = false;
+ mouse_is_near_scrollbar_track_ = false;
if (captured_)
return;
@@ -129,24 +165,39 @@ void SingleScrollbarAnimationControllerThinning::DidMouseLeave() {
StartAnimation();
}
-void SingleScrollbarAnimationControllerThinning::DidMouseMoveNear(
- float distance) {
- bool mouse_is_over_scrollbar = distance == 0.0f;
- bool mouse_is_near_scrollbar =
- distance < kDefaultMouseMoveDistanceToTriggerAnimation;
+void SingleScrollbarAnimationControllerThinning::DidMouseMove(
+ const gfx::PointF& device_viewport_point) {
+ ScrollbarLayerImplBase* scrollbar = GetScrollbar();
+
+ if (!scrollbar)
+ return;
+
+ float distance_to_scrollbar_track = DistanceToScrollbarPart(
+ device_viewport_point, *scrollbar, ScrollbarPart::TRACK);
+ float distance_to_scrollbar_thumb = DistanceToScrollbarPart(
+ device_viewport_point, *scrollbar, ScrollbarPart::THUMB);
+
+ mouse_is_near_scrollbar_track_ =
+ distance_to_scrollbar_track <
+ ScrollbarAnimationController::kMouseMoveDistanceToTriggerFadeIn;
+
+ bool mouse_is_over_scrollbar_thumb = distance_to_scrollbar_thumb == 0.0f;
+ bool mouse_is_near_scrollbar_thumb =
+ distance_to_scrollbar_thumb < kMouseMoveDistanceToTriggerExpand;
- if (!captured_ && mouse_is_near_scrollbar != mouse_is_near_scrollbar_) {
- thickness_change_ = mouse_is_near_scrollbar ? INCREASE : DECREASE;
+ if (!captured_ &&
+ mouse_is_near_scrollbar_thumb != mouse_is_near_scrollbar_thumb_) {
+ thickness_change_ = mouse_is_near_scrollbar_thumb ? INCREASE : DECREASE;
StartAnimation();
}
- mouse_is_near_scrollbar_ = mouse_is_near_scrollbar;
- mouse_is_over_scrollbar_ = mouse_is_over_scrollbar;
+ mouse_is_near_scrollbar_thumb_ = mouse_is_near_scrollbar_thumb;
+ mouse_is_over_scrollbar_thumb_ = mouse_is_over_scrollbar_thumb;
}
float SingleScrollbarAnimationControllerThinning::ThumbThicknessScaleAt(
float progress) {
if (thickness_change_ == NONE)
- return mouse_is_near_scrollbar_ ? 1.f : kIdleThicknessScale;
+ return mouse_is_near_scrollbar_thumb_ ? 1.f : kIdleThicknessScale;
float factor = thickness_change_ == INCREASE ? progress : (1.f - progress);
return ((1.f - kIdleThicknessScale) * factor) + kIdleThicknessScale;
}
@@ -173,18 +224,16 @@ float SingleScrollbarAnimationControllerThinning::AdjustScale(
void SingleScrollbarAnimationControllerThinning::UpdateThumbThicknessScale() {
StopAnimation();
- ApplyThumbThicknessScale(mouse_is_near_scrollbar_ ? 1.f
- : kIdleThicknessScale);
+ ApplyThumbThicknessScale(
+ mouse_is_near_scrollbar_thumb_ ? 1.f : kIdleThicknessScale);
}
void SingleScrollbarAnimationControllerThinning::ApplyThumbThicknessScale(
float thumb_thickness_scale) {
- for (ScrollbarLayerImplBase* scrollbar :
- client_->ScrollbarsFor(scroll_layer_id_)) {
+ for (auto* scrollbar : client_->ScrollbarsFor(scroll_element_id_)) {
if (scrollbar->orientation() != orientation_)
continue;
- if (!scrollbar->is_overlay_scrollbar())
- continue;
+ DCHECK(scrollbar->is_overlay_scrollbar());
float scale = AdjustScale(thumb_thickness_scale,
scrollbar->thumb_thickness_scale_factor(),
diff --git a/chromium/cc/input/single_scrollbar_animation_controller_thinning.h b/chromium/cc/input/single_scrollbar_animation_controller_thinning.h
index 32ba069a12b..20c06835b3e 100644
--- a/chromium/cc/input/single_scrollbar_animation_controller_thinning.h
+++ b/chromium/cc/input/single_scrollbar_animation_controller_thinning.h
@@ -23,18 +23,26 @@ class ScrollbarAnimationControllerClient;
class CC_EXPORT SingleScrollbarAnimationControllerThinning {
public:
static constexpr float kIdleThicknessScale = 0.4f;
- static constexpr float kDefaultMouseMoveDistanceToTriggerAnimation = 25.f;
+ static constexpr float kMouseMoveDistanceToTriggerExpand = 25.f;
static std::unique_ptr<SingleScrollbarAnimationControllerThinning> Create(
- int scroll_layer_id,
+ ElementId scroll_element_id,
ScrollbarOrientation orientation,
ScrollbarAnimationControllerClient* client,
base::TimeDelta thinning_duration);
~SingleScrollbarAnimationControllerThinning() {}
- bool mouse_is_over_scrollbar() const { return mouse_is_over_scrollbar_; }
- bool mouse_is_near_scrollbar() const { return mouse_is_near_scrollbar_; }
+ bool mouse_is_over_scrollbar_thumb() const {
+ return mouse_is_over_scrollbar_thumb_;
+ }
+ bool mouse_is_near_scrollbar_thumb() const {
+ return mouse_is_near_scrollbar_thumb_;
+ }
+ bool mouse_is_near_scrollbar_track() const {
+ return mouse_is_near_scrollbar_track_;
+ }
+
bool captured() const { return captured_; }
bool Animate(base::TimeTicks now);
@@ -46,15 +54,16 @@ class CC_EXPORT SingleScrollbarAnimationControllerThinning {
void DidMouseDown();
void DidMouseUp();
void DidMouseLeave();
- void DidMouseMoveNear(float distance);
+ void DidMouseMove(const gfx::PointF& device_viewport_point);
private:
SingleScrollbarAnimationControllerThinning(
- int scroll_layer_id,
+ ElementId scroll_element_id,
ScrollbarOrientation orientation,
ScrollbarAnimationControllerClient* client,
base::TimeDelta thinning_duration);
+ ScrollbarLayerImplBase* GetScrollbar() const;
float AnimationProgressAtTime(base::TimeTicks now);
void RunAnimationFrame(float progress);
const base::TimeDelta& Duration();
@@ -76,12 +85,13 @@ class CC_EXPORT SingleScrollbarAnimationControllerThinning {
base::TimeTicks last_awaken_time_;
bool is_animating_;
- int scroll_layer_id_;
+ ElementId scroll_element_id_;
ScrollbarOrientation orientation_;
bool captured_;
- bool mouse_is_over_scrollbar_;
- bool mouse_is_near_scrollbar_;
+ bool mouse_is_over_scrollbar_thumb_;
+ bool mouse_is_near_scrollbar_thumb_;
+ bool mouse_is_near_scrollbar_track_;
// Are we narrowing or thickening the bars.
AnimationChange thickness_change_;
diff --git a/chromium/cc/input/single_scrollbar_animation_controller_thinning_unittest.cc b/chromium/cc/input/single_scrollbar_animation_controller_thinning_unittest.cc
index 50659ff44d8..0faa8d3265b 100644
--- a/chromium/cc/input/single_scrollbar_animation_controller_thinning_unittest.cc
+++ b/chromium/cc/input/single_scrollbar_animation_controller_thinning_unittest.cc
@@ -23,9 +23,11 @@ namespace {
const float kIdleThicknessScale =
SingleScrollbarAnimationControllerThinning::kIdleThicknessScale;
-const float kDefaultMouseMoveDistanceToTriggerAnimation =
+const float kMouseMoveDistanceToTriggerExpand =
SingleScrollbarAnimationControllerThinning::
- kDefaultMouseMoveDistanceToTriggerAnimation;
+ kMouseMoveDistanceToTriggerExpand;
+const float kMouseMoveDistanceToTriggerFadeIn =
+ ScrollbarAnimationController::kMouseMoveDistanceToTriggerFadeIn;
class MockSingleScrollbarAnimationControllerClient
: public ScrollbarAnimationControllerClient {
@@ -35,8 +37,8 @@ class MockSingleScrollbarAnimationControllerClient
: host_impl_(host_impl) {}
virtual ~MockSingleScrollbarAnimationControllerClient() {}
- ScrollbarSet ScrollbarsFor(int scroll_layer_id) const override {
- return host_impl_->ScrollbarsFor(scroll_layer_id);
+ ScrollbarSet ScrollbarsFor(ElementId scroll_element_id) const override {
+ return host_impl_->ScrollbarsFor(scroll_element_id);
}
MOCK_METHOD2(PostDelayedScrollbarAnimationTask,
@@ -65,6 +67,8 @@ class SingleScrollbarAnimationControllerThinningTest : public testing::Test {
LayerImpl::Create(host_impl_.active_tree(), 1);
std::unique_ptr<LayerImpl> clip =
LayerImpl::Create(host_impl_.active_tree(), 3);
+ scroll_layer->SetElementId(
+ LayerIdToElementIdForTesting(scroll_layer->id()));
clip_layer_ = clip.get();
scroll_layer->SetScrollClipLayer(clip_layer_->id());
LayerImpl* scroll_layer_ptr = scroll_layer.get();
@@ -72,6 +76,7 @@ class SingleScrollbarAnimationControllerThinningTest : public testing::Test {
const int kId = 2;
const int kThumbThickness = 10;
const int kTrackStart = 0;
+ const int kTrackLength = 100;
const bool kIsLeftSideVerticalScrollbar = false;
const bool kIsOverlayScrollbar = true;
@@ -85,14 +90,17 @@ class SingleScrollbarAnimationControllerThinningTest : public testing::Test {
clip_layer_->test_properties()->AddChild(std::move(scroll_layer));
host_impl_.active_tree()->SetRootLayerForTesting(std::move(clip));
- scrollbar_layer_->SetScrollLayerId(scroll_layer_ptr->id());
+ scrollbar_layer_->SetBounds(gfx::Size(kThumbThickness, kTrackLength));
+ scrollbar_layer_->SetPosition(gfx::PointF(90, 0));
+ scrollbar_layer_->SetScrollElementId(scroll_layer_ptr->element_id());
scrollbar_layer_->test_properties()->opacity_can_animate = true;
clip_layer_->SetBounds(gfx::Size(100, 100));
scroll_layer_ptr->SetBounds(gfx::Size(200, 200));
host_impl_.active_tree()->BuildLayerListAndPropertyTreesForTesting();
scrollbar_controller_ = SingleScrollbarAnimationControllerThinning::Create(
- scroll_layer_ptr->id(), HORIZONTAL, &client_, kThinningDuration);
+ scroll_layer_ptr->element_id(), HORIZONTAL, &client_,
+ kThinningDuration);
}
FakeImplTaskRunnerProvider task_runner_provider_;
@@ -105,6 +113,13 @@ class SingleScrollbarAnimationControllerThinningTest : public testing::Test {
NiceMock<MockSingleScrollbarAnimationControllerClient> client_;
};
+// Return a point with given offset from the top-left of scrollbar.
+gfx::PointF NearScrollbar(float offset_x, float offset_y) {
+ gfx::PointF p(90, 0);
+ p.Offset(offset_x, offset_y);
+ return p;
+}
+
// Check initialization of scrollbar. Should start thin.
TEST_F(SingleScrollbarAnimationControllerThinningTest, Idle) {
EXPECT_FLOAT_EQ(kIdleThicknessScale,
@@ -117,7 +132,7 @@ TEST_F(SingleScrollbarAnimationControllerThinningTest, MouseNear) {
base::TimeTicks time;
time += base::TimeDelta::FromSeconds(1);
- scrollbar_controller_->DidMouseMoveNear(1);
+ scrollbar_controller_->DidMouseMove(NearScrollbar(-1, 0));
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(kIdleThicknessScale,
scrollbar_layer_->thumb_thickness_scale_factor());
@@ -128,15 +143,24 @@ TEST_F(SingleScrollbarAnimationControllerThinningTest, MouseNear) {
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
// Subsequent moves within the nearness threshold should not change anything.
- scrollbar_controller_->DidMouseMoveNear(2);
+ scrollbar_controller_->DidMouseMove(NearScrollbar(-2, 0));
scrollbar_controller_->Animate(time);
time += base::TimeDelta::FromSeconds(10);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
- // Now move away from bar.
- scrollbar_controller_->DidMouseMoveNear(
- kDefaultMouseMoveDistanceToTriggerAnimation);
+ // Now move away from thumb.
+ scrollbar_controller_->DidMouseMove(
+ NearScrollbar(-kMouseMoveDistanceToTriggerExpand, 0));
+ scrollbar_controller_->Animate(time);
+ time += kThinningDuration;
+ scrollbar_controller_->Animate(time);
+ EXPECT_FLOAT_EQ(kIdleThicknessScale,
+ scrollbar_layer_->thumb_thickness_scale_factor());
+
+ // Move away from track.
+ scrollbar_controller_->DidMouseMove(
+ NearScrollbar(-kMouseMoveDistanceToTriggerFadeIn, 0));
scrollbar_controller_->Animate(time);
time += kThinningDuration;
scrollbar_controller_->Animate(time);
@@ -150,7 +174,7 @@ TEST_F(SingleScrollbarAnimationControllerThinningTest, MouseOver) {
base::TimeTicks time;
time += base::TimeDelta::FromSeconds(1);
- scrollbar_controller_->DidMouseMoveNear(0);
+ scrollbar_controller_->DidMouseMove(NearScrollbar(0, 0));
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(kIdleThicknessScale,
scrollbar_layer_->thumb_thickness_scale_factor());
@@ -161,7 +185,7 @@ TEST_F(SingleScrollbarAnimationControllerThinningTest, MouseOver) {
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
// Subsequent moves should not change anything.
- scrollbar_controller_->DidMouseMoveNear(0);
+ scrollbar_controller_->DidMouseMove(NearScrollbar(0, 0));
scrollbar_controller_->Animate(time);
time += base::TimeDelta::FromSeconds(10);
scrollbar_controller_->Animate(time);
@@ -169,16 +193,16 @@ TEST_F(SingleScrollbarAnimationControllerThinningTest, MouseOver) {
// Moving off the scrollbar but still withing the "near" threshold should do
// nothing.
- scrollbar_controller_->DidMouseMoveNear(
- kDefaultMouseMoveDistanceToTriggerAnimation - 1.f);
+ scrollbar_controller_->DidMouseMove(
+ NearScrollbar(-kMouseMoveDistanceToTriggerExpand + 1, 0));
scrollbar_controller_->Animate(time);
time += base::TimeDelta::FromSeconds(10);
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
- // Now move away from bar.
- scrollbar_controller_->DidMouseMoveNear(
- kDefaultMouseMoveDistanceToTriggerAnimation);
+ // Now move away from thumb.
+ scrollbar_controller_->DidMouseMove(
+ NearScrollbar(-kMouseMoveDistanceToTriggerExpand, 0));
scrollbar_controller_->Animate(time);
time += kThinningDuration;
scrollbar_controller_->Animate(time);
@@ -188,13 +212,13 @@ TEST_F(SingleScrollbarAnimationControllerThinningTest, MouseOver) {
// First move the pointer over the scrollbar off of it. Make sure the thinning
// animation kicked off in DidMouseMoveOffScrollbar gets overridden by the
-// thickening animation in the DidMouseMoveNear call.
+// thickening animation in the DidMouseMove call.
TEST_F(SingleScrollbarAnimationControllerThinningTest,
MouseNearThenAwayWhileAnimating) {
base::TimeTicks time;
time += base::TimeDelta::FromSeconds(1);
- scrollbar_controller_->DidMouseMoveNear(0);
+ scrollbar_controller_->DidMouseMove(NearScrollbar(0, 0));
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(kIdleThicknessScale,
scrollbar_layer_->thumb_thickness_scale_factor());
@@ -205,7 +229,7 @@ TEST_F(SingleScrollbarAnimationControllerThinningTest,
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
// This is tricky. The DidMouseLeave() is sent before the
- // subsequent DidMouseMoveNear(), if the mouse moves in that direction.
+ // subsequent DidMouseMove(), if the mouse moves in that direction.
// This results in the thumb thinning. We want to make sure that when the
// thumb starts expanding it doesn't first narrow to the idle thinness.
time += base::TimeDelta::FromSeconds(1);
@@ -222,7 +246,7 @@ TEST_F(SingleScrollbarAnimationControllerThinningTest,
// Now we get a notification for the mouse moving over the scroller. The
// animation is reset to the thickening direction but we won't start
// thickening until the new animation catches up to the current thickness.
- scrollbar_controller_->DidMouseMoveNear(1);
+ scrollbar_controller_->DidMouseMove(NearScrollbar(-1, 0));
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f - (1.0f - kIdleThicknessScale) / 2.0f,
scrollbar_layer_->thumb_thickness_scale_factor());
@@ -260,7 +284,7 @@ TEST_F(SingleScrollbarAnimationControllerThinningTest,
time += base::TimeDelta::FromSeconds(1);
// Move over the scrollbar.
- scrollbar_controller_->DidMouseMoveNear(0);
+ scrollbar_controller_->DidMouseMove(NearScrollbar(0, 0));
scrollbar_controller_->Animate(time);
time += kThinningDuration;
scrollbar_controller_->Animate(time);
@@ -278,8 +302,8 @@ TEST_F(SingleScrollbarAnimationControllerThinningTest,
// Move outside the "near" threshold. Because the scrollbar is captured it
// should remain thick.
- scrollbar_controller_->DidMouseMoveNear(
- kDefaultMouseMoveDistanceToTriggerAnimation);
+ scrollbar_controller_->DidMouseMove(
+ NearScrollbar(-kMouseMoveDistanceToTriggerExpand, 0));
time += kThinningDuration;
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
@@ -305,7 +329,7 @@ TEST_F(SingleScrollbarAnimationControllerThinningTest,
time += base::TimeDelta::FromSeconds(1);
// Move over scrollbar.
- scrollbar_controller_->DidMouseMoveNear(0);
+ scrollbar_controller_->DidMouseMove(NearScrollbar(0, 0));
scrollbar_controller_->Animate(time);
time += kThinningDuration;
scrollbar_controller_->Animate(time);
@@ -320,8 +344,8 @@ TEST_F(SingleScrollbarAnimationControllerThinningTest,
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
// Move away from scrollbar. Nothing should change.
- scrollbar_controller_->DidMouseMoveNear(
- kDefaultMouseMoveDistanceToTriggerAnimation);
+ scrollbar_controller_->DidMouseMove(
+ NearScrollbar(kMouseMoveDistanceToTriggerExpand, 0));
time += base::TimeDelta::FromSeconds(1);
scrollbar_controller_->Animate(time);
time += base::TimeDelta::FromSeconds(10);
@@ -330,7 +354,8 @@ TEST_F(SingleScrollbarAnimationControllerThinningTest,
// Move over scrollbar and release. Since we're near the scrollbar, it should
// remain thick.
- scrollbar_controller_->DidMouseMoveNear(0);
+ scrollbar_controller_->DidMouseMove(
+ NearScrollbar(-kMouseMoveDistanceToTriggerExpand + 1, 0));
scrollbar_controller_->DidMouseUp();
time += base::TimeDelta::FromSeconds(1);
scrollbar_controller_->Animate(time);
@@ -346,7 +371,7 @@ TEST_F(SingleScrollbarAnimationControllerThinningTest, ThicknessAnimated) {
// Move mouse near scrollbar. Test that at half the duration time, the
// thickness is half way through its animation.
- scrollbar_controller_->DidMouseMoveNear(1);
+ scrollbar_controller_->DidMouseMove(NearScrollbar(-1, 0));
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(kIdleThicknessScale,
scrollbar_layer_->thumb_thickness_scale_factor());
@@ -362,8 +387,8 @@ TEST_F(SingleScrollbarAnimationControllerThinningTest, ThicknessAnimated) {
// Move mouse away from scrollbar. Same check.
time += base::TimeDelta::FromSeconds(1);
- scrollbar_controller_->DidMouseMoveNear(
- kDefaultMouseMoveDistanceToTriggerAnimation);
+ scrollbar_controller_->DidMouseMove(
+ NearScrollbar(-kMouseMoveDistanceToTriggerExpand, 0));
scrollbar_controller_->Animate(time);
EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
diff --git a/chromium/cc/input/touch_action.h b/chromium/cc/input/touch_action.h
new file mode 100644
index 00000000000..8b11c4c9d7e
--- /dev/null
+++ b/chromium/cc/input/touch_action.h
@@ -0,0 +1,56 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_INPUT_TOUCH_ACTION_H_
+#define CC_INPUT_TOUCH_ACTION_H_
+
+#include <cstdlib>
+
+namespace cc {
+
+// The current touch action specifies what accelerated browser operations
+// (panning and zooming) are currently permitted via touch input.
+// See http://www.w3.org/TR/pointerevents/#the-touch-action-css-property.
+// This is intended to be the single canonical definition of the enum, it's used
+// elsewhere in both Blink and content since touch action logic spans those
+// subsystems.
+// TODO(crbug.com/720553): rework this enum to enum class.
+const size_t kTouchActionBits = 6;
+
+enum TouchAction {
+ // No scrolling or zooming allowed.
+ kTouchActionNone = 0x0,
+ kTouchActionPanLeft = 0x1,
+ kTouchActionPanRight = 0x2,
+ kTouchActionPanX = kTouchActionPanLeft | kTouchActionPanRight,
+ kTouchActionPanUp = 0x4,
+ kTouchActionPanDown = 0x8,
+ kTouchActionPanY = kTouchActionPanUp | kTouchActionPanDown,
+ kTouchActionPan = kTouchActionPanX | kTouchActionPanY,
+ kTouchActionPinchZoom = 0x10,
+ kTouchActionManipulation = kTouchActionPan | kTouchActionPinchZoom,
+ kTouchActionDoubleTapZoom = 0x20,
+ kTouchActionAuto = kTouchActionManipulation | kTouchActionDoubleTapZoom,
+ kTouchActionMax = (1 << 6) - 1
+};
+
+inline TouchAction operator|(TouchAction a, TouchAction b) {
+ return static_cast<TouchAction>(int(a) | int(b));
+}
+
+inline TouchAction& operator|=(TouchAction& a, TouchAction b) {
+ return a = a | b;
+}
+
+inline TouchAction operator&(TouchAction a, TouchAction b) {
+ return static_cast<TouchAction>(int(a) & int(b));
+}
+
+inline TouchAction& operator&=(TouchAction& a, TouchAction b) {
+ return a = a & b;
+}
+
+} // namespace cc
+
+#endif // CC_INPUT_TOUCH_ACTION_H_
diff --git a/chromium/cc/ipc/begin_frame_args_struct_traits.cc b/chromium/cc/ipc/begin_frame_args_struct_traits.cc
index 8ba827dbe1b..fedd0ddc4ec 100644
--- a/chromium/cc/ipc/begin_frame_args_struct_traits.cc
+++ b/chromium/cc/ipc/begin_frame_args_struct_traits.cc
@@ -29,6 +29,8 @@ bool StructTraits<cc::mojom::BeginFrameArgsDataView, cc::BeginFrameArgs>::Read(
bool StructTraits<cc::mojom::BeginFrameAckDataView, cc::BeginFrameAck>::Read(
cc::mojom::BeginFrameAckDataView data,
cc::BeginFrameAck* out) {
+ if (data.sequence_number() < cc::BeginFrameArgs::kStartingFrameNumber)
+ return false;
out->source_id = data.source_id();
out->sequence_number = data.sequence_number();
out->latest_confirmed_sequence_number =
diff --git a/chromium/cc/ipc/cc_param_traits.cc b/chromium/cc/ipc/cc_param_traits.cc
index 3b04eb68511..02483340a76 100644
--- a/chromium/cc/ipc/cc_param_traits.cc
+++ b/chromium/cc/ipc/cc_param_traits.cc
@@ -795,7 +795,7 @@ bool ParamTraits<cc::CompositorFrame>::Read(const base::Pickle* m,
uint32_t num_render_passes;
if (!ReadParam(m, iter, &p->resource_list) ||
- !ReadParam(m, iter, &num_render_passes) ||
+ !ReadParam(m, iter, &num_render_passes) || num_render_passes == 0 ||
num_render_passes > kMaxRenderPasses)
return false;
for (uint32_t i = 0; i < num_render_passes; ++i) {
@@ -960,6 +960,40 @@ void ParamTraits<cc::YUVVideoDrawQuad>::Log(const param_type& p,
l->append("])");
}
+void ParamTraits<cc::BeginFrameAck>::GetSize(base::PickleSizer* s,
+ const param_type& p) {
+ GetParamSize(s, p.sequence_number);
+ GetParamSize(s, p.latest_confirmed_sequence_number);
+ GetParamSize(s, p.source_id);
+}
+
+void ParamTraits<cc::BeginFrameAck>::Write(base::Pickle* m,
+ const param_type& p) {
+ m->WriteUInt64(p.sequence_number);
+ m->WriteUInt64(p.latest_confirmed_sequence_number);
+ m->WriteUInt32(p.source_id);
+ // |has_damage| is implicit through IPC message name, so not transmitted.
+}
+
+bool ParamTraits<cc::BeginFrameAck>::Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* p) {
+ return iter->ReadUInt64(&p->sequence_number) &&
+ p->sequence_number >= cc::BeginFrameArgs::kStartingFrameNumber &&
+ iter->ReadUInt64(&p->latest_confirmed_sequence_number) &&
+ iter->ReadUInt32(&p->source_id);
+}
+
+void ParamTraits<cc::BeginFrameAck>::Log(const param_type& p, std::string* l) {
+ l->append("(");
+ LogParam(p.sequence_number, l);
+ l->append(", ");
+ LogParam(p.latest_confirmed_sequence_number, l);
+ l->append(", ");
+ LogParam(p.source_id, l);
+ l->append(")");
+}
+
} // namespace IPC
// Generate param traits size methods.
diff --git a/chromium/cc/ipc/cc_param_traits.h b/chromium/cc/ipc/cc_param_traits.h
index 14e3dbacd99..d2e8b59978c 100644
--- a/chromium/cc/ipc/cc_param_traits.h
+++ b/chromium/cc/ipc/cc_param_traits.h
@@ -142,6 +142,17 @@ struct CC_IPC_EXPORT ParamTraits<cc::YUVVideoDrawQuad> {
static void Log(const param_type& p, std::string* l);
};
+template <>
+struct CC_IPC_EXPORT ParamTraits<cc::BeginFrameAck> {
+ typedef cc::BeginFrameAck param_type;
+ static void GetSize(base::PickleSizer* s, const param_type& p);
+ static void Write(base::Pickle* m, const param_type& p);
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* p);
+ static void Log(const param_type& p, std::string* l);
+};
+
} // namespace IPC
#endif // CC_IPC_CC_PARAM_TRAITS_H_
diff --git a/chromium/cc/ipc/cc_param_traits_macros.h b/chromium/cc/ipc/cc_param_traits_macros.h
index 39a4ecf2fe2..019a16e127d 100644
--- a/chromium/cc/ipc/cc_param_traits_macros.h
+++ b/chromium/cc/ipc/cc_param_traits_macros.h
@@ -126,7 +126,7 @@ IPC_STRUCT_TRAITS_END()
IPC_STRUCT_TRAITS_BEGIN(cc::SharedQuadState)
IPC_STRUCT_TRAITS_MEMBER(quad_to_target_transform)
- IPC_STRUCT_TRAITS_MEMBER(quad_layer_bounds)
+ IPC_STRUCT_TRAITS_MEMBER(quad_layer_rect)
IPC_STRUCT_TRAITS_MEMBER(visible_quad_layer_rect)
IPC_STRUCT_TRAITS_MEMBER(clip_rect)
IPC_STRUCT_TRAITS_MEMBER(is_clipped)
@@ -176,13 +176,6 @@ IPC_STRUCT_TRAITS_BEGIN(cc::BeginFrameArgs)
IPC_STRUCT_TRAITS_MEMBER(type)
IPC_STRUCT_TRAITS_END()
-IPC_STRUCT_TRAITS_BEGIN(cc::BeginFrameAck)
- IPC_STRUCT_TRAITS_MEMBER(sequence_number)
- IPC_STRUCT_TRAITS_MEMBER(latest_confirmed_sequence_number)
- IPC_STRUCT_TRAITS_MEMBER(source_id)
-// |has_damage| is implicit through IPC message name, so not transmitted.
-IPC_STRUCT_TRAITS_END()
-
IPC_STRUCT_TRAITS_BEGIN(cc::CompositorFrameMetadata)
IPC_STRUCT_TRAITS_MEMBER(device_scale_factor)
IPC_STRUCT_TRAITS_MEMBER(root_scroll_offset)
@@ -205,7 +198,7 @@ IPC_STRUCT_TRAITS_BEGIN(cc::CompositorFrameMetadata)
IPC_STRUCT_TRAITS_MEMBER(selection)
IPC_STRUCT_TRAITS_MEMBER(latency_info)
IPC_STRUCT_TRAITS_MEMBER(referenced_surfaces)
- IPC_STRUCT_TRAITS_MEMBER(embedded_surfaces)
+ IPC_STRUCT_TRAITS_MEMBER(activation_dependencies)
IPC_STRUCT_TRAITS_MEMBER(content_source_id)
IPC_STRUCT_TRAITS_MEMBER(begin_frame_ack)
IPC_STRUCT_TRAITS_MEMBER(frame_token)
diff --git a/chromium/cc/ipc/cc_param_traits_unittest.cc b/chromium/cc/ipc/cc_param_traits_unittest.cc
index edd451d7fe3..776e5c2ac30 100644
--- a/chromium/cc/ipc/cc_param_traits_unittest.cc
+++ b/chromium/cc/ipc/cc_param_traits_unittest.cc
@@ -81,7 +81,7 @@ class CCParamTraitsTest : public testing::Test {
void Compare(const SharedQuadState* a, const SharedQuadState* b) {
EXPECT_EQ(a->quad_to_target_transform, b->quad_to_target_transform);
- EXPECT_EQ(a->quad_layer_bounds, b->quad_layer_bounds);
+ EXPECT_EQ(a->quad_layer_rect, b->quad_layer_rect);
EXPECT_EQ(a->visible_quad_layer_rect, b->visible_quad_layer_rect);
EXPECT_EQ(a->clip_rect, b->clip_rect);
EXPECT_EQ(a->is_clipped, b->is_clipped);
@@ -315,7 +315,7 @@ TEST_F(CCParamTraitsTest, AllQuads) {
arbitrary_bool1);
SharedQuadState* shared_state1_in = pass_in->CreateAndAppendSharedQuadState();
- shared_state1_in->SetAll(arbitrary_matrix1, arbitrary_size1, arbitrary_rect1,
+ shared_state1_in->SetAll(arbitrary_matrix1, arbitrary_rect1, arbitrary_rect1,
arbitrary_rect2, arbitrary_bool1, arbitrary_float1,
arbitrary_blend_mode1, arbitrary_context_id1);
@@ -338,7 +338,7 @@ TEST_F(CCParamTraitsTest, AllQuads) {
debugborder_in->shared_quad_state);
SharedQuadState* shared_state2_in = pass_in->CreateAndAppendSharedQuadState();
- shared_state2_in->SetAll(arbitrary_matrix2, arbitrary_size2, arbitrary_rect2,
+ shared_state2_in->SetAll(arbitrary_matrix2, arbitrary_rect2, arbitrary_rect2,
arbitrary_rect3, arbitrary_bool1, arbitrary_float2,
arbitrary_blend_mode2, arbitrary_context_id2);
SharedQuadState* shared_state2_cmp =
@@ -357,7 +357,7 @@ TEST_F(CCParamTraitsTest, AllQuads) {
renderpass_in->render_pass_id);
SharedQuadState* shared_state3_in = pass_in->CreateAndAppendSharedQuadState();
- shared_state3_in->SetAll(arbitrary_matrix1, arbitrary_size3, arbitrary_rect3,
+ shared_state3_in->SetAll(arbitrary_matrix1, arbitrary_rect3, arbitrary_rect3,
arbitrary_rect1, arbitrary_bool1, arbitrary_float3,
arbitrary_blend_mode3, arbitrary_context_id3);
SharedQuadState* shared_state3_cmp =
@@ -456,6 +456,8 @@ TEST_F(CCParamTraitsTest, AllQuads) {
CompositorFrame frame_in;
frame_in.render_pass_list.push_back(std::move(child_pass_in));
frame_in.render_pass_list.push_back(std::move(pass_in));
+ frame_in.metadata.begin_frame_ack.sequence_number =
+ cc::BeginFrameArgs::kStartingFrameNumber;
IPC::ParamTraits<CompositorFrame>::Write(&msg, frame_in);
@@ -505,7 +507,7 @@ TEST_F(CCParamTraitsTest, UnusedSharedQuadStates) {
// The first SharedQuadState is used.
SharedQuadState* shared_state1_in = pass_in->CreateAndAppendSharedQuadState();
- shared_state1_in->SetAll(gfx::Transform(), gfx::Size(1, 1), gfx::Rect(),
+ shared_state1_in->SetAll(gfx::Transform(), gfx::Rect(1, 1), gfx::Rect(),
gfx::Rect(), false, 1.f, SkBlendMode::kSrcOver, 0);
SolidColorDrawQuad* quad1 =
@@ -515,16 +517,16 @@ TEST_F(CCParamTraitsTest, UnusedSharedQuadStates) {
// The second and third SharedQuadStates are not used.
SharedQuadState* shared_state2_in = pass_in->CreateAndAppendSharedQuadState();
- shared_state2_in->SetAll(gfx::Transform(), gfx::Size(2, 2), gfx::Rect(),
+ shared_state2_in->SetAll(gfx::Transform(), gfx::Rect(2, 2), gfx::Rect(),
gfx::Rect(), false, 1.f, SkBlendMode::kSrcOver, 0);
SharedQuadState* shared_state3_in = pass_in->CreateAndAppendSharedQuadState();
- shared_state3_in->SetAll(gfx::Transform(), gfx::Size(3, 3), gfx::Rect(),
+ shared_state3_in->SetAll(gfx::Transform(), gfx::Rect(3, 3), gfx::Rect(),
gfx::Rect(), false, 1.f, SkBlendMode::kSrcOver, 0);
// The fourth SharedQuadState is used.
SharedQuadState* shared_state4_in = pass_in->CreateAndAppendSharedQuadState();
- shared_state4_in->SetAll(gfx::Transform(), gfx::Size(4, 4), gfx::Rect(),
+ shared_state4_in->SetAll(gfx::Transform(), gfx::Rect(4, 4), gfx::Rect(),
gfx::Rect(), false, 1.f, SkBlendMode::kSrcOver, 0);
SolidColorDrawQuad* quad2 =
@@ -534,7 +536,7 @@ TEST_F(CCParamTraitsTest, UnusedSharedQuadStates) {
// The fifth is not used again.
SharedQuadState* shared_state5_in = pass_in->CreateAndAppendSharedQuadState();
- shared_state5_in->SetAll(gfx::Transform(), gfx::Size(5, 5), gfx::Rect(),
+ shared_state5_in->SetAll(gfx::Transform(), gfx::Rect(5, 5), gfx::Rect(),
gfx::Rect(), false, 1.f, SkBlendMode::kSrcOver, 0);
// 5 SharedQuadStates go in.
@@ -543,6 +545,8 @@ TEST_F(CCParamTraitsTest, UnusedSharedQuadStates) {
CompositorFrame frame_in;
frame_in.render_pass_list.push_back(std::move(pass_in));
+ frame_in.metadata.begin_frame_ack.sequence_number =
+ cc::BeginFrameArgs::kStartingFrameNumber;
IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
IPC::ParamTraits<CompositorFrame>::Write(&msg, frame_in);
@@ -559,12 +563,12 @@ TEST_F(CCParamTraitsTest, UnusedSharedQuadStates) {
ASSERT_EQ(2u, pass_out->shared_quad_state_list.size());
ASSERT_EQ(2u, pass_out->quad_list.size());
- EXPECT_EQ(gfx::Size(1, 1).ToString(),
+ EXPECT_EQ(gfx::Rect(1, 1).ToString(),
pass_out->shared_quad_state_list.ElementAt(0)
- ->quad_layer_bounds.ToString());
- EXPECT_EQ(gfx::Size(4, 4).ToString(),
+ ->quad_layer_rect.ToString());
+ EXPECT_EQ(gfx::Rect(4, 4).ToString(),
pass_out->shared_quad_state_list.ElementAt(1)
- ->quad_layer_bounds.ToString());
+ ->quad_layer_rect.ToString());
}
TEST_F(CCParamTraitsTest, Resources) {
@@ -620,6 +624,8 @@ TEST_F(CCParamTraitsTest, Resources) {
frame_in.resource_list.push_back(arbitrary_resource1);
frame_in.resource_list.push_back(arbitrary_resource2);
frame_in.render_pass_list.push_back(std::move(renderpass_in));
+ frame_in.metadata.begin_frame_ack.sequence_number =
+ cc::BeginFrameArgs::kStartingFrameNumber;
IPC::ParamTraits<CompositorFrame>::Write(&msg, frame_in);
diff --git a/chromium/cc/ipc/cc_serialization_perftest.cc b/chromium/cc/ipc/cc_serialization_perftest.cc
index ee90e503630..85a03a0e680 100644
--- a/chromium/cc/ipc/cc_serialization_perftest.cc
+++ b/chromium/cc/ipc/cc_serialization_perftest.cc
@@ -309,7 +309,7 @@ class CCSerializationPerfTest : public testing::Test {
for (uint32_t i = 0; i < 10; ++i) {
SharedQuadState* shared_state1_in =
pass_in->CreateAndAppendSharedQuadState();
- shared_state1_in->SetAll(arbitrary_matrix1, arbitrary_size1,
+ shared_state1_in->SetAll(arbitrary_matrix1, arbitrary_rect1,
arbitrary_rect1, arbitrary_rect2,
arbitrary_bool1, arbitrary_float1,
arbitrary_blend_mode1, arbitrary_context_id1);
@@ -355,7 +355,7 @@ class CCSerializationPerfTest : public testing::Test {
for (uint32_t i = 0; i < 10; ++i) {
SharedQuadState* shared_state2_in =
pass_in->CreateAndAppendSharedQuadState();
- shared_state2_in->SetAll(arbitrary_matrix2, arbitrary_size2,
+ shared_state2_in->SetAll(arbitrary_matrix2, arbitrary_rect2,
arbitrary_rect2, arbitrary_rect3,
arbitrary_bool1, arbitrary_float2,
arbitrary_blend_mode2, arbitrary_context_id2);
@@ -374,7 +374,7 @@ class CCSerializationPerfTest : public testing::Test {
for (uint32_t i = 0; i < 5; ++i) {
SharedQuadState* shared_state3_in =
pass_in->CreateAndAppendSharedQuadState();
- shared_state3_in->SetAll(arbitrary_matrix1, arbitrary_size3,
+ shared_state3_in->SetAll(arbitrary_matrix1, arbitrary_rect3,
arbitrary_rect3, arbitrary_rect1,
arbitrary_bool1, arbitrary_float3,
arbitrary_blend_mode3, arbitrary_context_id3);
diff --git a/chromium/cc/ipc/compositor_frame_metadata.mojom b/chromium/cc/ipc/compositor_frame_metadata.mojom
index 0b1a3d7b388..abbe76d395f 100644
--- a/chromium/cc/ipc/compositor_frame_metadata.mojom
+++ b/chromium/cc/ipc/compositor_frame_metadata.mojom
@@ -31,7 +31,7 @@ struct CompositorFrameMetadata {
Selection selection;
array<ui.mojom.LatencyInfo> latency_info;
array<SurfaceId> referenced_surfaces;
- array<SurfaceId> embedded_surfaces;
+ array<SurfaceId> activation_dependencies;
bool can_activate_before_dependencies;
uint32 content_source_id;
BeginFrameAck begin_frame_ack;
diff --git a/chromium/cc/ipc/compositor_frame_metadata_struct_traits.cc b/chromium/cc/ipc/compositor_frame_metadata_struct_traits.cc
index ab79ed7eb63..fc3d85bfc14 100644
--- a/chromium/cc/ipc/compositor_frame_metadata_struct_traits.cc
+++ b/chromium/cc/ipc/compositor_frame_metadata_struct_traits.cc
@@ -45,7 +45,7 @@ bool StructTraits<cc::mojom::CompositorFrameMetadataDataView,
return data.ReadSelection(&out->selection) &&
data.ReadLatencyInfo(&out->latency_info) &&
data.ReadReferencedSurfaces(&out->referenced_surfaces) &&
- data.ReadEmbeddedSurfaces(&out->embedded_surfaces) &&
+ data.ReadActivationDependencies(&out->activation_dependencies) &&
data.ReadBeginFrameAck(&out->begin_frame_ack);
}
diff --git a/chromium/cc/ipc/compositor_frame_metadata_struct_traits.h b/chromium/cc/ipc/compositor_frame_metadata_struct_traits.h
index f3077ce9495..2959ababfe8 100644
--- a/chromium/cc/ipc/compositor_frame_metadata_struct_traits.h
+++ b/chromium/cc/ipc/compositor_frame_metadata_struct_traits.h
@@ -106,9 +106,9 @@ struct StructTraits<cc::mojom::CompositorFrameMetadataDataView,
return metadata.referenced_surfaces;
}
- static const std::vector<cc::SurfaceId>& embedded_surfaces(
+ static const std::vector<cc::SurfaceId>& activation_dependencies(
const cc::CompositorFrameMetadata& metadata) {
- return metadata.embedded_surfaces;
+ return metadata.activation_dependencies;
}
static bool can_activate_before_dependencies(
diff --git a/chromium/cc/ipc/compositor_frame_struct_traits.cc b/chromium/cc/ipc/compositor_frame_struct_traits.cc
index e3d5442855a..f06f3704e64 100644
--- a/chromium/cc/ipc/compositor_frame_struct_traits.cc
+++ b/chromium/cc/ipc/compositor_frame_struct_traits.cc
@@ -14,11 +14,9 @@ bool StructTraits<cc::mojom::CompositorFrameDataView,
cc::CompositorFrame>::Read(cc::mojom::CompositorFrameDataView
data,
cc::CompositorFrame* out) {
- if (!data.ReadMetadata(&out->metadata))
- return false;
-
- return data.ReadResources(&out->resource_list) &&
- data.ReadPasses(&out->render_pass_list);
+ return data.ReadPasses(&out->render_pass_list) &&
+ !out->render_pass_list.empty() && data.ReadMetadata(&out->metadata) &&
+ data.ReadResources(&out->resource_list);
}
} // namespace mojo
diff --git a/chromium/cc/ipc/mojo_compositor_frame_sink.mojom b/chromium/cc/ipc/mojo_compositor_frame_sink.mojom
index 1ad4ae14d5e..e4c0ae3ef54 100644
--- a/chromium/cc/ipc/mojo_compositor_frame_sink.mojom
+++ b/chromium/cc/ipc/mojo_compositor_frame_sink.mojom
@@ -37,11 +37,11 @@ interface MojoCompositorFrameSink {
// Notifies the frame sink that a BeginFrame was completed, but that no
// CompositorFrame was produced as a result of it.
- BeginFrameDidNotSwap(cc.mojom.BeginFrameAck ack);
+ DidNotProduceFrame(cc.mojom.BeginFrameAck ack);
// Notify that the surface is no longer in use (and is okay to be evicted) so
// that its resources gets returned in time.
- EvictFrame();
+ EvictCurrentSurface();
};
interface MojoCompositorFrameSinkClient {
diff --git a/chromium/cc/ipc/quads.mojom b/chromium/cc/ipc/quads.mojom
index 5ec7e45fca1..436c4433b0c 100644
--- a/chromium/cc/ipc/quads.mojom
+++ b/chromium/cc/ipc/quads.mojom
@@ -8,6 +8,7 @@ import "cc/ipc/filter_operations.mojom";
import "cc/ipc/shared_quad_state.mojom";
import "cc/ipc/surface_id.mojom";
import "ui/gfx/geometry/mojo/geometry.mojom";
+import "ui/gfx/mojo/color_space.mojom";
import "ui/gfx/mojo/transform.mojom";
struct DebugBorderQuadState {
@@ -102,6 +103,7 @@ struct YUVVideoQuadState {
float resource_offset;
float resource_multiplier;
uint32 bits_per_channel;
+ gfx.mojom.ColorSpace video_color_space;
};
union DrawQuadState {
diff --git a/chromium/cc/ipc/quads_struct_traits.cc b/chromium/cc/ipc/quads_struct_traits.cc
index 011f62771f9..2de061d5507 100644
--- a/chromium/cc/ipc/quads_struct_traits.cc
+++ b/chromium/cc/ipc/quads_struct_traits.cc
@@ -229,7 +229,8 @@ bool StructTraits<cc::mojom::YUVVideoQuadStateDataView, cc::DrawQuad>::Read(
if (!data.ReadYaTexCoordRect(&quad->ya_tex_coord_rect) ||
!data.ReadUvTexCoordRect(&quad->uv_tex_coord_rect) ||
!data.ReadYaTexSize(&quad->ya_tex_size) ||
- !data.ReadUvTexSize(&quad->uv_tex_size)) {
+ !data.ReadUvTexSize(&quad->uv_tex_size) ||
+ !data.ReadVideoColorSpace(&quad->video_color_space)) {
return false;
}
quad->resources.ids[cc::YUVVideoDrawQuad::kYPlaneResourceIdIndex] =
diff --git a/chromium/cc/ipc/quads_struct_traits.h b/chromium/cc/ipc/quads_struct_traits.h
index ed27b9921ce..ebeb86c7de8 100644
--- a/chromium/cc/ipc/quads_struct_traits.h
+++ b/chromium/cc/ipc/quads_struct_traits.h
@@ -21,6 +21,7 @@
#include "cc/quads/tile_draw_quad.h"
#include "cc/quads/yuv_video_draw_quad.h"
#include "ui/gfx/geometry/mojo/geometry_struct_traits.h"
+#include "ui/gfx/ipc/color/gfx_param_traits.h"
namespace mojo {
@@ -414,6 +415,11 @@ struct StructTraits<cc::mojom::YUVVideoQuadStateDataView, cc::DrawQuad> {
cc::YUVVideoDrawQuad::MaterialCast(&input);
return quad->bits_per_channel;
}
+ static gfx::ColorSpace video_color_space(const cc::DrawQuad& input) {
+ const cc::YUVVideoDrawQuad* quad =
+ cc::YUVVideoDrawQuad::MaterialCast(&input);
+ return quad->video_color_space;
+ }
static bool Read(cc::mojom::YUVVideoQuadStateDataView data,
cc::DrawQuad* out);
diff --git a/chromium/cc/ipc/shared_quad_state.mojom b/chromium/cc/ipc/shared_quad_state.mojom
index d819acb0e66..cb1fdc0f9bd 100644
--- a/chromium/cc/ipc/shared_quad_state.mojom
+++ b/chromium/cc/ipc/shared_quad_state.mojom
@@ -11,8 +11,8 @@ struct SharedQuadState {
// gfx.mojom.Transforms quad rects into the target content space.
gfx.mojom.Transform quad_to_target_transform;
- // The size of the quads' originating layer in the space of the quad rects.
- gfx.mojom.Size quad_layer_bounds;
+ // The rect of the quads' originating layer in the space of the quad rects.
+ gfx.mojom.Rect quad_layer_rect;
// The size of the visible area in the quads' originating layer, in the space
// of the quad rects.
diff --git a/chromium/cc/ipc/shared_quad_state_struct_traits.h b/chromium/cc/ipc/shared_quad_state_struct_traits.h
index 8b62a34eacc..5b6dd2877de 100644
--- a/chromium/cc/ipc/shared_quad_state_struct_traits.h
+++ b/chromium/cc/ipc/shared_quad_state_struct_traits.h
@@ -25,8 +25,8 @@ struct StructTraits<cc::mojom::SharedQuadStateDataView, OptSharedQuadState> {
return input.sqs->quad_to_target_transform;
}
- static const gfx::Size& quad_layer_bounds(const OptSharedQuadState& input) {
- return input.sqs->quad_layer_bounds;
+ static const gfx::Rect& quad_layer_rect(const OptSharedQuadState& input) {
+ return input.sqs->quad_layer_rect;
}
static const gfx::Rect& visible_quad_layer_rect(
@@ -62,8 +62,8 @@ struct StructTraits<cc::mojom::SharedQuadStateDataView, cc::SharedQuadState> {
return sqs.quad_to_target_transform;
}
- static const gfx::Size& quad_layer_bounds(const cc::SharedQuadState& sqs) {
- return sqs.quad_layer_bounds;
+ static const gfx::Rect& quad_layer_rect(const cc::SharedQuadState& sqs) {
+ return sqs.quad_layer_rect;
}
static const gfx::Rect& visible_quad_layer_rect(
@@ -92,7 +92,7 @@ struct StructTraits<cc::mojom::SharedQuadStateDataView, cc::SharedQuadState> {
static bool Read(cc::mojom::SharedQuadStateDataView data,
cc::SharedQuadState* out) {
if (!data.ReadQuadToTargetTransform(&out->quad_to_target_transform) ||
- !data.ReadQuadLayerBounds(&out->quad_layer_bounds) ||
+ !data.ReadQuadLayerRect(&out->quad_layer_rect) ||
!data.ReadVisibleQuadLayerRect(&out->visible_quad_layer_rect) ||
!data.ReadClipRect(&out->clip_rect)) {
return false;
diff --git a/chromium/cc/ipc/struct_traits_unittest.cc b/chromium/cc/ipc/struct_traits_unittest.cc
index d132d29b7bb..40c402b3dc0 100644
--- a/chromium/cc/ipc/struct_traits_unittest.cc
+++ b/chromium/cc/ipc/struct_traits_unittest.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <utility>
+
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "cc/input/selection.h"
@@ -38,99 +40,90 @@ class StructTraitsTest : public testing::Test, public mojom::TraitsTestService {
private:
// TraitsTestService:
void EchoBeginFrameArgs(const BeginFrameArgs& b,
- const EchoBeginFrameArgsCallback& callback) override {
- callback.Run(b);
+ EchoBeginFrameArgsCallback callback) override {
+ std::move(callback).Run(b);
}
void EchoBeginFrameAck(const BeginFrameAck& b,
- const EchoBeginFrameAckCallback& callback) override {
- callback.Run(b);
+ EchoBeginFrameAckCallback callback) override {
+ std::move(callback).Run(b);
}
- void EchoCompositorFrame(
- CompositorFrame c,
- const EchoCompositorFrameCallback& callback) override {
- callback.Run(std::move(c));
+ void EchoCompositorFrame(CompositorFrame c,
+ EchoCompositorFrameCallback callback) override {
+ std::move(callback).Run(std::move(c));
}
void EchoCompositorFrameMetadata(
CompositorFrameMetadata c,
- const EchoCompositorFrameMetadataCallback& callback) override {
- callback.Run(std::move(c));
+ EchoCompositorFrameMetadataCallback callback) override {
+ std::move(callback).Run(std::move(c));
}
- void EchoCopyOutputRequest(
- std::unique_ptr<CopyOutputRequest> c,
- const EchoCopyOutputRequestCallback& callback) override {
- callback.Run(std::move(c));
+ void EchoCopyOutputRequest(std::unique_ptr<CopyOutputRequest> c,
+ EchoCopyOutputRequestCallback callback) override {
+ std::move(callback).Run(std::move(c));
}
- void EchoCopyOutputResult(
- std::unique_ptr<CopyOutputResult> c,
- const EchoCopyOutputResultCallback& callback) override {
- callback.Run(std::move(c));
+ void EchoCopyOutputResult(std::unique_ptr<CopyOutputResult> c,
+ EchoCopyOutputResultCallback callback) override {
+ std::move(callback).Run(std::move(c));
}
- void EchoFilterOperation(
- const FilterOperation& f,
- const EchoFilterOperationCallback& callback) override {
- callback.Run(f);
+ void EchoFilterOperation(const FilterOperation& f,
+ EchoFilterOperationCallback callback) override {
+ std::move(callback).Run(f);
}
- void EchoFilterOperations(
- const FilterOperations& f,
- const EchoFilterOperationsCallback& callback) override {
- callback.Run(f);
+ void EchoFilterOperations(const FilterOperations& f,
+ EchoFilterOperationsCallback callback) override {
+ std::move(callback).Run(f);
}
void EchoRenderPass(std::unique_ptr<RenderPass> r,
- const EchoRenderPassCallback& callback) override {
- callback.Run(std::move(r));
+ EchoRenderPassCallback callback) override {
+ std::move(callback).Run(std::move(r));
}
- void EchoReturnedResource(
- const ReturnedResource& r,
- const EchoReturnedResourceCallback& callback) override {
- callback.Run(r);
+ void EchoReturnedResource(const ReturnedResource& r,
+ EchoReturnedResourceCallback callback) override {
+ std::move(callback).Run(r);
}
void EchoSelection(const Selection<gfx::SelectionBound>& s,
- const EchoSelectionCallback& callback) override {
- callback.Run(s);
+ EchoSelectionCallback callback) override {
+ std::move(callback).Run(s);
}
- void EchoSharedQuadState(
- const SharedQuadState& s,
- const EchoSharedQuadStateCallback& callback) override {
- callback.Run(s);
+ void EchoSharedQuadState(const SharedQuadState& s,
+ EchoSharedQuadStateCallback callback) override {
+ std::move(callback).Run(s);
}
void EchoSurfaceId(const SurfaceId& s,
- const EchoSurfaceIdCallback& callback) override {
- callback.Run(s);
+ EchoSurfaceIdCallback callback) override {
+ std::move(callback).Run(s);
}
- void EchoSurfaceReference(
- const SurfaceReference& s,
- const EchoSurfaceReferenceCallback& callback) override {
- callback.Run(s);
+ void EchoSurfaceReference(const SurfaceReference& s,
+ EchoSurfaceReferenceCallback callback) override {
+ std::move(callback).Run(s);
}
- void EchoSurfaceSequence(
- const SurfaceSequence& s,
- const EchoSurfaceSequenceCallback& callback) override {
- callback.Run(s);
+ void EchoSurfaceSequence(const SurfaceSequence& s,
+ EchoSurfaceSequenceCallback callback) override {
+ std::move(callback).Run(s);
}
void EchoTextureMailbox(const TextureMailbox& t,
- const EchoTextureMailboxCallback& callback) override {
- callback.Run(t);
+ EchoTextureMailboxCallback callback) override {
+ std::move(callback).Run(t);
}
void EchoTransferableResource(
const TransferableResource& t,
- const EchoTransferableResourceCallback& callback) override {
- callback.Run(t);
+ EchoTransferableResourceCallback callback) override {
+ std::move(callback).Run(t);
}
mojo::BindingSet<TraitsTestService> traits_test_bindings_;
@@ -229,7 +222,7 @@ TEST_F(StructTraitsTest, CompositorFrame) {
const gfx::Transform sqs_quad_to_target_transform(
1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f, 10.f, 11.f, 12.f, 13.f, 14.f,
15.f, 16.f);
- const gfx::Size sqs_layer_bounds(1234, 5678);
+ const gfx::Rect sqs_layer_rect(1234, 5678);
const gfx::Rect sqs_visible_layer_rect(12, 34, 56, 78);
const gfx::Rect sqs_clip_rect(123, 456, 789, 101112);
const bool sqs_is_clipped = true;
@@ -237,7 +230,7 @@ TEST_F(StructTraitsTest, CompositorFrame) {
const SkBlendMode sqs_blend_mode = SkBlendMode::kSrcOver;
const int sqs_sorting_context_id = 1337;
SharedQuadState* sqs = render_pass->CreateAndAppendSharedQuadState();
- sqs->SetAll(sqs_quad_to_target_transform, sqs_layer_bounds,
+ sqs->SetAll(sqs_quad_to_target_transform, sqs_layer_rect,
sqs_visible_layer_rect, sqs_clip_rect, sqs_is_clipped,
sqs_opacity, sqs_blend_mode, sqs_sorting_context_id);
@@ -315,7 +308,7 @@ TEST_F(StructTraitsTest, CompositorFrame) {
const SharedQuadState* out_sqs =
out_render_pass->shared_quad_state_list.ElementAt(0);
EXPECT_EQ(sqs_quad_to_target_transform, out_sqs->quad_to_target_transform);
- EXPECT_EQ(sqs_layer_bounds, out_sqs->quad_layer_bounds);
+ EXPECT_EQ(sqs_layer_rect, out_sqs->quad_layer_rect);
EXPECT_EQ(sqs_visible_layer_rect, out_sqs->visible_quad_layer_rect);
EXPECT_EQ(sqs_clip_rect, out_sqs->clip_rect);
EXPECT_EQ(sqs_is_clipped, out_sqs->is_clipped);
@@ -374,11 +367,12 @@ TEST_F(StructTraitsTest, CompositorFrameMetadata) {
SurfaceId id(FrameSinkId(1234, 4321),
LocalSurfaceId(5678, base::UnguessableToken::Create()));
referenced_surfaces.push_back(id);
- std::vector<SurfaceId> embedded_surfaces;
+ std::vector<SurfaceId> activation_dependencies;
SurfaceId id2(FrameSinkId(4321, 1234),
LocalSurfaceId(8765, base::UnguessableToken::Create()));
- embedded_surfaces.push_back(id2);
+ activation_dependencies.push_back(id2);
uint32_t frame_token = 0xdeadbeef;
+ uint64_t begin_frame_ack_sequence_number = 0xdeadbeef;
CompositorFrameMetadata input;
input.device_scale_factor = device_scale_factor;
@@ -401,8 +395,9 @@ TEST_F(StructTraitsTest, CompositorFrameMetadata) {
input.selection = selection;
input.latency_info = latency_infos;
input.referenced_surfaces = referenced_surfaces;
- input.embedded_surfaces = embedded_surfaces;
+ input.activation_dependencies = activation_dependencies;
input.frame_token = frame_token;
+ input.begin_frame_ack.sequence_number = begin_frame_ack_sequence_number;
mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy();
CompositorFrameMetadata output;
@@ -434,10 +429,13 @@ TEST_F(StructTraitsTest, CompositorFrameMetadata) {
EXPECT_EQ(referenced_surfaces.size(), output.referenced_surfaces.size());
for (uint32_t i = 0; i < referenced_surfaces.size(); ++i)
EXPECT_EQ(referenced_surfaces[i], output.referenced_surfaces[i]);
- EXPECT_EQ(embedded_surfaces.size(), output.embedded_surfaces.size());
- for (uint32_t i = 0; i < embedded_surfaces.size(); ++i)
- EXPECT_EQ(embedded_surfaces[i], output.embedded_surfaces[i]);
+ EXPECT_EQ(activation_dependencies.size(),
+ output.activation_dependencies.size());
+ for (uint32_t i = 0; i < activation_dependencies.size(); ++i)
+ EXPECT_EQ(activation_dependencies[i], output.activation_dependencies[i]);
EXPECT_EQ(frame_token, output.frame_token);
+ EXPECT_EQ(begin_frame_ack_sequence_number,
+ output.begin_frame_ack.sequence_number);
}
TEST_F(StructTraitsTest, CopyOutputRequest_BitmapRequest) {
@@ -531,7 +529,8 @@ TEST_F(StructTraitsTest, CopyOutputResult_Bitmap) {
bitmap->allocN32Pixels(7, 8);
bitmap->eraseARGB(123, 213, 77, 33);
auto in_bitmap = base::MakeUnique<SkBitmap>();
- bitmap->deepCopyTo(in_bitmap.get());
+ in_bitmap->allocN32Pixels(7, 8);
+ in_bitmap->eraseARGB(123, 213, 77, 33);
auto input = CopyOutputResult::CreateBitmapResult(std::move(bitmap));
auto size = input->size();
@@ -844,14 +843,14 @@ TEST_F(StructTraitsTest, RenderPass) {
shared_state_1->SetAll(
gfx::Transform(16.1f, 15.3f, 14.3f, 13.7f, 12.2f, 11.4f, 10.4f, 9.8f,
8.1f, 7.3f, 6.3f, 5.7f, 4.8f, 3.4f, 2.4f, 1.2f),
- gfx::Size(1, 2), gfx::Rect(1337, 5679, 9101112, 131415),
+ gfx::Rect(1, 2), gfx::Rect(1337, 5679, 9101112, 131415),
gfx::Rect(1357, 2468, 121314, 1337), true, 2, SkBlendMode::kSrcOver, 1);
SharedQuadState* shared_state_2 = input->CreateAndAppendSharedQuadState();
shared_state_2->SetAll(
gfx::Transform(1.1f, 2.3f, 3.3f, 4.7f, 5.2f, 6.4f, 7.4f, 8.8f, 9.1f,
10.3f, 11.3f, 12.7f, 13.8f, 14.4f, 15.4f, 16.2f),
- gfx::Size(1337, 1234), gfx::Rect(1234, 5678, 9101112, 13141516),
+ gfx::Rect(1337, 1234), gfx::Rect(1234, 5678, 9101112, 13141516),
gfx::Rect(1357, 2468, 121314, 1337), true, 2, SkBlendMode::kSrcOver, 1);
// This quad uses the first shared quad state. The next two quads use the
@@ -896,7 +895,7 @@ TEST_F(StructTraitsTest, RenderPass) {
SharedQuadState* out_sqs1 = output->shared_quad_state_list.ElementAt(0);
EXPECT_EQ(shared_state_1->quad_to_target_transform,
out_sqs1->quad_to_target_transform);
- EXPECT_EQ(shared_state_1->quad_layer_bounds, out_sqs1->quad_layer_bounds);
+ EXPECT_EQ(shared_state_1->quad_layer_rect, out_sqs1->quad_layer_rect);
EXPECT_EQ(shared_state_1->visible_quad_layer_rect,
out_sqs1->visible_quad_layer_rect);
EXPECT_EQ(shared_state_1->clip_rect, out_sqs1->clip_rect);
@@ -908,7 +907,7 @@ TEST_F(StructTraitsTest, RenderPass) {
SharedQuadState* out_sqs2 = output->shared_quad_state_list.ElementAt(1);
EXPECT_EQ(shared_state_2->quad_to_target_transform,
out_sqs2->quad_to_target_transform);
- EXPECT_EQ(shared_state_2->quad_layer_bounds, out_sqs2->quad_layer_bounds);
+ EXPECT_EQ(shared_state_2->quad_layer_rect, out_sqs2->quad_layer_rect);
EXPECT_EQ(shared_state_2->visible_quad_layer_rect,
out_sqs2->visible_quad_layer_rect);
EXPECT_EQ(shared_state_2->clip_rect, out_sqs2->clip_rect);
@@ -948,7 +947,9 @@ TEST_F(StructTraitsTest, RenderPassWithEmptySharedQuadStateList) {
const gfx::Transform transform_to_root =
gfx::Transform(1.0, 0.5, 0.5, -0.5, -1.0, 0.0);
const gfx::Rect damage_rect(56, 123, 19, 43);
- gfx::ColorSpace color_space = gfx::ColorSpace::CreateSCRGBLinear();
+ SkMatrix44 to_XYZD50;
+ SkColorSpaceTransferFn fn = {1, 0, 1, 0, 0, 0, 1};
+ gfx::ColorSpace color_space = gfx::ColorSpace::CreateCustom(to_XYZD50, fn);
const bool has_transparent_background = true;
std::unique_ptr<RenderPass> input = RenderPass::Create();
input->SetAll(id, output_rect, damage_rect, transform_to_root,
@@ -1062,7 +1063,7 @@ TEST_F(StructTraitsTest, SharedQuadState) {
const gfx::Transform quad_to_target_transform(1.f, 2.f, 3.f, 4.f, 5.f, 6.f,
7.f, 8.f, 9.f, 10.f, 11.f, 12.f,
13.f, 14.f, 15.f, 16.f);
- const gfx::Size layer_bounds(1234, 5678);
+ const gfx::Rect layer_rect(1234, 5678);
const gfx::Rect visible_layer_rect(12, 34, 56, 78);
const gfx::Rect clip_rect(123, 456, 789, 101112);
const bool is_clipped = true;
@@ -1070,14 +1071,14 @@ TEST_F(StructTraitsTest, SharedQuadState) {
const SkBlendMode blend_mode = SkBlendMode::kSrcOver;
const int sorting_context_id = 1337;
SharedQuadState input_sqs;
- input_sqs.SetAll(quad_to_target_transform, layer_bounds, visible_layer_rect,
+ input_sqs.SetAll(quad_to_target_transform, layer_rect, visible_layer_rect,
clip_rect, is_clipped, opacity, blend_mode,
sorting_context_id);
mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy();
SharedQuadState output_sqs;
proxy->EchoSharedQuadState(input_sqs, &output_sqs);
EXPECT_EQ(quad_to_target_transform, output_sqs.quad_to_target_transform);
- EXPECT_EQ(layer_bounds, output_sqs.quad_layer_bounds);
+ EXPECT_EQ(layer_rect, output_sqs.quad_layer_rect);
EXPECT_EQ(visible_layer_rect, output_sqs.visible_quad_layer_rect);
EXPECT_EQ(clip_rect, output_sqs.clip_rect);
EXPECT_EQ(is_clipped, output_sqs.is_clipped);
@@ -1101,8 +1102,9 @@ TEST_F(StructTraitsTest, TextureMailbox) {
const bool is_overlay_candidate = true;
const bool secure_output_only = true;
const bool nearest_neighbor = true;
- const gfx::ColorSpace color_space =
- gfx::ColorSpace::CreateVideo(4, 5, 9, gfx::ColorSpace::RangeID::LIMITED);
+ const gfx::ColorSpace color_space = gfx::ColorSpace(
+ gfx::ColorSpace::PrimaryID::BT470M, gfx::ColorSpace::TransferID::GAMMA28,
+ gfx::ColorSpace::MatrixID::BT2020_NCL, gfx::ColorSpace::RangeID::LIMITED);
#if defined(OS_ANDROID)
const bool is_backed_by_surface_texture = true;
const bool wants_promotion_hint = true;
diff --git a/chromium/cc/ipc/transferable_resource.mojom b/chromium/cc/ipc/transferable_resource.mojom
index 971536c3b94..ea20a63f826 100644
--- a/chromium/cc/ipc/transferable_resource.mojom
+++ b/chromium/cc/ipc/transferable_resource.mojom
@@ -6,6 +6,7 @@ module cc.mojom;
import "gpu/ipc/common/mailbox_holder.mojom";
import "ui/gfx/geometry/mojo/geometry.mojom";
+import "ui/gfx/mojo/color_space.mojom";
import "ui/gfx/mojo/buffer_types.mojom";
enum ResourceFormat {
@@ -31,4 +32,5 @@ struct TransferableResource {
bool is_overlay_candidate;
bool is_backed_by_surface_texture;
bool wants_promotion_hint;
+ gfx.mojom.ColorSpace color_space;
};
diff --git a/chromium/cc/ipc/transferable_resource_struct_traits.cc b/chromium/cc/ipc/transferable_resource_struct_traits.cc
index 140276a32b0..ea6c56d3398 100644
--- a/chromium/cc/ipc/transferable_resource_struct_traits.cc
+++ b/chromium/cc/ipc/transferable_resource_struct_traits.cc
@@ -16,7 +16,8 @@ bool StructTraits<cc::mojom::TransferableResourceDataView,
Read(cc::mojom::TransferableResourceDataView data,
cc::TransferableResource* out) {
if (!data.ReadSize(&out->size) ||
- !data.ReadMailboxHolder(&out->mailbox_holder))
+ !data.ReadMailboxHolder(&out->mailbox_holder) ||
+ !data.ReadColorSpace(&out->color_space))
return false;
out->id = data.id();
out->format = static_cast<cc::ResourceFormat>(data.format());
diff --git a/chromium/cc/ipc/transferable_resource_struct_traits.h b/chromium/cc/ipc/transferable_resource_struct_traits.h
index 1e3f24b7567..e9964c6fce3 100644
--- a/chromium/cc/ipc/transferable_resource_struct_traits.h
+++ b/chromium/cc/ipc/transferable_resource_struct_traits.h
@@ -7,6 +7,7 @@
#include "cc/ipc/transferable_resource.mojom-shared.h"
#include "cc/resources/transferable_resource.h"
+#include "ui/gfx/ipc/color/gfx_param_traits.h"
namespace mojo {
@@ -74,6 +75,11 @@ struct StructTraits<cc::mojom::TransferableResourceDataView,
#endif
}
+ static const gfx::ColorSpace& color_space(
+ const cc::TransferableResource& resource) {
+ return resource.color_space;
+ }
+
static bool Read(cc::mojom::TransferableResourceDataView data,
cc::TransferableResource* out);
};
diff --git a/chromium/cc/layers/append_quads_data.h b/chromium/cc/layers/append_quads_data.h
index 45afa469072..5fec36e9506 100644
--- a/chromium/cc/layers/append_quads_data.h
+++ b/chromium/cc/layers/append_quads_data.h
@@ -30,8 +30,10 @@ class CC_EXPORT AppendQuadsData {
int64_t checkerboarded_no_recording_content_area = 0;
// This is the area within interest rect.
int64_t checkerboarded_needs_raster_content_area = 0;
- // This is the set of surface IDs embedded in SurfaceDrawQuads.
- std::vector<SurfaceId> embedded_surfaces;
+ // This is the set of surface IDs that must have corresponding
+ // active CompositorFrames so that this CompositorFrame can
+ // activate.
+ std::vector<SurfaceId> activation_dependencies;
};
} // namespace cc
diff --git a/chromium/cc/layers/effect_tree_layer_list_iterator.cc b/chromium/cc/layers/effect_tree_layer_list_iterator.cc
index a5228dcb851..340fb94afdc 100644
--- a/chromium/cc/layers/effect_tree_layer_list_iterator.cc
+++ b/chromium/cc/layers/effect_tree_layer_list_iterator.cc
@@ -17,9 +17,8 @@ EffectTreeLayerListIterator::EffectTreeLayerListIterator(
layer_list_iterator_ = layer_tree_impl->rbegin();
// Find the front-most drawn layer.
- while (
- layer_list_iterator_ != layer_tree_impl->rend() &&
- !(*layer_list_iterator_)->is_drawn_render_surface_layer_list_member()) {
+ while (layer_list_iterator_ != layer_tree_impl->rend() &&
+ !(*layer_list_iterator_)->contributes_to_drawn_render_surface()) {
layer_list_iterator_++;
}
@@ -43,28 +42,13 @@ EffectTreeLayerListIterator::EffectTreeLayerListIterator(
EffectTreeLayerListIterator::~EffectTreeLayerListIterator() {}
-// Finds the lowest common ancestor that has a render surface.
-static int LowestCommonAncestor(int effect_id_1,
- int effect_id_2,
- const EffectTree* effect_tree) {
- while (effect_id_1 != effect_id_2) {
- if (effect_id_1 < effect_id_2)
- effect_id_2 = effect_tree->Node(effect_id_2)->target_id;
- else
- effect_id_1 = effect_tree->Node(effect_id_1)->target_id;
- }
-
- return effect_id_1;
-}
-
void EffectTreeLayerListIterator::operator++() {
switch (state_) {
case State::LAYER:
// Find the next drawn layer.
layer_list_iterator_++;
while (layer_list_iterator_ != layer_tree_impl_->rend() &&
- !(*layer_list_iterator_)
- ->is_drawn_render_surface_layer_list_member()) {
+ !(*layer_list_iterator_)->contributes_to_drawn_render_surface()) {
layer_list_iterator_++;
}
if (layer_list_iterator_ == layer_tree_impl_->rend()) {
@@ -80,8 +64,9 @@ void EffectTreeLayerListIterator::operator++() {
// If the next drawn layer has a different target effect tree index, check
// for surfaces whose contributors have all been visited.
if (next_effect_tree_index_ != current_effect_tree_index_) {
- lowest_common_effect_tree_ancestor_index_ = LowestCommonAncestor(
- current_effect_tree_index_, next_effect_tree_index_, effect_tree_);
+ lowest_common_effect_tree_ancestor_index_ =
+ effect_tree_->LowestCommonAncestorWithRenderSurface(
+ current_effect_tree_index_, next_effect_tree_index_);
// If the current layer's target effect node is an ancestor of the next
// layer's target effect node, then the current effect node still has
// more contributors that need to be visited. Otherwise, all
diff --git a/chromium/cc/layers/effect_tree_layer_list_iterator_unittest.cc b/chromium/cc/layers/effect_tree_layer_list_iterator_unittest.cc
index 6d6fb8d0a9b..71fc0fc207a 100644
--- a/chromium/cc/layers/effect_tree_layer_list_iterator_unittest.cc
+++ b/chromium/cc/layers/effect_tree_layer_list_iterator_unittest.cc
@@ -9,6 +9,7 @@
#include "base/memory/ptr_util.h"
#include "cc/layers/layer.h"
#include "cc/test/fake_layer_tree_host.h"
+#include "cc/test/layer_test_common.h"
#include "cc/test/test_task_graph_runner.h"
#include "cc/trees/layer_tree_host_common.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -37,7 +38,7 @@ class TestLayerImpl : public LayerImpl {
};
#define EXPECT_COUNT(layer, target, contrib, itself) \
- if (layer->GetRenderSurface()) { \
+ if (GetRenderSurface(layer)) { \
EXPECT_EQ(target, target_surface_count_[layer->effect_tree_index()]); \
EXPECT_EQ(contrib, \
contributing_surface_count_[layer->effect_tree_index()]); \
@@ -108,9 +109,9 @@ TEST_F(EffectTreeLayerListIteratorTest, TreeWithNoDrawnLayers) {
host_impl_.active_tree()->SetRootLayerForTesting(std::move(root_layer));
- LayerImplList render_surface_layer_list;
+ RenderSurfaceList render_surface_list;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root_ptr, root_ptr->bounds(), &render_surface_layer_list);
+ root_ptr, root_ptr->bounds(), &render_surface_list);
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
IterateFrontToBack();
@@ -137,17 +138,17 @@ TEST_F(EffectTreeLayerListIteratorTest, SimpleTree) {
host_impl_.active_tree()->SetRootLayerForTesting(std::move(root_layer));
- LayerImplList render_surface_layer_list;
+ RenderSurfaceList render_surface_list;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root_ptr, root_ptr->bounds(), &render_surface_layer_list);
+ root_ptr, root_ptr->bounds(), &render_surface_list);
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
IterateFrontToBack();
EXPECT_COUNT(root_ptr, 5, -1, 4);
- EXPECT_COUNT(first_ptr, -1, -1, 3);
- EXPECT_COUNT(second_ptr, -1, -1, 2);
- EXPECT_COUNT(third_ptr, -1, -1, 1);
- EXPECT_COUNT(fourth_ptr, -1, -1, 0);
+ EXPECT_COUNT(first_ptr, 5, -1, 3);
+ EXPECT_COUNT(second_ptr, 5, -1, 2);
+ EXPECT_COUNT(third_ptr, 5, -1, 1);
+ EXPECT_COUNT(fourth_ptr, 5, -1, 0);
}
TEST_F(EffectTreeLayerListIteratorTest, ComplexTree) {
@@ -182,21 +183,21 @@ TEST_F(EffectTreeLayerListIteratorTest, ComplexTree) {
host_impl_.active_tree()->SetRootLayerForTesting(std::move(root_layer));
- LayerImplList render_surface_layer_list;
+ RenderSurfaceList render_surface_list;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root_ptr, root_ptr->bounds(), &render_surface_layer_list);
+ root_ptr, root_ptr->bounds(), &render_surface_list);
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
IterateFrontToBack();
EXPECT_COUNT(root_ptr, 9, -1, 8);
- EXPECT_COUNT(root1_ptr, -1, -1, 7);
- EXPECT_COUNT(root2_ptr, -1, -1, 6);
- EXPECT_COUNT(root21_ptr, -1, -1, 5);
- EXPECT_COUNT(root22_ptr, -1, -1, 4);
- EXPECT_COUNT(root221_ptr, -1, -1, 3);
- EXPECT_COUNT(root23_ptr, -1, -1, 2);
- EXPECT_COUNT(root231_ptr, -1, -1, 1);
- EXPECT_COUNT(root3_ptr, -1, -1, 0);
+ EXPECT_COUNT(root1_ptr, 9, -1, 7);
+ EXPECT_COUNT(root2_ptr, 9, -1, 6);
+ EXPECT_COUNT(root21_ptr, 9, -1, 5);
+ EXPECT_COUNT(root22_ptr, 9, -1, 4);
+ EXPECT_COUNT(root221_ptr, 9, -1, 3);
+ EXPECT_COUNT(root23_ptr, 9, -1, 2);
+ EXPECT_COUNT(root231_ptr, 9, -1, 1);
+ EXPECT_COUNT(root3_ptr, 9, -1, 0);
}
TEST_F(EffectTreeLayerListIteratorTest, ComplexTreeMultiSurface) {
@@ -235,21 +236,21 @@ TEST_F(EffectTreeLayerListIteratorTest, ComplexTreeMultiSurface) {
host_impl_.active_tree()->SetRootLayerForTesting(std::move(root_layer));
- LayerImplList render_surface_layer_list;
+ RenderSurfaceList render_surface_list;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root_ptr, root_ptr->bounds(), &render_surface_layer_list);
+ root_ptr, root_ptr->bounds(), &render_surface_list);
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
IterateFrontToBack();
EXPECT_COUNT(root_ptr, 14, -1, 13);
- EXPECT_COUNT(root1_ptr, -1, -1, 12);
+ EXPECT_COUNT(root1_ptr, 14, -1, 12);
EXPECT_COUNT(root2_ptr, 10, 11, -1);
- EXPECT_COUNT(root21_ptr, -1, -1, 9);
+ EXPECT_COUNT(root21_ptr, 10, 11, 9);
EXPECT_COUNT(root22_ptr, 7, 8, 6);
- EXPECT_COUNT(root221_ptr, -1, -1, 5);
+ EXPECT_COUNT(root221_ptr, 7, 8, 5);
EXPECT_COUNT(root23_ptr, 3, 4, 2);
- EXPECT_COUNT(root231_ptr, -1, -1, 1);
- EXPECT_COUNT(root3_ptr, -1, -1, 0);
+ EXPECT_COUNT(root231_ptr, 3, 4, 1);
+ EXPECT_COUNT(root3_ptr, 14, -1, 0);
}
} // namespace
diff --git a/chromium/cc/layers/heads_up_display_layer_impl.cc b/chromium/cc/layers/heads_up_display_layer_impl.cc
index 7340f184c1f..bde1f0c1f76 100644
--- a/chromium/cc/layers/heads_up_display_layer_impl.cc
+++ b/chromium/cc/layers/heads_up_display_layer_impl.cc
@@ -607,10 +607,6 @@ SkRect HeadsUpDisplayLayerImpl::DrawGpuRasterizationStatus(SkCanvas* canvas,
status = "MSAA (content)";
color = SK_ColorCYAN;
break;
- case GpuRasterizationStatus::OFF_CONTENT:
- status = "off (content)";
- color = SK_ColorYELLOW;
- break;
}
if (status.empty())
diff --git a/chromium/cc/layers/layer.cc b/chromium/cc/layers/layer.cc
index 72a530a3bf3..d3100f3daa8 100644
--- a/chromium/cc/layers/layer.cc
+++ b/chromium/cc/layers/layer.cc
@@ -93,6 +93,7 @@ Layer::Layer()
may_contain_video_(false),
is_scroll_clip_layer_(false),
needs_show_scrollbars_(false),
+ subtree_has_copy_request_(false),
safe_opaque_background_color_(0),
num_unclipped_descendants_(0) {}
@@ -123,7 +124,8 @@ void Layer::SetLayerTreeHost(LayerTreeHost* host) {
layer_tree_host_->property_trees()->RemoveIdFromIdToIndexMaps(id());
layer_tree_host_->property_trees()->needs_rebuild = true;
layer_tree_host_->UnregisterLayer(this);
- if (inputs_.element_id) {
+ if (!layer_tree_host_->GetSettings().use_layer_lists &&
+ inputs_.element_id) {
layer_tree_host_->UnregisterElement(inputs_.element_id,
ElementListType::ACTIVE, this);
}
@@ -131,7 +133,7 @@ void Layer::SetLayerTreeHost(LayerTreeHost* host) {
if (host) {
host->property_trees()->needs_rebuild = true;
host->RegisterLayer(this);
- if (inputs_.element_id) {
+ if (!host->GetSettings().use_layer_lists && inputs_.element_id) {
host->RegisterElement(inputs_.element_id, ElementListType::ACTIVE, this);
}
}
@@ -149,12 +151,10 @@ void Layer::SetLayerTreeHost(LayerTreeHost* host) {
if (inputs_.mask_layer.get())
inputs_.mask_layer->SetLayerTreeHost(host);
- const bool has_any_animation =
- layer_tree_host_ ? GetMutatorHost()->HasAnyAnimation(element_id())
- : false;
-
- if (host && has_any_animation)
+ if (host && !host->GetSettings().use_layer_lists &&
+ GetMutatorHost()->HasAnyAnimation(element_id())) {
host->SetNeedsCommit();
+ }
}
void Layer::SetNeedsCommit() {
@@ -362,6 +362,20 @@ void Layer::RequestCopyOfOutput(std::unique_ptr<CopyOutputRequest> request) {
SetSubtreePropertyChanged();
SetPropertyTreesNeedRebuild();
SetNeedsCommit();
+ if (layer_tree_host_)
+ layer_tree_host_->SetHasCopyRequest(true);
+}
+
+void Layer::SetSubtreeHasCopyRequest(bool subtree_has_copy_request) {
+ subtree_has_copy_request_ = subtree_has_copy_request;
+}
+
+bool Layer::SubtreeHasCopyRequest() const {
+ DCHECK(layer_tree_host_);
+ // When the copy request is pushed to effect tree, we reset layer tree host's
+ // has_copy_request but do not clear subtree_has_copy_request on individual
+ // layers.
+ return layer_tree_host_->has_copy_request() && subtree_has_copy_request_;
}
void Layer::SetBackgroundColor(SkColor background_color) {
@@ -497,10 +511,6 @@ bool Layer::OpacityCanAnimateOnImplThread() const {
return false;
}
-bool Layer::AlwaysUseActiveTreeOpacity() const {
- return false;
-}
-
void Layer::SetBlendMode(SkBlendMode blend_mode) {
DCHECK(IsPropertyChangeAllowed());
if (inputs_.blend_mode == blend_mode)
@@ -684,11 +694,6 @@ bool Layer::ScrollOffsetAnimationWasInterrupted() const {
return GetMutatorHost()->ScrollOffsetAnimationWasInterrupted(element_id());
}
-bool Layer::HasOnlyTranslationTransforms() const {
- return GetMutatorHost()->HasOnlyTranslationTransforms(
- element_id(), GetElementTypeForAnimation());
-}
-
void Layer::SetScrollParent(Layer* parent) {
DCHECK(IsPropertyChangeAllowed());
if (inputs_.scroll_parent == parent)
@@ -761,17 +766,7 @@ void Layer::SetScrollOffset(const gfx::ScrollOffset& scroll_offset) {
if (!layer_tree_host_)
return;
- PropertyTrees* property_trees = layer_tree_host_->property_trees();
- if (scroll_tree_index() != ScrollTree::kInvalidNodeId && scrollable())
- property_trees->scroll_tree.SetScrollOffset(id(), scroll_offset);
-
- if (TransformNode* transform_node =
- property_trees->transform_tree.UpdateNodeFromOwningLayerId(id())) {
- DCHECK_EQ(transform_tree_index(), transform_node->id);
- transform_node->scroll_offset = CurrentScrollOffset();
- transform_node->needs_local_transform_update = true;
- property_trees->transform_tree.set_needs_update(true);
- }
+ UpdateScrollOffset(scroll_offset);
SetNeedsCommit();
}
@@ -787,17 +782,7 @@ void Layer::SetScrollOffsetFromImplSide(
inputs_.scroll_offset = scroll_offset;
SetNeedsPushProperties();
- PropertyTrees* property_trees = layer_tree_host_->property_trees();
- if (scroll_tree_index() != ScrollTree::kInvalidNodeId && scrollable())
- property_trees->scroll_tree.SetScrollOffset(id(), scroll_offset);
-
- if (TransformNode* transform_node =
- property_trees->transform_tree.UpdateNodeFromOwningLayerId(id())) {
- DCHECK_EQ(transform_tree_index(), transform_node->id);
- transform_node->scroll_offset = CurrentScrollOffset();
- transform_node->needs_local_transform_update = true;
- property_trees->transform_tree.set_needs_update(true);
- }
+ UpdateScrollOffset(scroll_offset);
if (!inputs_.did_scroll_callback.is_null())
inputs_.did_scroll_callback.Run(scroll_offset);
@@ -806,6 +791,28 @@ void Layer::SetScrollOffsetFromImplSide(
// "this" may have been destroyed during the process.
}
+void Layer::UpdateScrollOffset(const gfx::ScrollOffset& scroll_offset) {
+ DCHECK(scrollable());
+ if (scroll_tree_index() == ScrollTree::kInvalidNodeId) {
+ // Ensure the property trees just have not been built yet but are marked for
+ // being built which will set the correct scroll offset values.
+ DCHECK(layer_tree_host_->property_trees()->needs_rebuild);
+ return;
+ }
+
+ // If a scroll node exists, it should have an associated transform node.
+ DCHECK(transform_tree_index() != TransformTree::kInvalidNodeId);
+
+ auto& property_trees = *layer_tree_host_->property_trees();
+ property_trees.scroll_tree.SetScrollOffset(id(), scroll_offset);
+ auto* transform_node =
+ property_trees.transform_tree.Node(transform_tree_index());
+ DCHECK_EQ(transform_tree_index(), transform_node->id);
+ transform_node->scroll_offset = CurrentScrollOffset();
+ transform_node->needs_local_transform_update = true;
+ property_trees.transform_tree.set_needs_update(true);
+}
+
void Layer::SetScrollClipLayerId(int clip_layer_id) {
DCHECK(IsPropertyChangeAllowed());
if (inputs_.scroll_clip_layer_id == clip_layer_id)
@@ -1124,15 +1131,12 @@ void Layer::PushPropertiesTo(LayerImpl* layer) {
TRACE_EVENT0("cc", "Layer::PushPropertiesTo");
DCHECK(layer_tree_host_);
- // If we did not SavePaintProperties() for the layer this frame, then push the
- // real property values, not the paint property values.
- bool use_paint_properties = paint_properties_.source_frame_number ==
- layer_tree_host_->SourceFrameNumber();
-
+ // The ElementId should be set first because other setters depend on it such
+ // as LayerImpl::SetScrollClipLayer.
+ layer->SetElementId(inputs_.element_id);
layer->SetBackgroundColor(inputs_.background_color);
layer->SetSafeOpaqueBackgroundColor(safe_opaque_background_color_);
- layer->SetBounds(use_paint_properties ? paint_properties_.bounds
- : inputs_.bounds);
+ layer->SetBounds(inputs_.bounds);
#if defined(NDEBUG)
if (frame_viewer_instrumentation::IsTracingLayerTreeSnapshots())
@@ -1169,9 +1173,12 @@ void Layer::PushPropertiesTo(LayerImpl* layer) {
layer->SetScrollClipLayer(inputs_.scroll_clip_layer_id);
layer->set_user_scrollable_horizontal(inputs_.user_scrollable_horizontal);
layer->set_user_scrollable_vertical(inputs_.user_scrollable_vertical);
- layer->SetElementId(inputs_.element_id);
layer->SetMutableProperties(inputs_.mutable_properties);
+ // The property trees must be safe to access because they will be used below
+ // to call |SetScrollOffsetClobberActiveValue|.
+ DCHECK(layer->layer_tree_impl()->lifecycle().AllowsPropertyTreeAccess());
+
// When a scroll offset animation is interrupted the new scroll position on
// the pending tree will clobber any impl-side scrolling occuring on the
// active tree. To do so, avoid scrolling the pending tree along with it
@@ -1254,20 +1261,8 @@ int Layer::NumDescendantsThatDrawContent() const {
return num_descendants_that_draw_content_;
}
-void Layer::SavePaintProperties() {
- DCHECK(layer_tree_host_);
-
- // TODO(reveman): Save all layer properties that we depend on not
- // changing until PushProperties() has been called. crbug.com/231016
- paint_properties_.bounds = inputs_.bounds;
- paint_properties_.source_frame_number = layer_tree_host_->SourceFrameNumber();
-}
-
bool Layer::Update() {
DCHECK(layer_tree_host_);
- DCHECK_EQ(layer_tree_host_->SourceFrameNumber(),
- paint_properties_.source_frame_number)
- << "SavePaintProperties must be called for any layer that is painted.";
return false;
}
@@ -1307,16 +1302,6 @@ void Layer::SetScrollbarsHiddenFromImplSide(bool hidden) {
inputs_.client->didChangeScrollbarsHidden(hidden);
}
-bool Layer::FilterIsAnimating() const {
- return GetMutatorHost()->IsAnimatingFilterProperty(
- element_id(), GetElementTypeForAnimation());
-}
-
-bool Layer::TransformIsAnimating() const {
- return GetMutatorHost()->IsAnimatingTransformProperty(
- element_id(), GetElementTypeForAnimation());
-}
-
gfx::ScrollOffset Layer::ScrollOffsetForAnimation() const {
return CurrentScrollOffset();
}
@@ -1436,10 +1421,10 @@ void Layer::SetMutableProperties(uint32_t properties) {
SetNeedsCommit();
}
-int Layer::num_copy_requests_in_target_subtree() {
+bool Layer::has_copy_requests_in_target_subtree() {
return layer_tree_host_->property_trees()
->effect_tree.Node(effect_tree_index())
- ->num_copy_requests_in_subtree;
+ ->subtree_has_copy_request;
}
gfx::Transform Layer::ScreenSpaceTransform() const {
diff --git a/chromium/cc/layers/layer.h b/chromium/cc/layers/layer.h
index 58dde9c4577..c88721b0fa6 100644
--- a/chromium/cc/layers/layer.h
+++ b/chromium/cc/layers/layer.h
@@ -24,7 +24,6 @@
#include "cc/input/input_handler.h"
#include "cc/layers/layer_collections.h"
#include "cc/layers/layer_position_constraint.h"
-#include "cc/layers/paint_properties.h"
#include "cc/paint/paint_record.h"
#include "cc/trees/element_id.h"
#include "cc/trees/mutator_host_client.h"
@@ -97,6 +96,9 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
void RequestCopyOfOutput(std::unique_ptr<CopyOutputRequest> request);
bool HasCopyRequest() const { return !inputs_.copy_requests.empty(); }
+ void SetSubtreeHasCopyRequest(bool subtree_has_copy_request);
+ bool SubtreeHasCopyRequest() const;
+
void TakeCopyRequests(
std::vector<std::unique_ptr<CopyOutputRequest>>* requests);
@@ -127,8 +129,6 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
float EffectiveOpacity() const;
virtual bool OpacityCanAnimateOnImplThread() const;
- virtual bool AlwaysUseActiveTreeOpacity() const;
-
void SetBlendMode(SkBlendMode blend_mode);
SkBlendMode blend_mode() const { return inputs_.blend_mode; }
@@ -163,10 +163,6 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
void SetIsContainerForFixedPositionLayers(bool container);
bool IsContainerForFixedPositionLayers() const;
- gfx::Vector2dF FixedContainerSizeDelta() const {
- return gfx::Vector2dF();
- }
-
void SetPositionConstraint(const LayerPositionConstraint& constraint);
const LayerPositionConstraint& position_constraint() const {
return inputs_.position_constraint;
@@ -304,9 +300,6 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
virtual bool DrawsContent() const;
// This methods typically need to be overwritten by derived classes.
- // TODO(chrishtr): Blink no longer resizes anything during paint. We can
- // remove this.
- virtual void SavePaintProperties();
// Returns true iff anything was updated that needs to be committed.
virtual bool Update();
virtual void SetLayerMaskType(Layer::LayerMaskType type) {}
@@ -334,10 +327,6 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
bool NeedsDisplayForTesting() const { return !inputs_.update_rect.IsEmpty(); }
void ResetNeedsDisplayForTesting() { inputs_.update_rect = gfx::Rect(); }
- const PaintProperties& paint_properties() const {
- return paint_properties_;
- }
-
// Mark the layer as needing to push its properties to the LayerImpl during
// commit.
void SetNeedsPushProperties();
@@ -401,8 +390,9 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
void SetMayContainVideo(bool yes);
- int num_copy_requests_in_target_subtree();
+ bool has_copy_requests_in_target_subtree();
+ // Stable identifier for clients. See comment in cc/trees/element_id.h.
void SetElementId(ElementId id);
ElementId element_id() const { return inputs_.element_id; }
@@ -480,10 +470,7 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
void OnTransformAnimated(const gfx::Transform& transform);
void OnScrollOffsetAnimated(const gfx::ScrollOffset& scroll_offset);
- bool FilterIsAnimating() const;
- bool TransformIsAnimating() const;
bool ScrollOffsetAnimationWasInterrupted() const;
- bool HasOnlyTranslationTransforms() const;
void AddScrollChild(Layer* child);
void RemoveScrollChild(Layer* child);
@@ -513,6 +500,12 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
// layer should own a property tree node or not.
void SetPropertyTreesNeedRebuild();
+ // Fast-path for |SetScrollOffset| and |SetScrollOffsetFromImplSide| to
+ // directly update scroll offset values in the property tree without needing a
+ // full property tree update. If property trees do not exist yet, ensures
+ // they are marked as needing to be rebuilt.
+ void UpdateScrollOffset(const gfx::ScrollOffset&);
+
// Encapsulates all data, callbacks or interfaces received from the embedder.
// TODO(khushalsagar): This is only valid when PropertyTrees are built
// internally in cc. Update this for the SPv2 path where blink generates
@@ -627,13 +620,13 @@ class CC_EXPORT Layer : public base::RefCounted<Layer> {
bool may_contain_video_ : 1;
bool is_scroll_clip_layer_ : 1;
bool needs_show_scrollbars_ : 1;
+ // This value is valid only when LayerTreeHost::has_copy_request() is true
+ bool subtree_has_copy_request_ : 1;
SkColor safe_opaque_background_color_;
std::unique_ptr<std::set<Layer*>> scroll_children_;
std::unique_ptr<std::set<Layer*>> clip_children_;
- PaintProperties paint_properties_;
-
// These all act like draw properties, so don't need push properties.
gfx::Rect visible_layer_rect_;
size_t num_unclipped_descendants_;
diff --git a/chromium/cc/layers/layer_collections.h b/chromium/cc/layers/layer_collections.h
index c7a2b746205..14da9699d14 100644
--- a/chromium/cc/layers/layer_collections.h
+++ b/chromium/cc/layers/layer_collections.h
@@ -15,10 +15,12 @@
namespace cc {
class Layer;
class LayerImpl;
+class RenderSurfaceImpl;
using LayerList = std::vector<scoped_refptr<Layer>>;
using OwnedLayerImplList = std::vector<std::unique_ptr<LayerImpl>>;
using LayerImplList = std::vector<LayerImpl*>;
+using RenderSurfaceList = std::vector<RenderSurfaceImpl*>;
using OwnedLayerImplMap = std::unordered_map<int, std::unique_ptr<LayerImpl>>;
using LayerImplMap = std::unordered_map<int, LayerImpl*>;
diff --git a/chromium/cc/layers/layer_impl.cc b/chromium/cc/layers/layer_impl.cc
index b9f9b993e91..e40b5701e13 100644
--- a/chromium/cc/layers/layer_impl.cc
+++ b/chromium/cc/layers/layer_impl.cc
@@ -66,8 +66,8 @@ LayerImpl::LayerImpl(LayerTreeImpl* tree_impl, int id)
use_local_transform_for_backface_visibility_(false),
should_check_backface_visibility_(false),
draws_content_(false),
- is_drawn_render_surface_layer_list_member_(false),
- was_ever_ready_since_last_transform_animation_(true),
+ contributes_to_drawn_render_surface_(false),
+ viewport_layer_type_(NOT_VIEWPORT_LAYER),
background_color_(0),
safe_opaque_background_color_(0),
transform_tree_index_(TransformTree::kInvalidNodeId),
@@ -80,7 +80,8 @@ LayerImpl::LayerImpl(LayerTreeImpl* tree_impl, int id)
has_will_change_transform_hint_(false),
needs_push_properties_(false),
scrollbars_hidden_(false),
- needs_show_scrollbars_(false) {
+ needs_show_scrollbars_(false),
+ raster_even_if_not_in_rsll_(false) {
DCHECK_GT(layer_id_, 0);
DCHECK(layer_tree_impl_);
@@ -147,7 +148,7 @@ void LayerImpl::SetScrollTreeIndex(int index) {
}
void LayerImpl::PopulateSharedQuadState(SharedQuadState* state) const {
- state->SetAll(draw_properties_.target_space_transform, bounds(),
+ state->SetAll(draw_properties_.target_space_transform, gfx::Rect(bounds()),
draw_properties_.visible_layer_rect, draw_properties_.clip_rect,
draw_properties_.is_clipped, draw_properties_.opacity,
SkBlendMode::kSrcOver, GetSortingContextId());
@@ -167,10 +168,10 @@ void LayerImpl::PopulateScaledSharedQuadState(
visible_layer_rect(), layer_to_content_scale_x, layer_to_content_scale_y);
scaled_visible_layer_rect.Intersect(gfx::Rect(scaled_bounds));
- state->SetAll(scaled_draw_transform, scaled_bounds, scaled_visible_layer_rect,
- draw_properties().clip_rect, draw_properties().is_clipped,
- draw_properties().opacity, SkBlendMode::kSrcOver,
- GetSortingContextId());
+ state->SetAll(scaled_draw_transform, gfx::Rect(scaled_bounds),
+ scaled_visible_layer_rect, draw_properties().clip_rect,
+ draw_properties().is_clipped, draw_properties().opacity,
+ SkBlendMode::kSrcOver, GetSortingContextId());
}
bool LayerImpl::WillDraw(DrawMode draw_mode,
@@ -259,7 +260,8 @@ void LayerImpl::AppendDebugBorderQuad(RenderPass* render_pass,
}
void LayerImpl::GetContentsResourceId(ResourceId* resource_id,
- gfx::Size* resource_size) const {
+ gfx::Size* resource_size,
+ gfx::SizeF* resource_uv_size) const {
NOTREACHED();
*resource_id = 0;
}
@@ -312,6 +314,10 @@ bool LayerImpl::IsSnapped() {
void LayerImpl::PushPropertiesTo(LayerImpl* layer) {
DCHECK(layer->IsActive());
+ // The ElementId should be set first because other setters depend on it such
+ // as LayerImpl::SetScrollClipLayer.
+ layer->SetElementId(element_id_);
+
layer->offset_to_transform_parent_ = offset_to_transform_parent_;
layer->main_thread_scrolling_reasons_ = main_thread_scrolling_reasons_;
layer->user_scrollable_horizontal_ = user_scrollable_horizontal_;
@@ -346,7 +352,6 @@ void LayerImpl::PushPropertiesTo(LayerImpl* layer) {
layer->SetBounds(bounds_);
layer->SetScrollClipLayer(scroll_clip_layer_id_);
- layer->SetElementId(element_id_);
layer->SetMutableProperties(mutable_properties_);
// If the main thread commits multiple times before the impl thread actually
@@ -373,15 +378,6 @@ bool LayerImpl::IsAffectedByPageScale() const {
->in_subtree_of_page_scale_layer;
}
-gfx::Vector2dF LayerImpl::FixedContainerSizeDelta() const {
- LayerImpl* scroll_clip_layer =
- layer_tree_impl()->LayerById(scroll_clip_layer_id_);
- if (!scroll_clip_layer)
- return gfx::Vector2dF();
-
- return scroll_clip_layer->bounds_delta();
-}
-
std::unique_ptr<base::DictionaryValue> LayerImpl::LayerTreeAsJson() {
std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue);
result->SetInteger("LayerId", id());
@@ -470,10 +466,8 @@ void LayerImpl::ResetChangeTracking() {
damage_rect_.SetRect(0, 0, 0, 0);
}
-int LayerImpl::num_copy_requests_in_target_subtree() {
- return GetEffectTree()
- .Node(effect_tree_index())
- ->num_copy_requests_in_subtree;
+bool LayerImpl::has_copy_requests_in_target_subtree() {
+ return GetEffectTree().Node(effect_tree_index())->subtree_has_copy_request;
}
void LayerImpl::UpdatePropertyTreeForScrollingAndAnimationIfNeeded() {
@@ -486,7 +480,9 @@ void LayerImpl::UpdatePropertyTreeForScrollingAndAnimationIfNeeded() {
bool has_potential_animation = HasPotentiallyRunningTransformAnimation();
if (node->has_potential_animation != has_potential_animation) {
node->has_potential_animation = has_potential_animation;
- node->has_only_translation_animations = HasOnlyTranslationTransforms();
+ node->has_only_translation_animations =
+ GetMutatorHost()->HasOnlyTranslationTransforms(
+ element_id(), GetElementTypeForAnimation());
GetTransformTree().set_needs_update(true);
layer_tree_impl()->set_needs_update_draw_properties();
}
@@ -503,14 +499,15 @@ bool LayerImpl::IsActive() const {
}
gfx::Size LayerImpl::bounds() const {
- gfx::Vector2d delta = gfx::ToCeiledVector2d(bounds_delta_);
- return gfx::Size(bounds_.width() + delta.x(),
- bounds_.height() + delta.y());
+ auto viewport_bounds_delta = gfx::ToCeiledVector2d(ViewportBoundsDelta());
+ return gfx::Size(bounds_.width() + viewport_bounds_delta.x(),
+ bounds_.height() + viewport_bounds_delta.y());
}
gfx::SizeF LayerImpl::BoundsForScrolling() const {
- return gfx::SizeF(bounds_.width() + bounds_delta_.x(),
- bounds_.height() + bounds_delta_.y());
+ auto viewport_bounds_delta = ViewportBoundsDelta();
+ return gfx::SizeF(bounds_.width() + viewport_bounds_delta.x(),
+ bounds_.height() + viewport_bounds_delta.y());
}
void LayerImpl::SetBounds(const gfx::Size& bounds) {
@@ -524,20 +521,27 @@ void LayerImpl::SetBounds(const gfx::Size& bounds) {
NoteLayerPropertyChanged();
}
-void LayerImpl::SetBoundsDelta(const gfx::Vector2dF& bounds_delta) {
+void LayerImpl::SetViewportBoundsDelta(const gfx::Vector2dF& bounds_delta) {
DCHECK(IsActive());
- if (bounds_delta_ == bounds_delta)
- return;
- bounds_delta_ = bounds_delta;
+ if (bounds_delta == ViewportBoundsDelta())
+ return;
PropertyTrees* property_trees = GetPropertyTrees();
- if (this == layer_tree_impl()->InnerViewportContainerLayer())
- property_trees->SetInnerViewportContainerBoundsDelta(bounds_delta);
- else if (this == layer_tree_impl()->OuterViewportContainerLayer())
- property_trees->SetOuterViewportContainerBoundsDelta(bounds_delta);
- else if (this == layer_tree_impl()->InnerViewportScrollLayer())
- property_trees->SetInnerViewportScrollBoundsDelta(bounds_delta);
+ switch (viewport_layer_type_) {
+ case (INNER_VIEWPORT_CONTAINER):
+ property_trees->SetInnerViewportContainerBoundsDelta(bounds_delta);
+ break;
+ case (OUTER_VIEWPORT_CONTAINER):
+ property_trees->SetOuterViewportContainerBoundsDelta(bounds_delta);
+ break;
+ case (INNER_VIEWPORT_SCROLL):
+ property_trees->SetInnerViewportScrollBoundsDelta(bounds_delta);
+ break;
+ case (OUTER_VIEWPORT_SCROLL):
+ // OUTER_VIEWPORT_SCROLL should not have viewport bounds deltas.
+ NOTREACHED();
+ }
layer_tree_impl()->DidUpdateScrollState(id());
@@ -557,6 +561,19 @@ void LayerImpl::SetBoundsDelta(const gfx::Vector2dF& bounds_delta) {
}
}
+gfx::Vector2dF LayerImpl::ViewportBoundsDelta() const {
+ switch (viewport_layer_type_) {
+ case (INNER_VIEWPORT_CONTAINER):
+ return GetPropertyTrees()->inner_viewport_container_bounds_delta();
+ case (OUTER_VIEWPORT_CONTAINER):
+ return GetPropertyTrees()->outer_viewport_container_bounds_delta();
+ case (INNER_VIEWPORT_SCROLL):
+ return GetPropertyTrees()->inner_viewport_scroll_bounds_delta();
+ default:
+ return gfx::Vector2dF();
+ }
+}
+
ScrollbarLayerImplBase* LayerImpl::ToScrollbarLayer() {
return nullptr;
}
@@ -590,11 +607,6 @@ SkColor LayerImpl::SafeOpaqueBackgroundColor() const {
return color;
}
-bool LayerImpl::FilterIsAnimating() const {
- return GetMutatorHost()->IsAnimatingFilterProperty(
- element_id(), GetElementTypeForAnimation());
-}
-
bool LayerImpl::HasPotentiallyRunningFilterAnimation() const {
return GetMutatorHost()->HasPotentiallyRunningFilterAnimation(
element_id(), GetElementTypeForAnimation());
@@ -651,21 +663,11 @@ void LayerImpl::SetPosition(const gfx::PointF& position) {
position_ = position;
}
-bool LayerImpl::TransformIsAnimating() const {
- return GetMutatorHost()->IsAnimatingTransformProperty(
- element_id(), GetElementTypeForAnimation());
-}
-
bool LayerImpl::HasPotentiallyRunningTransformAnimation() const {
return GetMutatorHost()->HasPotentiallyRunningTransformAnimation(
element_id(), GetElementTypeForAnimation());
}
-bool LayerImpl::HasOnlyTranslationTransforms() const {
- return GetMutatorHost()->HasOnlyTranslationTransforms(
- element_id(), GetElementTypeForAnimation());
-}
-
bool LayerImpl::HasAnyAnimationTargetingProperty(
TargetProperty::Type property) const {
return GetMutatorHost()->HasAnyAnimationTargetingProperty(element_id(),
@@ -866,14 +868,9 @@ void LayerImpl::RunMicroBenchmark(MicroBenchmarkImpl* benchmark) {
gfx::Transform LayerImpl::DrawTransform() const {
// Only drawn layers have up-to-date draw properties.
- if (!is_drawn_render_surface_layer_list_member()) {
- if (GetPropertyTrees()->non_root_surfaces_enabled) {
+ if (!contributes_to_drawn_render_surface()) {
return draw_property_utils::DrawTransform(this, GetTransformTree(),
GetEffectTree());
- } else {
- return draw_property_utils::ScreenSpaceTransform(this,
- GetTransformTree());
- }
}
return draw_properties().target_space_transform;
@@ -881,7 +878,7 @@ gfx::Transform LayerImpl::DrawTransform() const {
gfx::Transform LayerImpl::ScreenSpaceTransform() const {
// Only drawn layers have up-to-date draw properties.
- if (!is_drawn_render_surface_layer_list_member()) {
+ if (!contributes_to_drawn_render_surface()) {
return draw_property_utils::ScreenSpaceTransform(this, GetTransformTree());
}
@@ -932,13 +929,6 @@ gfx::Rect LayerImpl::GetScaledEnclosingRectInTargetSpace(float scale) const {
gfx::Rect(scaled_bounds));
}
-RenderSurfaceImpl* LayerImpl::GetRenderSurface() const {
- EffectNode* effect_node = GetEffectTree().Node(effect_tree_index_);
- if (effect_node->owning_layer_id == id())
- return GetEffectTree().GetRenderSurface(effect_tree_index_);
- return nullptr;
-}
-
RenderSurfaceImpl* LayerImpl::render_target() {
return GetEffectTree().GetRenderSurface(render_target_effect_tree_index());
}
@@ -960,8 +950,18 @@ float LayerImpl::GetIdealContentsScale() const {
return default_scale;
}
- gfx::Vector2dF transform_scales = MathUtil::ComputeTransform2dScaleComponents(
- ScreenSpaceTransform(), default_scale);
+ const auto& transform = ScreenSpaceTransform();
+ if (transform.HasPerspective()) {
+ float scale = MathUtil::ComputeApproximateMaxScale(transform);
+ // Since we're approximating the scale anyway, round it to the nearest
+ // integer to prevent jitter when animating the transform.
+ scale = std::round(scale);
+ // Don't let the scale fall below the default scale.
+ return std::max(scale, default_scale);
+ }
+
+ gfx::Vector2dF transform_scales =
+ MathUtil::ComputeTransform2dScaleComponents(transform, default_scale);
return std::max(transform_scales.x(), transform_scales.y());
}
@@ -985,26 +985,4 @@ TransformTree& LayerImpl::GetTransformTree() const {
return GetPropertyTrees()->transform_tree;
}
-bool LayerImpl::HasValidPropertyTreeIndices() const {
- // TODO(crbug.com/726423): LayerImpls should never have invalid PropertyTree
- // indices.
- const bool has_valid_transform_node =
- !!GetTransformTree().Node(transform_tree_index());
- DCHECK(has_valid_transform_node);
-
- const bool has_valid_effect_node =
- !!GetEffectTree().Node(effect_tree_index());
- DCHECK(has_valid_effect_node);
-
- const bool has_valid_clip_node = !!GetClipTree().Node(clip_tree_index());
- DCHECK(has_valid_clip_node);
-
- const bool has_valid_scroll_node =
- !!GetScrollTree().Node(scroll_tree_index());
- DCHECK(has_valid_scroll_node);
-
- return has_valid_transform_node && has_valid_effect_node &&
- has_valid_clip_node && has_valid_scroll_node;
-}
-
} // namespace cc
diff --git a/chromium/cc/layers/layer_impl.h b/chromium/cc/layers/layer_impl.h
index d976ae50045..c32c208ff13 100644
--- a/chromium/cc/layers/layer_impl.h
+++ b/chromium/cc/layers/layer_impl.h
@@ -70,12 +70,17 @@ enum DrawMode {
DRAW_MODE_RESOURCELESS_SOFTWARE
};
+enum ViewportLayerType {
+ NOT_VIEWPORT_LAYER,
+ INNER_VIEWPORT_CONTAINER,
+ OUTER_VIEWPORT_CONTAINER,
+ INNER_VIEWPORT_SCROLL,
+ OUTER_VIEWPORT_SCROLL,
+ LAST_VIEWPORT_LAYER_TYPE = OUTER_VIEWPORT_SCROLL,
+};
+
class CC_EXPORT LayerImpl {
public:
- typedef LayerImplList RenderSurfaceListType;
- typedef LayerImplList LayerListType;
- typedef RenderSurfaceImpl RenderSurfaceType;
-
static std::unique_ptr<LayerImpl> Create(LayerTreeImpl* tree_impl, int id) {
return base::WrapUnique(new LayerImpl(tree_impl, id));
}
@@ -147,7 +152,8 @@ class CC_EXPORT LayerImpl {
}
virtual void GetContentsResourceId(ResourceId* resource_id,
- gfx::Size* resource_size) const;
+ gfx::Size* resource_size,
+ gfx::SizeF* resource_uv_size) const;
virtual void NotifyTileStateChanged(const Tile* tile) {}
@@ -170,7 +176,6 @@ class CC_EXPORT LayerImpl {
// non-opaque color. Tries to return background_color(), if possible.
SkColor SafeOpaqueBackgroundColor() const;
- bool FilterIsAnimating() const;
bool HasPotentiallyRunningFilterAnimation() const;
void SetMasksToBounds(bool masks_to_bounds);
@@ -182,6 +187,7 @@ class CC_EXPORT LayerImpl {
float Opacity() const;
const gfx::Transform& Transform() const;
+ // Stable identifier for clients. See comment in cc/trees/element_id.h.
void SetElementId(ElementId element_id);
ElementId element_id() const { return element_id_; }
@@ -193,8 +199,6 @@ class CC_EXPORT LayerImpl {
bool IsAffectedByPageScale() const;
- gfx::Vector2dF FixedContainerSizeDelta() const;
-
bool Is3dSorted() const { return GetSortingContextId() != 0; }
void SetUseParentBackfaceVisibility(bool use) {
@@ -220,11 +224,6 @@ class CC_EXPORT LayerImpl {
bool ShowDebugBorders(DebugBorderType type) const;
- // TODO(http://crbug.com/557160): Currently SPv2 creates dummy layers for the
- // sole purpose of representing a render surface. Once that dependency is
- // removed, also remove dummy layers from PaintArtifactCompositor.
- RenderSurfaceImpl* GetRenderSurface() const;
-
// The render surface which this layer draws into. This can be either owned by
// the same layer or an ancestor of this layer.
RenderSurfaceImpl* render_target();
@@ -272,8 +271,22 @@ class CC_EXPORT LayerImpl {
// Like bounds() but doesn't snap to int. Lossy on giant pages (e.g. millions
// of pixels) due to use of single precision float.
gfx::SizeF BoundsForScrolling() const;
- void SetBoundsDelta(const gfx::Vector2dF& bounds_delta);
- gfx::Vector2dF bounds_delta() const { return bounds_delta_; }
+
+ // Viewport bounds delta are only used for viewport layers and account for
+ // changes in the viewport layers from browser controls and page scale
+ // factors. These deltas are only set on the active tree.
+ void SetViewportBoundsDelta(const gfx::Vector2dF& bounds_delta);
+ gfx::Vector2dF ViewportBoundsDelta() const;
+
+ void SetViewportLayerType(ViewportLayerType type) {
+ // Once set as a viewport layer type, the viewport type should not change.
+ DCHECK(viewport_layer_type() == NOT_VIEWPORT_LAYER ||
+ viewport_layer_type() == type);
+ viewport_layer_type_ = type;
+ }
+ ViewportLayerType viewport_layer_type() const {
+ return static_cast<ViewportLayerType>(viewport_layer_type_);
+ }
void SetCurrentScrollOffset(const gfx::ScrollOffset& scroll_offset);
gfx::ScrollOffset CurrentScrollOffset() const;
@@ -322,7 +335,6 @@ class CC_EXPORT LayerImpl {
return touch_event_handler_region_;
}
- bool TransformIsAnimating() const;
bool HasPotentiallyRunningTransformAnimation() const;
bool HasFilterAnimationThatInflatesBounds() const;
@@ -382,16 +394,16 @@ class CC_EXPORT LayerImpl {
void SetDebugInfo(
std::unique_ptr<base::trace_event::ConvertableToTraceFormat> debug_info);
- void set_is_drawn_render_surface_layer_list_member(bool is_member) {
- is_drawn_render_surface_layer_list_member_ = is_member;
+ void set_contributes_to_drawn_render_surface(bool is_member) {
+ contributes_to_drawn_render_surface_ = is_member;
}
- bool is_drawn_render_surface_layer_list_member() const {
- return is_drawn_render_surface_layer_list_member_;
+ bool contributes_to_drawn_render_surface() const {
+ return contributes_to_drawn_render_surface_;
}
bool IsDrawnScrollbar() {
- return ToScrollbarLayer() && is_drawn_render_surface_layer_list_member_;
+ return ToScrollbarLayer() && contributes_to_drawn_render_surface_;
}
void set_may_contain_video(bool yes) { may_contain_video_ = yes; }
@@ -408,20 +420,12 @@ class CC_EXPORT LayerImpl {
virtual gfx::Rect GetEnclosingRectInTargetSpace() const;
- int num_copy_requests_in_target_subtree();
+ bool has_copy_requests_in_target_subtree();
void UpdatePropertyTreeForScrollingAndAnimationIfNeeded();
float GetIdealContentsScale() const;
- bool was_ever_ready_since_last_transform_animation() const {
- return was_ever_ready_since_last_transform_animation_;
- }
-
- void set_was_ever_ready_since_last_transform_animation(bool was_ready) {
- was_ever_ready_since_last_transform_animation_ = was_ready;
- }
-
void NoteLayerPropertyChanged();
void SetHasWillChangeTransformHint(bool has_will_change);
@@ -436,7 +440,12 @@ class CC_EXPORT LayerImpl {
void set_needs_show_scrollbars(bool yes) { needs_show_scrollbars_ = yes; }
bool needs_show_scrollbars() { return needs_show_scrollbars_; }
- bool HasValidPropertyTreeIndices() const;
+ void set_raster_even_if_not_in_rsll(bool yes) {
+ raster_even_if_not_in_rsll_ = yes;
+ }
+ bool raster_even_if_not_in_rsll() const {
+ return raster_even_if_not_in_rsll_;
+ }
protected:
LayerImpl(LayerTreeImpl* layer_impl,
@@ -461,8 +470,6 @@ class CC_EXPORT LayerImpl {
gfx::Rect GetScaledEnclosingRectInTargetSpace(float scale) const;
private:
- bool HasOnlyTranslationTransforms() const;
-
// This includes all animations, even those that are finished but haven't yet
// been deleted.
bool HasAnyAnimationTargetingProperty(TargetProperty::Type property) const;
@@ -476,8 +483,6 @@ class CC_EXPORT LayerImpl {
std::unique_ptr<LayerImplTestProperties> test_properties_;
- gfx::Vector2dF bounds_delta_;
-
// Properties synchronized from the associated Layer.
gfx::Size bounds_;
int scroll_clip_layer_id_;
@@ -499,11 +504,11 @@ class CC_EXPORT LayerImpl {
bool use_local_transform_for_backface_visibility_ : 1;
bool should_check_backface_visibility_ : 1;
bool draws_content_ : 1;
- bool is_drawn_render_surface_layer_list_member_ : 1;
+ bool contributes_to_drawn_render_surface_ : 1;
- // This is true if and only if the layer was ever ready since it last animated
- // (all content was complete).
- bool was_ever_ready_since_last_transform_animation_ : 1;
+ static_assert(LAST_VIEWPORT_LAYER_TYPE < (1u << 3),
+ "enough bits for ViewportLayerType (viewport_layer_type_)");
+ uint8_t viewport_layer_type_ : 3; // ViewportLayerType
Region non_fast_scrollable_region_;
Region touch_event_handler_region_;
@@ -559,6 +564,8 @@ class CC_EXPORT LayerImpl {
// layers) and consumed by LayerTreeImpl::PushPropertiesTo during activation.
bool needs_show_scrollbars_ : 1;
+ bool raster_even_if_not_in_rsll_ : 1;
+
DISALLOW_COPY_AND_ASSIGN(LayerImpl);
};
diff --git a/chromium/cc/layers/layer_impl_test_properties.cc b/chromium/cc/layers/layer_impl_test_properties.cc
index 2ae194db2aa..9de5d11d439 100644
--- a/chromium/cc/layers/layer_impl_test_properties.cc
+++ b/chromium/cc/layers/layer_impl_test_properties.cc
@@ -18,6 +18,7 @@ LayerImplTestProperties::LayerImplTestProperties(LayerImpl* owning_layer)
should_flatten_transform(true),
hide_layer_and_subtree(false),
opacity_can_animate(false),
+ subtree_has_copy_request(false),
sorting_context_id(0),
opacity(1.f),
blend_mode(SkBlendMode::kSrcOver),
diff --git a/chromium/cc/layers/layer_impl_test_properties.h b/chromium/cc/layers/layer_impl_test_properties.h
index 5f4fd66f2db..ee2917e2a4a 100644
--- a/chromium/cc/layers/layer_impl_test_properties.h
+++ b/chromium/cc/layers/layer_impl_test_properties.h
@@ -37,6 +37,7 @@ struct CC_EXPORT LayerImplTestProperties {
bool should_flatten_transform;
bool hide_layer_and_subtree;
bool opacity_can_animate;
+ bool subtree_has_copy_request;
int sorting_context_id;
float opacity;
FilterOperations filters;
diff --git a/chromium/cc/layers/layer_impl_unittest.cc b/chromium/cc/layers/layer_impl_unittest.cc
index 2180d540d58..07259ad1ab7 100644
--- a/chromium/cc/layers/layer_impl_unittest.cc
+++ b/chromium/cc/layers/layer_impl_unittest.cc
@@ -138,6 +138,12 @@ TEST(LayerImplTest, VerifyLayerChangesAreTrackedProperly) {
root_clip_ptr->test_properties()->AddChild(std::move(root_ptr));
host_impl.active_tree()->SetRootLayerForTesting(std::move(root_clip_ptr));
+ // Make root the inner viewport scroll layer. This ensures the later call to
+ // |SetViewportBoundsDelta| will be on a viewport layer.
+ LayerTreeImpl::ViewportLayerIds viewport_ids;
+ viewport_ids.inner_viewport_scroll = root->id();
+ host_impl.active_tree()->SetViewportLayersFromIds(viewport_ids);
+
root->test_properties()->force_render_surface = true;
root->SetMasksToBounds(true);
root->layer_tree_impl()->ResetAllChangeTracking();
@@ -192,11 +198,13 @@ TEST(LayerImplTest, VerifyLayerChangesAreTrackedProperly) {
arbitrary_transform));
EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->ScrollBy(arbitrary_vector2d);
root->SetNeedsPushProperties());
- // SetBoundsDelta changes subtree only when masks_to_bounds is true and it
- // doesn't set needs_push_properties as it is always called on active tree.
+ // SetViewportBoundsDelta changes subtree only when masks_to_bounds is true
+ // and it doesn't set needs_push_properties as it is always called on active
+ // tree.
root->SetMasksToBounds(true);
- EXECUTE_AND_VERIFY_SUBTREE_CHANGED(root->SetBoundsDelta(arbitrary_vector2d);
- root->SetNeedsPushProperties());
+ EXECUTE_AND_VERIFY_SUBTREE_CHANGED(
+ root->SetViewportBoundsDelta(arbitrary_vector2d);
+ root->SetNeedsPushProperties());
// Changing these properties only affects the layer itself.
EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(root->SetDrawsContent(true));
@@ -218,7 +226,7 @@ TEST(LayerImplTest, VerifyLayerChangesAreTrackedProperly) {
// Changing these properties does not cause the layer to be marked as changed
// but does cause the layer to need to push properties.
EXECUTE_AND_VERIFY_NEEDS_PUSH_PROPERTIES_AND_SUBTREE_DID_NOT_CHANGE(
- root->SetElementId(ElementId(2, 0)));
+ root->SetElementId(ElementId(2)));
EXECUTE_AND_VERIFY_NEEDS_PUSH_PROPERTIES_AND_SUBTREE_DID_NOT_CHANGE(
root->SetMutableProperties(MutableProperty::kOpacity);
root->SetNeedsPushProperties());
@@ -342,7 +350,7 @@ TEST(LayerImplTest, VerifyNeedsUpdateDrawProperties) {
VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(
layer->SetBackgroundColor(arbitrary_color));
VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetBounds(arbitrary_size));
- VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetElementId(ElementId(2, 0)));
+ VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(layer->SetElementId(ElementId(2)));
VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(
layer->SetMutableProperties(MutableProperty::kTransform));
}
@@ -385,6 +393,43 @@ TEST(LayerImplTest, SafeOpaqueBackgroundColor) {
}
}
+TEST(LayerImplTest, PerspectiveTransformHasReasonableScale) {
+ FakeImplTaskRunnerProvider task_runner_provider;
+ TestTaskGraphRunner task_graph_runner;
+ std::unique_ptr<CompositorFrameSink> compositor_frame_sink =
+ FakeCompositorFrameSink::Create3d();
+ LayerTreeSettings settings;
+ settings.layer_transforms_should_scale_layer_contents = true;
+ FakeLayerTreeHostImpl host_impl(settings, &task_runner_provider,
+ &task_graph_runner);
+ auto owned_layer = LayerImpl::Create(host_impl.active_tree(), 1);
+ LayerImpl* layer = owned_layer.get();
+ layer->set_contributes_to_drawn_render_surface(true);
+ host_impl.active_tree()->SetRootLayerForTesting(std::move(owned_layer));
+ host_impl.active_tree()->BuildLayerListAndPropertyTreesForTesting();
+
+ // Ensure that we are close to the maximum scale for the matrix.
+ {
+ gfx::Transform transform;
+ transform.Scale(10.2f, 15.1f);
+ transform.ApplyPerspectiveDepth(10);
+ layer->draw_properties().screen_space_transform = transform;
+
+ ASSERT_TRUE(layer->ScreenSpaceTransform().HasPerspective());
+ EXPECT_FLOAT_EQ(15.f, layer->GetIdealContentsScale());
+ }
+ // Ensure that we don't fall below the device scale factor.
+ {
+ gfx::Transform transform;
+ transform.Scale(0.1f, 0.2f);
+ transform.ApplyPerspectiveDepth(10);
+ layer->draw_properties().screen_space_transform = transform;
+
+ ASSERT_TRUE(layer->ScreenSpaceTransform().HasPerspective());
+ EXPECT_FLOAT_EQ(1.f, layer->GetIdealContentsScale());
+ }
+}
+
class LayerImplScrollTest : public testing::Test {
public:
LayerImplScrollTest()
diff --git a/chromium/cc/layers/layer_position_constraint_unittest.cc b/chromium/cc/layers/layer_position_constraint_unittest.cc
index ce8e2149816..ff886dbe792 100644
--- a/chromium/cc/layers/layer_position_constraint_unittest.cc
+++ b/chromium/cc/layers/layer_position_constraint_unittest.cc
@@ -12,6 +12,7 @@
#include "cc/test/fake_layer_tree_host.h"
#include "cc/test/fake_proxy.h"
#include "cc/test/geometry_test_utils.h"
+#include "cc/test/layer_test_common.h"
#include "cc/test/test_task_graph_runner.h"
#include "cc/trees/layer_tree_host_common.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -47,9 +48,9 @@ void SetLayerPropertiesForTesting(Layer* layer,
}
void ExecuteCalculateDrawProperties(LayerImpl* root_layer) {
- std::vector<LayerImpl*> dummy_render_surface_layer_list;
+ RenderSurfaceList dummy_render_surface_list;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root_layer, root_layer->bounds(), &dummy_render_surface_layer_list);
+ root_layer, root_layer->bounds(), &dummy_render_surface_list);
inputs.inner_viewport_scroll_layer =
root_layer->layer_tree_impl()->InnerViewportScrollLayer();
inputs.outer_viewport_scroll_layer =
@@ -134,8 +135,13 @@ class LayerPositionConstraintTest : public testing::Test {
root_->AddChild(inner_viewport_container_layer_);
layer_tree_host_->SetRootLayer(root_);
- layer_tree_host_->RegisterViewportLayers(nullptr, root_, scroll_layer_,
- child_);
+ LayerTreeHost::ViewportLayers viewport_layers;
+ viewport_layers.page_scale = root_;
+ viewport_layers.inner_viewport_container = inner_viewport_container_layer_;
+ viewport_layers.outer_viewport_container = outer_viewport_container_layer_;
+ viewport_layers.inner_viewport_scroll = scroll_layer_;
+ viewport_layers.outer_viewport_scroll = child_;
+ layer_tree_host_->RegisterViewportLayers(viewport_layers);
}
void CommitAndUpdateImplPointers() {
@@ -207,18 +213,6 @@ class LayerPositionConstraintTest : public testing::Test {
}
};
-namespace {
-
-void SetFixedContainerSizeDelta(LayerImpl* scroll_layer,
- const gfx::Vector2d& delta) {
- DCHECK(scroll_layer);
- DCHECK(scroll_layer->scrollable());
-
- LayerImpl* container_layer = scroll_layer->scroll_clip_layer();
- container_layer->SetBoundsDelta(delta);
-}
-} // namespace
-
TEST_F(LayerPositionConstraintTest,
ScrollCompensationForFixedPositionLayerWithDirectContainer) {
// This test checks for correct scroll compensation when the fixed-position
@@ -256,7 +250,8 @@ TEST_F(LayerPositionConstraintTest,
grand_child_impl_->DrawTransform());
// Case 3: fixed-container size delta of 20, 20
- SetFixedContainerSizeDelta(child_impl_, gfx::Vector2d(20, 20));
+ outer_viewport_container_layer_impl_->SetViewportBoundsDelta(
+ gfx::Vector2d(20, 20));
ExecuteCalculateDrawProperties(root_impl_);
// Top-left fixed-position layer should not be affected by container size.
@@ -270,7 +265,8 @@ TEST_F(LayerPositionConstraintTest,
CommitAndUpdateImplPointers();
SetScrollOffsetDelta(child_impl_, gfx::Vector2d(10, 10));
- SetFixedContainerSizeDelta(child_impl_, gfx::Vector2d(20, 20));
+ outer_viewport_container_layer_impl_->SetViewportBoundsDelta(
+ gfx::Vector2d(20, 20));
ExecuteCalculateDrawProperties(root_impl_);
// Bottom-right fixed-position layer moves as container resizes.
@@ -331,7 +327,8 @@ TEST_F(LayerPositionConstraintTest,
great_grand_child_impl_->DrawTransform());
// Case 3: fixed-container size delta of 20, 20
- SetFixedContainerSizeDelta(child_impl_, gfx::Vector2d(20, 20));
+ outer_viewport_container_layer_impl_->SetViewportBoundsDelta(
+ gfx::Vector2d(20, 20));
ExecuteCalculateDrawProperties(root_impl_);
// Top-left fixed-position layer should not be affected by container size.
@@ -346,7 +343,8 @@ TEST_F(LayerPositionConstraintTest,
great_grand_child_->SetPositionConstraint(fixed_to_bottom_right_);
CommitAndUpdateImplPointers();
SetScrollOffsetDelta(child_impl_, gfx::Vector2d(10, 10));
- SetFixedContainerSizeDelta(child_impl_, gfx::Vector2d(20, 20));
+ outer_viewport_container_layer_impl_->SetViewportBoundsDelta(
+ gfx::Vector2d(20, 20));
ExecuteCalculateDrawProperties(root_impl_);
// Bottom-right fixed-position layer moves as container resizes.
@@ -459,12 +457,12 @@ TEST_F(LayerPositionConstraintTest,
gfx::Transform expected_grand_child_transform;
gfx::Transform expected_great_grand_child_transform;
expected_great_grand_child_transform.PreconcatTransform(rotation_about_z);
- EXPECT_TRUE(grand_child_impl_->GetRenderSurface());
+ EXPECT_TRUE(GetRenderSurface(grand_child_impl_));
EXPECT_TRANSFORMATION_MATRIX_EQ(expected_child_transform,
child_impl_->DrawTransform());
EXPECT_TRANSFORMATION_MATRIX_EQ(
expected_surface_draw_transform,
- grand_child_impl_->GetRenderSurface()->draw_transform());
+ GetRenderSurface(grand_child_impl_)->draw_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(expected_grand_child_transform,
grand_child_impl_->DrawTransform());
EXPECT_TRANSFORMATION_MATRIX_EQ(expected_great_grand_child_transform,
@@ -496,19 +494,20 @@ TEST_F(LayerPositionConstraintTest,
expected_great_grand_child_transform.Translate(10.0, 30.0);
expected_great_grand_child_transform.PreconcatTransform(rotation_about_z);
- EXPECT_TRUE(grand_child_impl_->GetRenderSurface());
+ EXPECT_TRUE(GetRenderSurface(grand_child_impl_));
EXPECT_TRANSFORMATION_MATRIX_EQ(expected_child_transform,
child_impl_->DrawTransform());
EXPECT_TRANSFORMATION_MATRIX_EQ(
expected_surface_draw_transform,
- grand_child_impl_->GetRenderSurface()->draw_transform());
+ GetRenderSurface(grand_child_impl_)->draw_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(expected_grand_child_transform,
grand_child_impl_->DrawTransform());
EXPECT_TRANSFORMATION_MATRIX_EQ(expected_great_grand_child_transform,
great_grand_child_impl_->DrawTransform());
// Case 3: fixed-container size delta of 20, 20
- SetFixedContainerSizeDelta(child_impl_, gfx::Vector2d(20, 20));
+ outer_viewport_container_layer_impl_->SetViewportBoundsDelta(
+ gfx::Vector2d(20, 20));
ExecuteCalculateDrawProperties(root_impl_);
// Top-left fixed-position layer should not be affected by container size.
@@ -524,7 +523,8 @@ TEST_F(LayerPositionConstraintTest,
CommitAndUpdateImplPointers();
SetScrollOffsetDelta(child_impl_, gfx::Vector2d(10, 30));
- SetFixedContainerSizeDelta(child_impl_, gfx::Vector2d(20, 20));
+ outer_viewport_container_layer_impl_->SetViewportBoundsDelta(
+ gfx::Vector2d(20, 20));
ExecuteCalculateDrawProperties(root_impl_);
@@ -603,18 +603,18 @@ TEST_F(LayerPositionConstraintTest,
gfx::Transform expected_fixed_position_child_transform;
expected_fixed_position_child_transform.PreconcatTransform(rotation_about_z);
- EXPECT_TRUE(grand_child_impl_->GetRenderSurface());
- EXPECT_TRUE(great_grand_child_impl_->GetRenderSurface());
+ EXPECT_TRUE(GetRenderSurface(grand_child_impl_));
+ EXPECT_TRUE(GetRenderSurface(great_grand_child_impl_));
EXPECT_TRANSFORMATION_MATRIX_EQ(expected_child_transform,
child_impl_->DrawTransform());
EXPECT_TRANSFORMATION_MATRIX_EQ(
expected_grand_child_surface_draw_transform,
- grand_child_impl_->GetRenderSurface()->draw_transform());
+ GetRenderSurface(grand_child_impl_)->draw_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(expected_grand_child_transform,
grand_child_impl_->DrawTransform());
EXPECT_TRANSFORMATION_MATRIX_EQ(
expected_great_grand_child_surface_draw_transform,
- great_grand_child_impl_->GetRenderSurface()->draw_transform());
+ GetRenderSurface(great_grand_child_impl_)->draw_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(expected_great_grand_child_transform,
great_grand_child_impl_->DrawTransform());
EXPECT_TRANSFORMATION_MATRIX_EQ(expected_fixed_position_child_transform,
@@ -643,25 +643,26 @@ TEST_F(LayerPositionConstraintTest,
expected_fixed_position_child_transform.Translate(10.0, 30.0);
expected_fixed_position_child_transform.PreconcatTransform(rotation_about_z);
- EXPECT_TRUE(grand_child_impl_->GetRenderSurface());
- EXPECT_TRUE(great_grand_child_impl_->GetRenderSurface());
+ EXPECT_TRUE(GetRenderSurface(grand_child_impl_));
+ EXPECT_TRUE(GetRenderSurface(great_grand_child_impl_));
EXPECT_TRANSFORMATION_MATRIX_EQ(expected_child_transform,
child_impl_->DrawTransform());
EXPECT_TRANSFORMATION_MATRIX_EQ(
expected_grand_child_surface_draw_transform,
- grand_child_impl_->GetRenderSurface()->draw_transform());
+ GetRenderSurface(grand_child_impl_)->draw_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(expected_grand_child_transform,
grand_child_impl_->DrawTransform());
EXPECT_TRANSFORMATION_MATRIX_EQ(
expected_great_grand_child_surface_draw_transform,
- great_grand_child_impl_->GetRenderSurface()->draw_transform());
+ GetRenderSurface(great_grand_child_impl_)->draw_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(expected_great_grand_child_transform,
great_grand_child_impl_->DrawTransform());
EXPECT_TRANSFORMATION_MATRIX_EQ(expected_fixed_position_child_transform,
fixed_position_child_impl->DrawTransform());
// Case 3: fixed-container size delta of 20, 20
- SetFixedContainerSizeDelta(child_impl_, gfx::Vector2d(20, 20));
+ outer_viewport_container_layer_impl_->SetViewportBoundsDelta(
+ gfx::Vector2d(20, 20));
ExecuteCalculateDrawProperties(root_impl_);
// Top-left fixed-position layer should not be affected by container size.
@@ -680,7 +681,8 @@ TEST_F(LayerPositionConstraintTest,
fixed_position_child_impl =
layer_tree_impl_->LayerById(fixed_position_child->id());
SetScrollOffsetDelta(child_impl_, gfx::Vector2d(10, 30));
- SetFixedContainerSizeDelta(child_impl_, gfx::Vector2d(20, 20));
+ outer_viewport_container_layer_impl_->SetViewportBoundsDelta(
+ gfx::Vector2d(20, 20));
ExecuteCalculateDrawProperties(root_impl_);
// Bottom-right fixed-position layer moves as container resizes.
@@ -765,18 +767,18 @@ TEST_F(
gfx::Transform expected_fixed_position_child_transform;
expected_fixed_position_child_transform.PreconcatTransform(rotation_about_z);
- EXPECT_TRUE(grand_child_impl_->GetRenderSurface());
- EXPECT_TRUE(great_grand_child_impl_->GetRenderSurface());
+ EXPECT_TRUE(GetRenderSurface(grand_child_impl_));
+ EXPECT_TRUE(GetRenderSurface(great_grand_child_impl_));
EXPECT_TRANSFORMATION_MATRIX_EQ(expected_child_transform,
child_impl_->DrawTransform());
EXPECT_TRANSFORMATION_MATRIX_EQ(
expected_grand_child_surface_draw_transform,
- grand_child_impl_->GetRenderSurface()->draw_transform());
+ GetRenderSurface(grand_child_impl_)->draw_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(expected_grand_child_transform,
grand_child_impl_->DrawTransform());
EXPECT_TRANSFORMATION_MATRIX_EQ(
expected_great_grand_child_surface_draw_transform,
- great_grand_child_impl_->GetRenderSurface()->draw_transform());
+ GetRenderSurface(great_grand_child_impl_)->draw_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(expected_great_grand_child_transform,
great_grand_child_impl_->DrawTransform());
EXPECT_TRANSFORMATION_MATRIX_EQ(expected_fixed_position_child_transform,
@@ -810,18 +812,18 @@ TEST_F(
expected_fixed_position_child_transform.Translate(10.0, 30.0);
expected_fixed_position_child_transform.PreconcatTransform(rotation_about_z);
- EXPECT_TRUE(grand_child_impl_->GetRenderSurface());
- EXPECT_TRUE(great_grand_child_impl_->GetRenderSurface());
+ EXPECT_TRUE(GetRenderSurface(grand_child_impl_));
+ EXPECT_TRUE(GetRenderSurface(great_grand_child_impl_));
EXPECT_TRANSFORMATION_MATRIX_EQ(expected_child_transform,
child_impl_->DrawTransform());
EXPECT_TRANSFORMATION_MATRIX_EQ(
expected_grand_child_surface_draw_transform,
- grand_child_impl_->GetRenderSurface()->draw_transform());
+ GetRenderSurface(grand_child_impl_)->draw_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(expected_grand_child_transform,
grand_child_impl_->DrawTransform());
EXPECT_TRANSFORMATION_MATRIX_EQ(
expected_great_grand_child_surface_draw_transform,
- great_grand_child_impl_->GetRenderSurface()->draw_transform());
+ GetRenderSurface(great_grand_child_impl_)->draw_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(expected_great_grand_child_transform,
great_grand_child_impl_->DrawTransform());
EXPECT_TRANSFORMATION_MATRIX_EQ(expected_fixed_position_child_transform,
@@ -848,10 +850,10 @@ TEST_F(LayerPositionConstraintTest,
gfx::Transform expected_surface_draw_transform;
gfx::Transform expected_child_transform;
gfx::Transform expected_grand_child_transform;
- EXPECT_TRUE(child_impl_->GetRenderSurface());
+ EXPECT_TRUE(GetRenderSurface(child_impl_));
EXPECT_TRANSFORMATION_MATRIX_EQ(
expected_surface_draw_transform,
- child_impl_->GetRenderSurface()->draw_transform());
+ GetRenderSurface(child_impl_)->draw_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(expected_child_transform,
child_impl_->DrawTransform());
EXPECT_TRANSFORMATION_MATRIX_EQ(expected_grand_child_transform,
@@ -869,17 +871,18 @@ TEST_F(LayerPositionConstraintTest,
expected_grand_child_transform.MakeIdentity();
expected_grand_child_transform.Translate(10.0, 10.0);
- EXPECT_TRUE(child_impl_->GetRenderSurface());
+ EXPECT_TRUE(GetRenderSurface(child_impl_));
EXPECT_TRANSFORMATION_MATRIX_EQ(
expected_surface_draw_transform,
- child_impl_->GetRenderSurface()->draw_transform());
+ GetRenderSurface(child_impl_)->draw_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(expected_child_transform,
child_impl_->DrawTransform());
EXPECT_TRANSFORMATION_MATRIX_EQ(expected_grand_child_transform,
grand_child_impl_->DrawTransform());
// Case 3: fixed-container size delta of 20, 20
- SetFixedContainerSizeDelta(child_impl_, gfx::Vector2d(20, 20));
+ outer_viewport_container_layer_impl_->SetViewportBoundsDelta(
+ gfx::Vector2d(20, 20));
ExecuteCalculateDrawProperties(root_impl_);
// Top-left fixed-position layer should not be affected by container size.
@@ -892,7 +895,8 @@ TEST_F(LayerPositionConstraintTest,
grand_child_->SetPositionConstraint(fixed_to_bottom_right_);
CommitAndUpdateImplPointers();
SetScrollOffsetDelta(child_impl_, gfx::Vector2d(10, 10));
- SetFixedContainerSizeDelta(child_impl_, gfx::Vector2d(20, 20));
+ outer_viewport_container_layer_impl_->SetViewportBoundsDelta(
+ gfx::Vector2d(20, 20));
ExecuteCalculateDrawProperties(root_impl_);
// Bottom-right fixed-position layer moves as container resizes.
@@ -950,7 +954,8 @@ TEST_F(LayerPositionConstraintTest,
grand_child_impl_->DrawTransform());
// Case 3: fixed-container size delta of 20, 20
- SetFixedContainerSizeDelta(child_impl_, gfx::Vector2d(20, 20));
+ outer_viewport_container_layer_impl_->SetViewportBoundsDelta(
+ gfx::Vector2d(20, 20));
ExecuteCalculateDrawProperties(root_impl_);
// Top-left fixed-position layer should not be affected by container size.
@@ -963,7 +968,8 @@ TEST_F(LayerPositionConstraintTest,
grand_child_->SetPositionConstraint(fixed_to_bottom_right_);
CommitAndUpdateImplPointers();
SetScrollOffsetDelta(child_impl_, gfx::Vector2d(10, 10));
- SetFixedContainerSizeDelta(child_impl_, gfx::Vector2d(20, 20));
+ outer_viewport_container_layer_impl_->SetViewportBoundsDelta(
+ gfx::Vector2d(20, 20));
ExecuteCalculateDrawProperties(root_impl_);
@@ -1017,7 +1023,8 @@ TEST_F(LayerPositionConstraintTest,
// Case 2: sizeDelta
SetScrollOffsetDelta(child_impl_, gfx::Vector2d(0, 0));
- SetFixedContainerSizeDelta(child_impl_, gfx::Vector2d(20, 20));
+ outer_viewport_container_layer_impl_->SetViewportBoundsDelta(
+ gfx::Vector2d(20, 20));
ExecuteCalculateDrawProperties(root_impl_);
expected_child_transform.MakeIdentity();
@@ -1112,7 +1119,8 @@ TEST_F(LayerPositionConstraintTest,
// Case 1: fixed-container size delta of 20, 20
SetScrollOffsetDelta(scroll_layer_impl_, gfx::Vector2d(10, 10));
scroll_layer_impl_->SetDrawsContent(true);
- SetFixedContainerSizeDelta(scroll_layer_impl_, gfx::Vector2d(20, 20));
+ inner_viewport_container_layer_impl_->SetViewportBoundsDelta(
+ gfx::Vector2d(20, 20));
gfx::Transform expected_scroll_layer_transform;
expected_scroll_layer_transform.Translate(-10.0, -10.0);
gfx::Transform expected_fixed_child_transform;
@@ -1132,7 +1140,8 @@ TEST_F(LayerPositionConstraintTest,
root_impl_->layer_tree_impl()->FindActiveTreeLayerById(fixed_child->id());
SetScrollOffsetDelta(scroll_layer_impl_, gfx::Vector2d(10, 10));
- SetFixedContainerSizeDelta(scroll_layer_impl_, gfx::Vector2d(20, 20));
+ inner_viewport_container_layer_impl_->SetViewportBoundsDelta(
+ gfx::Vector2d(20, 20));
ExecuteCalculateDrawProperties(root_impl_);
// Bottom-right fixed-position layer moves as container resizes.
diff --git a/chromium/cc/layers/layer_unittest.cc b/chromium/cc/layers/layer_unittest.cc
index 1a227ca01ae..652d84e6dee 100644
--- a/chromium/cc/layers/layer_unittest.cc
+++ b/chromium/cc/layers/layer_unittest.cc
@@ -929,7 +929,7 @@ TEST_F(LayerTest, CheckPropertyChangeCausesCorrectBehavior) {
gfx::Rect(10, 10)));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetForceRenderSurfaceForTesting(true));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetHideLayerAndSubtree(true));
- EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetElementId(ElementId(2, 0)));
+ EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetElementId(ElementId(2)));
EXPECT_SET_NEEDS_COMMIT(
1, test_layer->SetMutableProperties(MutableProperty::kTransform));
@@ -1385,7 +1385,7 @@ TEST_F(LayerTest, AnimationSchedulesLayerUpdate) {
// though currently there is no good place for this unittest to go. Move to
// LayerTreeHost unittest when there is a good setup.
scoped_refptr<Layer> layer = Layer::Create();
- layer->SetElementId(ElementId(2, 0));
+ layer->SetElementId(ElementId(2));
EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, layer_tree_host_->SetRootLayer(layer));
auto element_id = layer->element_id();
@@ -1419,7 +1419,7 @@ TEST_F(LayerTest, ElementIdAndMutablePropertiesArePushed) {
EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(2);
- test_layer->SetElementId(ElementId(2, 0));
+ test_layer->SetElementId(ElementId(2));
test_layer->SetMutableProperties(MutableProperty::kTransform);
EXPECT_FALSE(impl_layer->element_id());
@@ -1427,9 +1427,66 @@ TEST_F(LayerTest, ElementIdAndMutablePropertiesArePushed) {
test_layer->PushPropertiesTo(impl_layer.get());
- EXPECT_EQ(ElementId(2, 0), impl_layer->element_id());
+ EXPECT_EQ(ElementId(2), impl_layer->element_id());
EXPECT_EQ(MutableProperty::kTransform, impl_layer->mutable_properties());
}
+TEST_F(LayerTest, NotUsingLayerListsManagesElementId) {
+ scoped_refptr<Layer> test_layer = Layer::Create();
+ ElementId element_id = ElementId(2);
+ test_layer->SetElementId(element_id);
+
+ // Expect additional call due to has-animation check.
+ EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(2);
+ scoped_refptr<AnimationTimeline> timeline =
+ AnimationTimeline::Create(AnimationIdProvider::NextTimelineId());
+ animation_host_->AddAnimationTimeline(timeline);
+
+ AddOpacityTransitionToElementWithPlayer(element_id, timeline, 10.0, 1.f, 0.f,
+ false);
+ EXPECT_TRUE(animation_host_->HasAnyAnimation(element_id));
+
+ 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));
+
+ test_layer->SetLayerTreeHost(nullptr);
+ // Layer should have been un-registered.
+ EXPECT_EQ(nullptr, layer_tree_host_->LayerByElementId(element_id));
+}
+
+class LayerTestWithLayerLists : public LayerTest {
+ protected:
+ void SetUp() override {
+ settings_.use_layer_lists = true;
+ LayerTest::SetUp();
+ }
+};
+
+TEST_F(LayerTestWithLayerLists, UsingLayerListsDoesNotManageElementId) {
+ scoped_refptr<Layer> test_layer = Layer::Create();
+ ElementId element_id = ElementId(2);
+ test_layer->SetElementId(element_id);
+
+ // Only one call expected since we should skip the has-animation check.
+ EXPECT_CALL(*layer_tree_host_, SetNeedsCommit()).Times(1);
+ scoped_refptr<AnimationTimeline> timeline =
+ AnimationTimeline::Create(AnimationIdProvider::NextTimelineId());
+ animation_host_->AddAnimationTimeline(timeline);
+
+ AddOpacityTransitionToElementWithPlayer(element_id, timeline, 10.0, 1.f, 0.f,
+ false);
+ EXPECT_TRUE(animation_host_->HasAnyAnimation(element_id));
+
+ EXPECT_EQ(nullptr, layer_tree_host_->LayerByElementId(element_id));
+ test_layer->SetLayerTreeHost(layer_tree_host_.get());
+ // Layer shouldn't have been registered by element id.
+ EXPECT_EQ(nullptr, layer_tree_host_->LayerByElementId(element_id));
+
+ test_layer->SetLayerTreeHost(nullptr);
+ EXPECT_EQ(nullptr, layer_tree_host_->LayerByElementId(element_id));
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/layers/nine_patch_layer_unittest.cc b/chromium/cc/layers/nine_patch_layer_unittest.cc
index 440b608f9df..340c6b8d730 100644
--- a/chromium/cc/layers/nine_patch_layer_unittest.cc
+++ b/chromium/cc/layers/nine_patch_layer_unittest.cc
@@ -56,7 +56,6 @@ TEST_F(NinePatchLayerTest, SetLayerProperties) {
EXPECT_EQ(test_layer->GetLayerTreeHostForTesting(), layer_tree_host_.get());
gfx::Rect screen_space_clip_rect;
- test_layer->SavePaintProperties();
test_layer->Update();
EXPECT_FALSE(test_layer->DrawsContent());
diff --git a/chromium/cc/layers/paint_properties.h b/chromium/cc/layers/paint_properties.h
deleted file mode 100644
index b57f90f3127..00000000000
--- a/chromium/cc/layers/paint_properties.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_LAYERS_PAINT_PROPERTIES_H_
-#define CC_LAYERS_PAINT_PROPERTIES_H_
-
-#include "ui/gfx/geometry/size.h"
-
-namespace cc {
-
-// Container for properties that layers need to save before they can be paint.
-struct CC_EXPORT PaintProperties {
- PaintProperties() : source_frame_number(-1) {}
-
- gfx::Size bounds;
-
- int source_frame_number;
-};
-
-} // namespace cc
-
-#endif // CC_LAYERS_PAINT_PROPERTIES_H_
diff --git a/chromium/cc/layers/painted_overlay_scrollbar_layer.cc b/chromium/cc/layers/painted_overlay_scrollbar_layer.cc
index 81a515edf1c..52ead4b4cb8 100644
--- a/chromium/cc/layers/painted_overlay_scrollbar_layer.cc
+++ b/chromium/cc/layers/painted_overlay_scrollbar_layer.cc
@@ -32,16 +32,16 @@ std::unique_ptr<LayerImpl> PaintedOverlayScrollbarLayer::CreateLayerImpl(
scoped_refptr<PaintedOverlayScrollbarLayer>
PaintedOverlayScrollbarLayer::Create(std::unique_ptr<Scrollbar> scrollbar,
- int scroll_layer_id) {
- return make_scoped_refptr(
- new PaintedOverlayScrollbarLayer(std::move(scrollbar), scroll_layer_id));
+ ElementId scroll_element_id) {
+ return make_scoped_refptr(new PaintedOverlayScrollbarLayer(
+ std::move(scrollbar), scroll_element_id));
}
PaintedOverlayScrollbarLayer::PaintedOverlayScrollbarLayer(
std::unique_ptr<Scrollbar> scrollbar,
- int scroll_layer_id)
+ ElementId scroll_element_id)
: scrollbar_(std::move(scrollbar)),
- scroll_layer_id_(scroll_layer_id),
+ scroll_element_id_(scroll_element_id),
thumb_thickness_(scrollbar_->ThumbThickness()),
thumb_length_(scrollbar_->ThumbLength()) {
DCHECK(scrollbar_->UsesNinePatchThumbResource());
@@ -49,15 +49,15 @@ PaintedOverlayScrollbarLayer::PaintedOverlayScrollbarLayer(
PaintedOverlayScrollbarLayer::~PaintedOverlayScrollbarLayer() {}
-int PaintedOverlayScrollbarLayer::ScrollLayerId() const {
- return scroll_layer_id_;
+ElementId PaintedOverlayScrollbarLayer::scroll_element_id() const {
+ return scroll_element_id_;
}
-void PaintedOverlayScrollbarLayer::SetScrollLayer(int layer_id) {
- if (layer_id == scroll_layer_id_)
+void PaintedOverlayScrollbarLayer::SetScrollElementId(ElementId element_id) {
+ if (element_id == scroll_element_id_)
return;
- scroll_layer_id_ = layer_id;
+ scroll_element_id_ = element_id;
SetNeedsFullTreeSync();
}
@@ -65,10 +65,6 @@ bool PaintedOverlayScrollbarLayer::OpacityCanAnimateOnImplThread() const {
return scrollbar_->IsOverlay();
}
-bool PaintedOverlayScrollbarLayer::AlwaysUseActiveTreeOpacity() const {
- return true;
-}
-
ScrollbarOrientation PaintedOverlayScrollbarLayer::orientation() const {
return scrollbar_->Orientation();
}
@@ -79,7 +75,7 @@ void PaintedOverlayScrollbarLayer::PushPropertiesTo(LayerImpl* layer) {
PaintedOverlayScrollbarLayerImpl* scrollbar_layer =
static_cast<PaintedOverlayScrollbarLayerImpl*>(layer);
- scrollbar_layer->SetScrollLayerId(scroll_layer_id_);
+ scrollbar_layer->SetScrollElementId(scroll_element_id_);
scrollbar_layer->SetThumbThickness(thumb_thickness_);
scrollbar_layer->SetThumbLength(thumb_length_);
diff --git a/chromium/cc/layers/painted_overlay_scrollbar_layer.h b/chromium/cc/layers/painted_overlay_scrollbar_layer.h
index f7cd66e5fd5..c0537d59e3c 100644
--- a/chromium/cc/layers/painted_overlay_scrollbar_layer.h
+++ b/chromium/cc/layers/painted_overlay_scrollbar_layer.h
@@ -22,15 +22,14 @@ class CC_EXPORT PaintedOverlayScrollbarLayer : public ScrollbarLayerInterface,
static scoped_refptr<PaintedOverlayScrollbarLayer> Create(
std::unique_ptr<Scrollbar> scrollbar,
- int scroll_layer_id);
+ ElementId scroll_element_id = ElementId());
bool OpacityCanAnimateOnImplThread() const override;
- bool AlwaysUseActiveTreeOpacity() const override;
ScrollbarLayerInterface* ToScrollbarLayer() override;
// ScrollbarLayerInterface
- int ScrollLayerId() const override;
- void SetScrollLayer(int layer_id) override;
+ ElementId scroll_element_id() const override;
+ void SetScrollElementId(ElementId element_id) override;
ScrollbarOrientation orientation() const override;
// Layer interface
@@ -40,7 +39,7 @@ class CC_EXPORT PaintedOverlayScrollbarLayer : public ScrollbarLayerInterface,
protected:
PaintedOverlayScrollbarLayer(std::unique_ptr<Scrollbar> scrollbar,
- int scroll_layer_id);
+ ElementId scroll_element_id);
~PaintedOverlayScrollbarLayer() override;
private:
@@ -58,7 +57,7 @@ class CC_EXPORT PaintedOverlayScrollbarLayer : public ScrollbarLayerInterface,
bool PaintThumbIfNeeded();
std::unique_ptr<Scrollbar> scrollbar_;
- int scroll_layer_id_;
+ ElementId scroll_element_id_;
int thumb_thickness_;
int thumb_length_;
diff --git a/chromium/cc/layers/painted_scrollbar_layer.cc b/chromium/cc/layers/painted_scrollbar_layer.cc
index 98aca6dbe19..66dde4c2989 100644
--- a/chromium/cc/layers/painted_scrollbar_layer.cc
+++ b/chromium/cc/layers/painted_scrollbar_layer.cc
@@ -34,16 +34,16 @@ std::unique_ptr<LayerImpl> PaintedScrollbarLayer::CreateLayerImpl(
scoped_refptr<PaintedScrollbarLayer> PaintedScrollbarLayer::Create(
std::unique_ptr<Scrollbar> scrollbar,
- int scroll_layer_id) {
+ ElementId scroll_element_id) {
return make_scoped_refptr(
- new PaintedScrollbarLayer(std::move(scrollbar), scroll_layer_id));
+ new PaintedScrollbarLayer(std::move(scrollbar), scroll_element_id));
}
PaintedScrollbarLayer::PaintedScrollbarLayer(
std::unique_ptr<Scrollbar> scrollbar,
- int scroll_layer_id)
+ ElementId scroll_element_id)
: scrollbar_(std::move(scrollbar)),
- scroll_layer_id_(scroll_layer_id),
+ scroll_element_id_(scroll_element_id),
internal_contents_scale_(1.f),
thumb_thickness_(scrollbar_->ThumbThickness()),
thumb_length_(scrollbar_->ThumbLength()),
@@ -57,15 +57,15 @@ PaintedScrollbarLayer::PaintedScrollbarLayer(
PaintedScrollbarLayer::~PaintedScrollbarLayer() {}
-int PaintedScrollbarLayer::ScrollLayerId() const {
- return scroll_layer_id_;
+ElementId PaintedScrollbarLayer::scroll_element_id() const {
+ return scroll_element_id_;
}
-void PaintedScrollbarLayer::SetScrollLayer(int layer_id) {
- if (layer_id == scroll_layer_id_)
+void PaintedScrollbarLayer::SetScrollElementId(ElementId element_id) {
+ if (element_id == scroll_element_id_)
return;
- scroll_layer_id_ = layer_id;
+ scroll_element_id_ = element_id;
SetNeedsFullTreeSync();
}
@@ -73,10 +73,6 @@ bool PaintedScrollbarLayer::OpacityCanAnimateOnImplThread() const {
return scrollbar_->IsOverlay();
}
-bool PaintedScrollbarLayer::AlwaysUseActiveTreeOpacity() const {
- return true;
-}
-
ScrollbarOrientation PaintedScrollbarLayer::orientation() const {
return scrollbar_->Orientation();
}
@@ -87,7 +83,7 @@ void PaintedScrollbarLayer::PushPropertiesTo(LayerImpl* layer) {
PaintedScrollbarLayerImpl* scrollbar_layer =
static_cast<PaintedScrollbarLayerImpl*>(layer);
- scrollbar_layer->SetScrollLayerId(scroll_layer_id_);
+ scrollbar_layer->SetScrollElementId(scroll_element_id_);
scrollbar_layer->set_internal_contents_scale_and_bounds(
internal_contents_scale_, internal_content_bounds_);
diff --git a/chromium/cc/layers/painted_scrollbar_layer.h b/chromium/cc/layers/painted_scrollbar_layer.h
index 8e1884f44f5..6320051c1aa 100644
--- a/chromium/cc/layers/painted_scrollbar_layer.h
+++ b/chromium/cc/layers/painted_scrollbar_layer.h
@@ -22,15 +22,14 @@ class CC_EXPORT PaintedScrollbarLayer : public ScrollbarLayerInterface,
static scoped_refptr<PaintedScrollbarLayer> Create(
std::unique_ptr<Scrollbar> scrollbar,
- int scroll_layer_id);
+ ElementId element_id = ElementId());
bool OpacityCanAnimateOnImplThread() const override;
- bool AlwaysUseActiveTreeOpacity() const override;
ScrollbarLayerInterface* ToScrollbarLayer() override;
// ScrollbarLayerInterface
- int ScrollLayerId() const override;
- void SetScrollLayer(int layer_id) override;
+ ElementId scroll_element_id() const override;
+ void SetScrollElementId(ElementId element_id) override;
ScrollbarOrientation orientation() const override;
@@ -45,7 +44,7 @@ class CC_EXPORT PaintedScrollbarLayer : public ScrollbarLayerInterface,
protected:
PaintedScrollbarLayer(std::unique_ptr<Scrollbar> scrollbar,
- int scroll_layer_id);
+ ElementId scroll_element_id);
~PaintedScrollbarLayer() override;
// For unit tests
@@ -76,7 +75,7 @@ class CC_EXPORT PaintedScrollbarLayer : public ScrollbarLayerInterface,
ScrollbarPart part);
std::unique_ptr<Scrollbar> scrollbar_;
- int scroll_layer_id_;
+ ElementId scroll_element_id_;
float internal_contents_scale_;
gfx::Size internal_content_bounds_;
diff --git a/chromium/cc/layers/painted_scrollbar_layer_impl.cc b/chromium/cc/layers/painted_scrollbar_layer_impl.cc
index 3abad0dd275..6e6db9f91f7 100644
--- a/chromium/cc/layers/painted_scrollbar_layer_impl.cc
+++ b/chromium/cc/layers/painted_scrollbar_layer_impl.cc
@@ -209,4 +209,9 @@ const char* PaintedScrollbarLayerImpl::LayerTypeAsString() const {
return "cc::PaintedScrollbarLayerImpl";
}
+LayerTreeSettings::ScrollbarAnimator
+PaintedScrollbarLayerImpl::GetScrollbarAnimator() const {
+ return LayerTreeSettings::NO_ANIMATOR;
+}
+
} // namespace cc
diff --git a/chromium/cc/layers/painted_scrollbar_layer_impl.h b/chromium/cc/layers/painted_scrollbar_layer_impl.h
index 9ff7e89691f..81b5aa20538 100644
--- a/chromium/cc/layers/painted_scrollbar_layer_impl.h
+++ b/chromium/cc/layers/painted_scrollbar_layer_impl.h
@@ -57,6 +57,8 @@ class CC_EXPORT PaintedScrollbarLayerImpl : public ScrollbarLayerImplBase {
int ThumbThickness() const override;
+ LayerTreeSettings::ScrollbarAnimator GetScrollbarAnimator() const override;
+
protected:
PaintedScrollbarLayerImpl(LayerTreeImpl* tree_impl,
int id,
diff --git a/chromium/cc/layers/painted_scrollbar_layer_unittest.cc b/chromium/cc/layers/painted_scrollbar_layer_unittest.cc
index ed58fa0136c..f4767910181 100644
--- a/chromium/cc/layers/painted_scrollbar_layer_unittest.cc
+++ b/chromium/cc/layers/painted_scrollbar_layer_unittest.cc
@@ -37,7 +37,7 @@ TEST(PaintedScrollbarLayerTest, NeedsPaint) {
MockScrollbar* scrollbar = new MockScrollbar();
scoped_refptr<PaintedScrollbarLayer> scrollbar_layer =
- PaintedScrollbarLayer::Create(std::unique_ptr<Scrollbar>(scrollbar), 1);
+ PaintedScrollbarLayer::Create(std::unique_ptr<Scrollbar>(scrollbar));
scrollbar_layer->SetIsDrawable(true);
scrollbar_layer->SetBounds(gfx::Size(100, 100));
@@ -45,7 +45,6 @@ TEST(PaintedScrollbarLayerTest, NeedsPaint) {
layer_tree_host->SetRootLayer(scrollbar_layer);
EXPECT_EQ(scrollbar_layer->GetLayerTreeHostForTesting(),
layer_tree_host.get());
- scrollbar_layer->SavePaintProperties();
// Request no paint, but expect them to be painted because they have not
// yet been initialized.
diff --git a/chromium/cc/layers/picture_image_layer.cc b/chromium/cc/layers/picture_image_layer.cc
index c219d8d906d..327582e8748 100644
--- a/chromium/cc/layers/picture_image_layer.cc
+++ b/chromium/cc/layers/picture_image_layer.cc
@@ -33,15 +33,15 @@ std::unique_ptr<LayerImpl> PictureImageLayer::CreateLayerImpl(
}
bool PictureImageLayer::HasDrawableContent() const {
- return image_ && PictureLayer::HasDrawableContent();
+ return image_.sk_image() && PictureLayer::HasDrawableContent();
}
-void PictureImageLayer::SetImage(sk_sp<const SkImage> image) {
+void PictureImageLayer::SetImage(PaintImage image) {
// SetImage() currently gets called whenever there is any
// style change that affects the layer even if that change doesn't
// affect the actual contents of the image (e.g. a CSS animation).
// With this check in place we avoid unecessary texture uploads.
- if (image_.get() == image.get())
+ if (image_ == image)
return;
image_ = std::move(image);
@@ -55,9 +55,9 @@ gfx::Rect PictureImageLayer::PaintableRegion() {
scoped_refptr<DisplayItemList> PictureImageLayer::PaintContentsToDisplayList(
ContentLayerClient::PaintingControlSetting painting_control) {
- DCHECK(image_);
- DCHECK_GT(image_->width(), 0);
- DCHECK_GT(image_->height(), 0);
+ DCHECK(image_.sk_image());
+ DCHECK_GT(image_.sk_image()->width(), 0);
+ DCHECK_GT(image_.sk_image()->height(), 0);
DCHECK(layer_tree_host());
auto display_list = make_scoped_refptr(new DisplayItemList);
@@ -66,10 +66,10 @@ scoped_refptr<DisplayItemList> PictureImageLayer::PaintContentsToDisplayList(
PaintCanvas* canvas =
recorder.beginRecording(gfx::RectToSkRect(PaintableRegion()));
- SkScalar content_to_layer_scale_x =
- SkFloatToScalar(static_cast<float>(bounds().width()) / image_->width());
- SkScalar content_to_layer_scale_y =
- SkFloatToScalar(static_cast<float>(bounds().height()) / image_->height());
+ SkScalar content_to_layer_scale_x = SkFloatToScalar(
+ static_cast<float>(bounds().width()) / image_.sk_image()->width());
+ SkScalar content_to_layer_scale_y = SkFloatToScalar(
+ static_cast<float>(bounds().height()) / image_.sk_image()->height());
canvas->scale(content_to_layer_scale_x, content_to_layer_scale_y);
// Because Android WebView resourceless software draw mode rasters directly
@@ -78,7 +78,8 @@ scoped_refptr<DisplayItemList> PictureImageLayer::PaintContentsToDisplayList(
canvas->drawImage(image_, 0, 0);
display_list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
- PaintableRegion(), recorder.finishRecordingAsPicture());
+ PaintableRegion(), recorder.finishRecordingAsPicture(),
+ gfx::RectToSkRect(PaintableRegion()));
display_list->Finalize();
return display_list;
diff --git a/chromium/cc/layers/picture_image_layer.h b/chromium/cc/layers/picture_image_layer.h
index d07e6cae731..faa62f41e8e 100644
--- a/chromium/cc/layers/picture_image_layer.h
+++ b/chromium/cc/layers/picture_image_layer.h
@@ -11,18 +11,17 @@
#include "cc/cc_export.h"
#include "cc/layers/content_layer_client.h"
#include "cc/layers/picture_layer.h"
+#include "cc/paint/paint_image.h"
#include "third_party/skia/include/core/SkRefCnt.h"
#include "ui/gfx/geometry/size.h"
-class SkImage;
-
namespace cc {
class CC_EXPORT PictureImageLayer : public PictureLayer, ContentLayerClient {
public:
static scoped_refptr<PictureImageLayer> Create();
- void SetImage(sk_sp<const SkImage> image);
+ void SetImage(PaintImage image);
// Layer implementation.
std::unique_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
@@ -42,7 +41,7 @@ class CC_EXPORT PictureImageLayer : public PictureLayer, ContentLayerClient {
PictureImageLayer();
~PictureImageLayer() override;
- sk_sp<const SkImage> image_;
+ PaintImage image_;
DISALLOW_COPY_AND_ASSIGN(PictureImageLayer);
};
diff --git a/chromium/cc/layers/picture_image_layer_unittest.cc b/chromium/cc/layers/picture_image_layer_unittest.cc
index 8701d316cdf..e17cc6c4677 100644
--- a/chromium/cc/layers/picture_image_layer_unittest.cc
+++ b/chromium/cc/layers/picture_image_layer_unittest.cc
@@ -40,7 +40,8 @@ TEST(PictureImageLayerTest, PaintContentsToDisplayList) {
image_canvas->drawRect(SkRect::MakeWH(100, 100), blue_paint);
image_canvas->drawRect(SkRect::MakeLTRB(100, 100, 200, 200), blue_paint);
- layer->SetImage(image_surface->makeImageSnapshot());
+ layer->SetImage(
+ PaintImage(PaintImage::GetNextId(), image_surface->makeImageSnapshot()));
layer->SetBounds(gfx::Size(layer_rect.width(), layer_rect.height()));
scoped_refptr<DisplayItemList> display_list =
diff --git a/chromium/cc/layers/picture_layer.cc b/chromium/cc/layers/picture_layer.cc
index d853f13ae1a..d2ce7ccd954 100644
--- a/chromium/cc/layers/picture_layer.cc
+++ b/chromium/cc/layers/picture_layer.cc
@@ -50,8 +50,7 @@ void PictureLayer::PushPropertiesTo(LayerImpl* base_layer) {
Layer::PushPropertiesTo(base_layer);
TRACE_EVENT0("cc", "PictureLayer::PushPropertiesTo");
PictureLayerImpl* layer_impl = static_cast<PictureLayerImpl*>(base_layer);
- // TODO(danakj): Make mask_type_ a constructor parameter for PictureLayer.
- DCHECK_EQ(layer_impl->mask_type(), mask_type());
+ layer_impl->SetLayerMaskType(mask_type());
DropRecordingSourceContentIfInvalid();
layer_impl->SetNearestNeighbor(picture_layer_inputs_.nearest_neighbor);
@@ -83,11 +82,10 @@ void PictureLayer::SetLayerTreeHost(LayerTreeHost* host) {
recording_source_.reset(new RecordingSource);
recording_source_->SetSlowdownRasterScaleFactor(
host->GetDebugState().slow_down_raster_scale_factor);
- // If we need to enable image decode tasks, then we have to generate the
- // discardable images metadata.
- const LayerTreeSettings& settings = layer_tree_host()->GetSettings();
- recording_source_->SetGenerateDiscardableImagesMetadata(
- settings.image_decode_tasks_enabled);
+
+ // Source frame numbers are relative the LayerTreeHost, so this needs
+ // to be reset.
+ update_source_frame_number_ = -1;
}
void PictureLayer::SetNeedsDisplayRect(const gfx::Rect& layer_rect) {
@@ -101,7 +99,7 @@ bool PictureLayer::Update() {
update_source_frame_number_ = layer_tree_host()->SourceFrameNumber();
bool updated = Layer::Update();
- gfx::Size layer_size = paint_properties().bounds;
+ gfx::Size layer_size = bounds();
recording_source_->SetBackgroundColor(SafeOpaqueBackgroundColor());
recording_source_->SetRequiresClear(
@@ -227,8 +225,6 @@ void PictureLayer::DropRecordingSourceContentIfInvalid() {
gfx::Size recording_source_bounds = recording_source_->GetSize();
gfx::Size layer_bounds = bounds();
- if (paint_properties().source_frame_number == source_frame_number)
- layer_bounds = paint_properties().bounds;
// If update called, then recording source size must match bounds pushed to
// impl layer.
diff --git a/chromium/cc/layers/picture_layer_impl.cc b/chromium/cc/layers/picture_layer_impl.cc
index a85580bf3cd..f43c977f684 100644
--- a/chromium/cc/layers/picture_layer_impl.cc
+++ b/chromium/cc/layers/picture_layer_impl.cc
@@ -120,6 +120,17 @@ PictureLayerImpl::~PictureLayerImpl() {
layer_tree_impl()->UnregisterPictureLayerImpl(this);
}
+void PictureLayerImpl::SetLayerMaskType(Layer::LayerMaskType mask_type) {
+ if (mask_type_ == mask_type)
+ return;
+ // It is expected that a layer can never change from being a mask to not being
+ // one and vice versa. Only changes that make mask layer single <-> multi are
+ // expected.
+ DCHECK(mask_type_ != Layer::LayerMaskType::NOT_MASK &&
+ mask_type != Layer::LayerMaskType::NOT_MASK);
+ mask_type_ = mask_type;
+}
+
const char* PictureLayerImpl::LayerTypeAsString() const {
return "cc::PictureLayerImpl";
}
@@ -131,10 +142,10 @@ std::unique_ptr<LayerImpl> PictureLayerImpl::CreateLayerImpl(
void PictureLayerImpl::PushPropertiesTo(LayerImpl* base_layer) {
PictureLayerImpl* layer_impl = static_cast<PictureLayerImpl*>(base_layer);
- DCHECK_EQ(layer_impl->mask_type_, mask_type_);
LayerImpl::PushPropertiesTo(base_layer);
+ layer_impl->SetLayerMaskType(mask_type());
// Twin relationships should never change once established.
DCHECK(!twin_layer_ || twin_layer_ == layer_impl);
DCHECK(!twin_layer_ || layer_impl->twin_layer_ == this);
@@ -215,8 +226,9 @@ void PictureLayerImpl::AppendQuads(RenderPass* render_pass,
if (current_draw_mode_ == DRAW_MODE_RESOURCELESS_SOFTWARE) {
AppendDebugBorderQuad(
- render_pass, shared_quad_state->quad_layer_bounds, shared_quad_state,
- append_quads_data, DebugColors::DirectPictureBorderColor(),
+ render_pass, shared_quad_state->quad_layer_rect.size(),
+ shared_quad_state, append_quads_data,
+ DebugColors::DirectPictureBorderColor(),
DebugColors::DirectPictureBorderWidth(device_scale_factor));
gfx::Rect geometry_rect = shared_quad_state->visible_quad_layer_rect;
@@ -250,7 +262,7 @@ void PictureLayerImpl::AppendQuads(RenderPass* render_pass,
return;
}
- AppendDebugBorderQuad(render_pass, shared_quad_state->quad_layer_bounds,
+ AppendDebugBorderQuad(render_pass, shared_quad_state->quad_layer_rect.size(),
shared_quad_state, append_quads_data);
if (ShowDebugBorders(DebugBorderType::LAYER)) {
@@ -365,7 +377,8 @@ void PictureLayerImpl::AppendQuads(RenderPass* render_pass,
float alpha =
(SkColorGetA(draw_info.solid_color()) * (1.0f / 255.0f)) *
shared_quad_state->opacity;
- if (alpha >= std::numeric_limits<float>::epsilon()) {
+ if (mask_type_ == Layer::LayerMaskType::MULTI_TEXTURE_MASK ||
+ alpha >= std::numeric_limits<float>::epsilon()) {
SolidColorDrawQuad* quad =
render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
quad->SetNew(shared_quad_state, geometry_rect,
@@ -731,10 +744,10 @@ const PictureLayerTiling* PictureLayerImpl::GetPendingOrActiveTwinTiling(
const PictureLayerTiling* twin_tiling =
twin_layer->tilings_->FindTilingWithScaleKey(
tiling->contents_scale_key());
- DCHECK(tiling->raster_transform().translation() == gfx::Vector2dF());
- DCHECK(!twin_tiling ||
- twin_tiling->raster_transform().translation() == gfx::Vector2dF());
- return twin_tiling;
+ if (twin_tiling &&
+ twin_tiling->raster_transform() == tiling->raster_transform())
+ return twin_tiling;
+ return nullptr;
}
bool PictureLayerImpl::RequiresHighResToDraw() const {
@@ -838,8 +851,10 @@ gfx::Size PictureLayerImpl::CalculateTileSize(
return gfx::Size(tile_width, tile_height);
}
-void PictureLayerImpl::GetContentsResourceId(ResourceId* resource_id,
- gfx::Size* resource_size) const {
+void PictureLayerImpl::GetContentsResourceId(
+ ResourceId* resource_id,
+ gfx::Size* resource_size,
+ gfx::SizeF* resource_uv_size) const {
// The bounds and the pile size may differ if the pile wasn't updated (ie.
// PictureLayer::Update didn't happen). In that case the pile will be empty.
DCHECK(raster_source_->GetSize().IsEmpty() ||
@@ -872,6 +887,18 @@ void PictureLayerImpl::GetContentsResourceId(ResourceId* resource_id,
*resource_id = draw_info.resource_id();
*resource_size = draw_info.resource_size();
+ // |resource_uv_size| represents the range of UV coordinates that map to the
+ // content being drawn. Typically, we draw to the entire texture, so these
+ // coordinates are (1.0f, 1.0f). However, if we are rasterizing to an
+ // over-large texture, this size will be smaller, mapping to the subset of the
+ // texture being used.
+ gfx::SizeF requested_tile_size =
+ gfx::SizeF(iter->tiling()->tiling_data()->tiling_size());
+ DCHECK_LE(requested_tile_size.width(), draw_info.resource_size().width());
+ DCHECK_LE(requested_tile_size.height(), draw_info.resource_size().height());
+ *resource_uv_size = gfx::SizeF(
+ requested_tile_size.width() / draw_info.resource_size().width(),
+ requested_tile_size.height() / draw_info.resource_size().height());
}
void PictureLayerImpl::SetNearestNeighbor(bool nearest_neighbor) {
@@ -890,13 +917,13 @@ void PictureLayerImpl::SetUseTransformedRasterization(bool use) {
NoteLayerPropertyChanged();
}
-PictureLayerTiling* PictureLayerImpl::AddTiling(float contents_scale) {
+PictureLayerTiling* PictureLayerImpl::AddTiling(
+ const gfx::AxisTransform2d& contents_transform) {
DCHECK(CanHaveTilings());
- DCHECK_GE(contents_scale, MinimumContentsScale());
- DCHECK_LE(contents_scale, MaximumContentsScale());
+ DCHECK_GE(contents_transform.scale(), MinimumContentsScale());
+ DCHECK_LE(contents_transform.scale(), MaximumContentsScale());
DCHECK(raster_source_->HasRecordings());
- return tilings_->AddTiling(
- gfx::AxisTransform2d(contents_scale, gfx::Vector2dF()), raster_source_);
+ return tilings_->AddTiling(contents_transform, raster_source_);
}
void PictureLayerImpl::RemoveAllTilings() {
@@ -912,9 +939,21 @@ void PictureLayerImpl::AddTilingsForRasterScale() {
PictureLayerTiling* high_res =
tilings_->FindTilingWithScaleKey(raster_contents_scale_);
+ // Note: This function is always invoked when raster scale is recomputed,
+ // but not necessarily changed. This means raster translation update is also
+ // always done when there are significant changes that triggered raster scale
+ // recomputation.
+ gfx::Vector2dF raster_translation =
+ CalculateRasterTranslation(raster_contents_scale_);
+ if (high_res &&
+ high_res->raster_transform().translation() != raster_translation) {
+ tilings_->Remove(high_res);
+ high_res = nullptr;
+ }
if (!high_res) {
// We always need a high res tiling, so create one if it doesn't exist.
- high_res = AddTiling(raster_contents_scale_);
+ high_res = AddTiling(
+ gfx::AxisTransform2d(raster_contents_scale_, raster_translation));
} else if (high_res->may_contain_low_resolution_tiles()) {
// If the tiling we find here was LOW_RESOLUTION previously, it may not be
// fully rastered, so destroy the old tiles.
@@ -1011,7 +1050,8 @@ void PictureLayerImpl::AddLowResolutionTilingIfNeeded() {
bool is_animating = draw_properties().screen_space_transform_is_animating;
if (!is_pinching && !is_animating) {
if (!low_res)
- low_res = AddTiling(low_res_raster_contents_scale_);
+ low_res = AddTiling(gfx::AxisTransform2d(low_res_raster_contents_scale_,
+ gfx::Vector2dF()));
low_res->set_resolution(LOW_RESOLUTION);
}
}
@@ -1177,6 +1217,34 @@ void PictureLayerImpl::CleanUpTilingsOnActiveLayer(
SanityCheckTilingState();
}
+gfx::Vector2dF PictureLayerImpl::CalculateRasterTranslation(
+ float raster_scale) {
+ if (!use_transformed_rasterization_)
+ return gfx::Vector2dF();
+
+ DCHECK(!draw_properties().screen_space_transform_is_animating);
+ gfx::Transform draw_transform = DrawTransform();
+ DCHECK(draw_transform.IsScaleOrTranslation());
+
+ // It is only useful to align the content space to the target space if their
+ // relative pixel ratio is some small rational number. Currently we only
+ // align if the relative pixel ratio is 1:1.
+ // Good match if the maximum alignment error on a layer of size 10000px
+ // does not exceed 0.001px.
+ static constexpr float kErrorThreshold = 0.0000001f;
+ if (std::abs(draw_transform.matrix().getFloat(0, 0) - raster_scale) >
+ kErrorThreshold ||
+ std::abs(draw_transform.matrix().getFloat(1, 1) - raster_scale) >
+ kErrorThreshold)
+ return gfx::Vector2dF();
+
+ // Extract the fractional part of layer origin in the target space.
+ float origin_x = draw_transform.matrix().getFloat(0, 3);
+ float origin_y = draw_transform.matrix().getFloat(1, 3);
+ return gfx::Vector2dF(origin_x - floorf(origin_x),
+ origin_y - floorf(origin_y));
+}
+
float PictureLayerImpl::MinimumContentsScale() const {
float setting_min = layer_tree_impl()->settings().minimum_contents_scale;
@@ -1390,12 +1458,12 @@ bool PictureLayerImpl::IsOnActiveOrPendingTree() const {
}
bool PictureLayerImpl::HasValidTilePriorities() const {
- return IsOnActiveOrPendingTree() &&
- is_drawn_render_surface_layer_list_member();
+ return IsOnActiveOrPendingTree() && (contributes_to_drawn_render_surface() ||
+ raster_even_if_not_in_rsll());
}
void PictureLayerImpl::InvalidateRegionForImages(
- const ImageIdFlatSet& images_to_invalidate) {
+ const PaintImageIdFlatSet& images_to_invalidate) {
TRACE_EVENT_BEGIN0("cc", "PictureLayerImpl::InvalidateRegionForImages");
InvalidationRegion image_invalidation;
diff --git a/chromium/cc/layers/picture_layer_impl.h b/chromium/cc/layers/picture_layer_impl.h
index 0e85d8d4208..96ac75c45d5 100644
--- a/chromium/cc/layers/picture_layer_impl.h
+++ b/chromium/cc/layers/picture_layer_impl.h
@@ -38,6 +38,7 @@ class CC_EXPORT PictureLayerImpl
~PictureLayerImpl() override;
Layer::LayerMaskType mask_type() const { return mask_type_; }
+ void SetLayerMaskType(Layer::LayerMaskType type);
// LayerImpl overrides.
const char* LayerTypeAsString() const override;
@@ -76,7 +77,8 @@ class CC_EXPORT PictureLayerImpl
// Mask-related functions.
void GetContentsResourceId(ResourceId* resource_id,
- gfx::Size* resource_size) const override;
+ gfx::Size* resource_size,
+ gfx::SizeF* resource_uv_size) const override;
void SetNearestNeighbor(bool nearest_neighbor);
@@ -101,18 +103,20 @@ class CC_EXPORT PictureLayerImpl
is_directly_composited_image_ = is_directly_composited_image;
}
- void InvalidateRegionForImages(const ImageIdFlatSet& images_to_invalidate);
+ void InvalidateRegionForImages(
+ const PaintImageIdFlatSet& images_to_invalidate);
protected:
PictureLayerImpl(LayerTreeImpl* tree_impl,
int id,
Layer::LayerMaskType mask_type);
- PictureLayerTiling* AddTiling(float contents_scale);
+ PictureLayerTiling* AddTiling(const gfx::AxisTransform2d& contents_transform);
void RemoveAllTilings();
void AddTilingsForRasterScale();
void AddLowResolutionTilingIfNeeded();
bool ShouldAdjustRasterScale() const;
void RecalculateRasterScales();
+ gfx::Vector2dF CalculateRasterTranslation(float raster_scale);
void CleanUpTilingsOnActiveLayer(
const std::vector<PictureLayerTiling*>& used_tilings);
float MinimumContentsScale() const;
@@ -150,7 +154,7 @@ class CC_EXPORT PictureLayerImpl
bool was_screen_space_transform_animating_;
bool only_used_low_res_last_append_quads_;
- const Layer::LayerMaskType mask_type_;
+ Layer::LayerMaskType mask_type_;
bool nearest_neighbor_;
bool use_transformed_rasterization_;
diff --git a/chromium/cc/layers/picture_layer_impl_perftest.cc b/chromium/cc/layers/picture_layer_impl_perftest.cc
index a434297fbc9..270978d8cff 100644
--- a/chromium/cc/layers/picture_layer_impl_perftest.cc
+++ b/chromium/cc/layers/picture_layer_impl_perftest.cc
@@ -28,7 +28,8 @@ static const int kTimeCheckInterval = 10;
void AddTiling(float scale,
FakePictureLayerImpl* layer,
std::vector<Tile*>* all_tiles) {
- PictureLayerTiling* tiling = layer->AddTiling(scale);
+ PictureLayerTiling* tiling =
+ layer->AddTiling(gfx::AxisTransform2d(scale, gfx::Vector2dF()));
tiling->set_resolution(HIGH_RESOLUTION);
tiling->CreateAllTilesForTesting();
@@ -186,11 +187,12 @@ TEST_F(PictureLayerImplPerfTest, TilingSetRasterQueueConstructAndIterate) {
float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
- pending_layer_->AddTiling(low_res_factor);
- pending_layer_->AddTiling(0.3f);
- pending_layer_->AddTiling(0.7f);
- pending_layer_->AddTiling(1.0f);
- pending_layer_->AddTiling(2.0f);
+ pending_layer_->AddTiling(
+ gfx::AxisTransform2d(low_res_factor, gfx::Vector2dF()));
+ pending_layer_->AddTiling(gfx::AxisTransform2d(0.3f, gfx::Vector2dF()));
+ pending_layer_->AddTiling(gfx::AxisTransform2d(0.7f, gfx::Vector2dF()));
+ pending_layer_->AddTiling(gfx::AxisTransform2d(1.0f, gfx::Vector2dF()));
+ pending_layer_->AddTiling(gfx::AxisTransform2d(2.0f, gfx::Vector2dF()));
RunRasterQueueConstructAndIterateTest("32_100x100", 32, gfx::Size(100, 100));
RunRasterQueueConstructAndIterateTest("32_500x500", 32, gfx::Size(500, 500));
@@ -203,11 +205,12 @@ TEST_F(PictureLayerImplPerfTest, TilingSetRasterQueueConstruct) {
float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
- pending_layer_->AddTiling(low_res_factor);
- pending_layer_->AddTiling(0.3f);
- pending_layer_->AddTiling(0.7f);
- pending_layer_->AddTiling(1.0f);
- pending_layer_->AddTiling(2.0f);
+ pending_layer_->AddTiling(
+ gfx::AxisTransform2d(low_res_factor, gfx::Vector2dF()));
+ pending_layer_->AddTiling(gfx::AxisTransform2d(0.3f, gfx::Vector2dF()));
+ pending_layer_->AddTiling(gfx::AxisTransform2d(0.7f, gfx::Vector2dF()));
+ pending_layer_->AddTiling(gfx::AxisTransform2d(1.0f, gfx::Vector2dF()));
+ pending_layer_->AddTiling(gfx::AxisTransform2d(2.0f, gfx::Vector2dF()));
RunRasterQueueConstructTest("0_0_100x100", gfx::Rect(0, 0, 100, 100));
RunRasterQueueConstructTest("5000_0_100x100", gfx::Rect(5000, 0, 100, 100));
diff --git a/chromium/cc/layers/picture_layer_impl_unittest.cc b/chromium/cc/layers/picture_layer_impl_unittest.cc
index 6ccf44a18d5..d9c825906cc 100644
--- a/chromium/cc/layers/picture_layer_impl_unittest.cc
+++ b/chromium/cc/layers/picture_layer_impl_unittest.cc
@@ -161,7 +161,7 @@ class PictureLayerImplTest : public TestLayerTreeHostBase {
gfx::Transform scale_transform;
scale_transform.Scale(ideal_contents_scale, ideal_contents_scale);
layer->draw_properties().screen_space_transform = scale_transform;
- layer->set_is_drawn_render_surface_layer_list_member(true);
+ layer->set_contributes_to_drawn_render_surface(true);
DCHECK_EQ(layer->GetIdealContentsScale(), ideal_contents_scale);
layer->layer_tree_impl()->property_trees()->SetAnimationScalesForTesting(
layer->transform_tree_index(), maximum_animation_contents_scale,
@@ -417,7 +417,8 @@ TEST_F(PictureLayerImplTest, ClonePartialInvalidation) {
Region());
ActivateTree();
// Add a unique tiling on the active tree.
- PictureLayerTiling* tiling = active_layer()->AddTiling(3.f);
+ PictureLayerTiling* tiling =
+ active_layer()->AddTiling(gfx::AxisTransform2d(3.f, gfx::Vector2dF()));
tiling->set_resolution(HIGH_RESOLUTION);
tiling->CreateAllTilesForTesting();
@@ -1230,9 +1231,12 @@ TEST_F(PictureLayerImplTest, HugeMasksGetScaledDown) {
// The mask resource exists.
ResourceId mask_resource_id;
gfx::Size mask_texture_size;
- active_mask->GetContentsResourceId(&mask_resource_id, &mask_texture_size);
+ gfx::SizeF mask_uv_size;
+ active_mask->GetContentsResourceId(&mask_resource_id, &mask_texture_size,
+ &mask_uv_size);
EXPECT_NE(0u, mask_resource_id);
EXPECT_EQ(active_mask->bounds(), mask_texture_size);
+ EXPECT_EQ(gfx::SizeF(1.0f, 1.0f), mask_uv_size);
// Drop resources and recreate them, still the same.
pending_mask->ReleaseTileResources();
@@ -1243,8 +1247,6 @@ TEST_F(PictureLayerImplTest, HugeMasksGetScaledDown) {
false);
active_mask->HighResTiling()->CreateAllTilesForTesting();
EXPECT_EQ(1u, active_mask->HighResTiling()->AllTilesForTesting().size());
- EXPECT_NE(0u, mask_resource_id);
- EXPECT_EQ(active_mask->bounds(), mask_texture_size);
// Resize larger than the max texture size.
int max_texture_size = host_impl()->resource_provider()->max_texture_size();
@@ -1271,11 +1273,13 @@ TEST_F(PictureLayerImplTest, HugeMasksGetScaledDown) {
// Mask layers have a tiling with a single tile in it.
EXPECT_EQ(1u, active_mask->HighResTiling()->AllTilesForTesting().size());
// The mask resource exists.
- active_mask->GetContentsResourceId(&mask_resource_id, &mask_texture_size);
+ active_mask->GetContentsResourceId(&mask_resource_id, &mask_texture_size,
+ &mask_uv_size);
EXPECT_NE(0u, mask_resource_id);
gfx::Size expected_size = active_mask->bounds();
expected_size.SetToMin(gfx::Size(max_texture_size, max_texture_size));
EXPECT_EQ(expected_size, mask_texture_size);
+ EXPECT_EQ(gfx::SizeF(1.0f, 1.0f), mask_uv_size);
// Drop resources and recreate them, still the same.
pending_mask->ReleaseTileResources();
@@ -1293,9 +1297,11 @@ TEST_F(PictureLayerImplTest, HugeMasksGetScaledDown) {
SetupPendingTree(huge_raster_source);
ActivateTree();
EXPECT_EQ(1u, active_mask->HighResTiling()->AllTilesForTesting().size());
- active_layer()->GetContentsResourceId(&mask_resource_id, &mask_texture_size);
+ active_layer()->GetContentsResourceId(&mask_resource_id, &mask_texture_size,
+ &mask_uv_size);
EXPECT_EQ(expected_size, mask_texture_size);
EXPECT_EQ(0u, mask_resource_id);
+ EXPECT_EQ(gfx::SizeF(1.0f, 1.0f), mask_uv_size);
// Resize even larger, so that the scale would be smaller than the minimum
// contents scale. Then the layer should no longer have any tiling.
@@ -1360,11 +1366,14 @@ TEST_F(PictureLayerImplTest, ScaledMaskLayer) {
// The mask resource exists.
ResourceId mask_resource_id;
gfx::Size mask_texture_size;
- active_mask->GetContentsResourceId(&mask_resource_id, &mask_texture_size);
+ gfx::SizeF mask_uv_size;
+ active_mask->GetContentsResourceId(&mask_resource_id, &mask_texture_size,
+ &mask_uv_size);
EXPECT_NE(0u, mask_resource_id);
gfx::Size expected_mask_texture_size =
gfx::ScaleToCeiledSize(active_mask->bounds(), 1.3f);
EXPECT_EQ(mask_texture_size, expected_mask_texture_size);
+ EXPECT_EQ(gfx::SizeF(1.0f, 1.0f), mask_uv_size);
}
TEST_F(PictureLayerImplTest, ReleaseTileResources) {
@@ -2133,7 +2142,7 @@ TEST_F(PictureLayerImplTest, ActivateUninitializedLayer) {
pending_raster_source);
pending_layer->SetDrawsContent(true);
pending_tree->SetRootLayerForTesting(std::move(pending_layer));
- pending_tree->BuildLayerListForTesting();
+ pending_tree->BuildLayerListAndPropertyTreesForTesting();
FakePictureLayerImpl* raw_pending_layer = static_cast<FakePictureLayerImpl*>(
host_impl()->pending_tree()->LayerById(layer_id()));
@@ -2352,7 +2361,7 @@ TEST_F(PictureLayerImplTest, SyncTilingAfterGpuRasterizationToggles) {
host_impl()->SetHasGpuRasterizationTrigger(true);
host_impl()->SetContentIsSuitableForGpuRasterization(false);
host_impl()->CommitComplete();
- EXPECT_EQ(GpuRasterizationStatus::OFF_CONTENT,
+ EXPECT_EQ(GpuRasterizationStatus::ON,
host_impl()->gpu_rasterization_status());
}
@@ -3570,9 +3579,9 @@ TEST_F(PictureLayerImplTest, SharedQuadStateContainsMaxTilingScale) {
->quad_to_target_transform.ToString());
// The content_bounds should be scaled by the
// MaximumTilingContentsScale on the layer.
- EXPECT_EQ(gfx::Size(2500u, 5000u).ToString(),
- render_pass->shared_quad_state_list.front()
- ->quad_layer_bounds.ToString());
+ EXPECT_EQ(
+ gfx::Rect(2500u, 5000u).ToString(),
+ render_pass->shared_quad_state_list.front()->quad_layer_rect.ToString());
// The visible_layer_rect should be scaled by the
// MaximumTilingContentsScale on the layer.
EXPECT_EQ(gfx::Rect(0u, 0u, 2500u, 5000u).ToString(),
@@ -3929,11 +3938,21 @@ TEST_F(OcclusionTrackingPictureLayerImplTest, OcclusionForDifferentScales) {
pending_layer()->tilings()->RemoveAllTilings();
float low_res_factor = host_impl()->settings().low_res_contents_scale_factor;
- pending_layer()->AddTiling(low_res_factor)->set_resolution(LOW_RESOLUTION);
- pending_layer()->AddTiling(0.3f)->set_resolution(HIGH_RESOLUTION);
- pending_layer()->AddTiling(0.7f)->set_resolution(HIGH_RESOLUTION);
- pending_layer()->AddTiling(1.0f)->set_resolution(HIGH_RESOLUTION);
- pending_layer()->AddTiling(2.0f)->set_resolution(HIGH_RESOLUTION);
+ pending_layer()
+ ->AddTiling(gfx::AxisTransform2d(low_res_factor, gfx::Vector2dF()))
+ ->set_resolution(LOW_RESOLUTION);
+ pending_layer()
+ ->AddTiling(gfx::AxisTransform2d(0.3f, gfx::Vector2dF()))
+ ->set_resolution(HIGH_RESOLUTION);
+ pending_layer()
+ ->AddTiling(gfx::AxisTransform2d(0.7f, gfx::Vector2dF()))
+ ->set_resolution(HIGH_RESOLUTION);
+ pending_layer()
+ ->AddTiling(gfx::AxisTransform2d(1.0f, gfx::Vector2dF()))
+ ->set_resolution(HIGH_RESOLUTION);
+ pending_layer()
+ ->AddTiling(gfx::AxisTransform2d(2.0f, gfx::Vector2dF()))
+ ->set_resolution(HIGH_RESOLUTION);
RebuildPropertyTreesOnPendingTree();
host_impl()->AdvanceToNextFrame(base::TimeDelta::FromMilliseconds(1));
@@ -5000,5 +5019,135 @@ TEST_F(PictureLayerImplTest, CompositedImageRasterScaleChanges) {
}
}
+TEST_F(PictureLayerImplTest, ChangeRasterTranslationNukePendingLayerTiles) {
+ gfx::Size layer_bounds(200, 200);
+ gfx::Size tile_size(256, 256);
+ SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size, Region());
+ pending_layer()->SetUseTransformedRasterization(true);
+
+ // Start with scale & translation of * 2.25 + (0.25, 0.5).
+ SetupDrawProperties(pending_layer(), 2.25f, 1.5f, 1.f, 2.25f, 2.25f, false);
+ gfx::Transform translate1;
+ translate1.Translate(0.25f, 0.5f);
+ pending_layer()->draw_properties().screen_space_transform.ConcatTransform(
+ translate1);
+ pending_layer()->draw_properties().target_space_transform =
+ pending_layer()->draw_properties().screen_space_transform;
+ pending_layer()->UpdateTiles();
+ ASSERT_EQ(1u, pending_layer()->tilings()->num_tilings());
+ {
+ PictureLayerTiling* tiling = pending_layer()->tilings()->tiling_at(0);
+ EXPECT_EQ(gfx::AxisTransform2d(2.25f, gfx::Vector2dF(0.25f, 0.5f)),
+ tiling->raster_transform());
+ EXPECT_EQ(4u, tiling->AllTilesForTesting().size());
+ for (auto* tile : tiling->AllTilesForTesting())
+ EXPECT_EQ(tile->raster_transform(), tiling->raster_transform());
+ }
+
+ // Change to scale & translation of * 2.25 + (0.75, 0.25).
+ // Verifies there is a hysteresis that simple layer movement doesn't update
+ // raster translation.
+ SetupDrawProperties(pending_layer(), 2.25f, 1.5f, 1.f, 2.25f, 2.25f, false);
+ gfx::Transform translate2;
+ translate2.Translate(0.75f, 0.25f);
+ pending_layer()->draw_properties().screen_space_transform.ConcatTransform(
+ translate2);
+ pending_layer()->draw_properties().target_space_transform =
+ pending_layer()->draw_properties().screen_space_transform;
+ pending_layer()->UpdateTiles();
+ ASSERT_EQ(1u, pending_layer()->tilings()->num_tilings());
+ {
+ PictureLayerTiling* tiling = pending_layer()->tilings()->tiling_at(0);
+ EXPECT_EQ(gfx::AxisTransform2d(2.25f, gfx::Vector2dF(0.25f, 0.5f)),
+ tiling->raster_transform());
+ EXPECT_EQ(4u, tiling->AllTilesForTesting().size());
+ for (auto* tile : tiling->AllTilesForTesting())
+ EXPECT_EQ(tile->raster_transform(), tiling->raster_transform());
+ }
+
+ // Now change the device scale factor but keep the same total scale.
+ // Our policy recomputes raster translation only if raster scale is
+ // recomputed. Even if the recomputed scale remains the same, we still
+ // updates to new translation value. Old tiles with the same scale but
+ // different translation would become non-ideal and deleted on pending
+ // layers (in fact, delete ahead due to slot conflict with the new tiling).
+ SetupDrawProperties(pending_layer(), 2.25f, 1.0f, 1.f, 2.25f, 2.25f, false);
+ pending_layer()->draw_properties().screen_space_transform.ConcatTransform(
+ translate2);
+ pending_layer()->draw_properties().target_space_transform =
+ pending_layer()->draw_properties().screen_space_transform;
+ pending_layer()->UpdateTiles();
+ ASSERT_EQ(1u, pending_layer()->tilings()->num_tilings());
+ {
+ PictureLayerTiling* tiling = pending_layer()->tilings()->tiling_at(0);
+ EXPECT_EQ(gfx::AxisTransform2d(2.25f, gfx::Vector2dF(0.75f, 0.25f)),
+ tiling->raster_transform());
+ EXPECT_EQ(4u, tiling->AllTilesForTesting().size());
+ for (auto* tile : tiling->AllTilesForTesting())
+ EXPECT_EQ(tile->raster_transform(), tiling->raster_transform());
+ }
+}
+
+TEST_F(PictureLayerImplTest, ChangeRasterTranslationNukeActiveLayerTiles) {
+ gfx::Size layer_bounds(200, 200);
+ gfx::Size tile_size(256, 256);
+ SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size, Region());
+ active_layer()->SetUseTransformedRasterization(true);
+ pending_layer()->SetUseTransformedRasterization(true);
+
+ // Start with scale & translation of * 2.25 + (0.25, 0.5) on the active layer.
+ SetupDrawProperties(active_layer(), 2.25f, 1.5f, 1.f, 2.25f, 2.25f, false);
+ gfx::Transform translate1;
+ translate1.Translate(0.25f, 0.5f);
+ active_layer()->draw_properties().screen_space_transform.ConcatTransform(
+ translate1);
+ active_layer()->draw_properties().target_space_transform =
+ active_layer()->draw_properties().screen_space_transform;
+ active_layer()->UpdateTiles();
+ ASSERT_EQ(3u, active_layer()->tilings()->num_tilings());
+ {
+ PictureLayerTiling* tiling =
+ active_layer()->tilings()->FindTilingWithScaleKey(2.25f);
+ EXPECT_EQ(gfx::AxisTransform2d(2.25f, gfx::Vector2dF(0.25f, 0.5f)),
+ tiling->raster_transform());
+ EXPECT_EQ(4u, tiling->AllTilesForTesting().size());
+ for (auto* tile : tiling->AllTilesForTesting())
+ EXPECT_EQ(tile->raster_transform(), tiling->raster_transform());
+ }
+
+ // Create a pending layer with the same scale but different translation.
+ SetupDrawProperties(pending_layer(), 2.25f, 1.5f, 1.f, 2.25f, 2.25f, false);
+ gfx::Transform translate2;
+ translate2.Translate(0.75f, 0.25f);
+ pending_layer()->draw_properties().screen_space_transform.ConcatTransform(
+ translate2);
+ pending_layer()->draw_properties().target_space_transform =
+ pending_layer()->draw_properties().screen_space_transform;
+ pending_layer()->UpdateTiles();
+ ASSERT_EQ(1u, pending_layer()->tilings()->num_tilings());
+ {
+ PictureLayerTiling* tiling = pending_layer()->tilings()->tiling_at(0);
+ EXPECT_EQ(gfx::AxisTransform2d(2.25f, gfx::Vector2dF(0.75f, 0.25f)),
+ tiling->raster_transform());
+ EXPECT_EQ(4u, tiling->AllTilesForTesting().size());
+ for (auto* tile : tiling->AllTilesForTesting())
+ EXPECT_EQ(tile->raster_transform(), tiling->raster_transform());
+ }
+
+ // Now push to the active layer.
+ // Verifies the active tiles get evicted due to slot conflict.
+ host_impl()->ActivateSyncTree();
+ ASSERT_EQ(3u, active_layer()->tilings()->num_tilings());
+ {
+ PictureLayerTiling* tiling =
+ active_layer()->tilings()->FindTilingWithScaleKey(2.25f);
+ EXPECT_EQ(gfx::AxisTransform2d(2.25f, gfx::Vector2dF(0.75f, 0.25f)),
+ tiling->raster_transform());
+ EXPECT_EQ(4u, tiling->AllTilesForTesting().size());
+ for (auto* tile : tiling->AllTilesForTesting())
+ EXPECT_EQ(tile->raster_transform(), tiling->raster_transform());
+ }
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/layers/picture_layer_unittest.cc b/chromium/cc/layers/picture_layer_unittest.cc
index 1ba4387702c..f976ab9f206 100644
--- a/chromium/cc/layers/picture_layer_unittest.cc
+++ b/chromium/cc/layers/picture_layer_unittest.cc
@@ -45,7 +45,6 @@ TEST(PictureLayerTest, NoTilesIfEmptyBounds) {
&host_client, &task_graph_runner, animation_host.get());
host->SetRootLayer(layer);
layer->SetIsDrawable(true);
- layer->SavePaintProperties();
layer->Update();
EXPECT_EQ(0, host->SourceFrameNumber());
@@ -53,7 +52,6 @@ TEST(PictureLayerTest, NoTilesIfEmptyBounds) {
EXPECT_EQ(1, host->SourceFrameNumber());
layer->SetBounds(gfx::Size(0, 0));
- layer->SavePaintProperties();
// Intentionally skipping Update since it would normally be skipped on
// a layer with empty bounds.
@@ -89,7 +87,6 @@ TEST(PictureLayerTest, InvalidateRasterAfterUpdate) {
&host_client, &task_graph_runner, animation_host.get());
host->SetRootLayer(layer);
layer->SetIsDrawable(true);
- layer->SavePaintProperties();
gfx::Rect invalidation_bounds(layer_size);
@@ -102,7 +99,6 @@ TEST(PictureLayerTest, InvalidateRasterAfterUpdate) {
std::unique_ptr<CompositorFrameSink> compositor_frame_sink(
FakeCompositorFrameSink::Create3d());
LayerTreeSettings layer_tree_settings = LayerTreeSettings();
- layer_tree_settings.image_decode_tasks_enabled = true;
FakeLayerTreeHostImpl host_impl(
layer_tree_settings, &impl_task_runner_provider, &task_graph_runner);
host_impl.SetVisible(true);
@@ -133,7 +129,6 @@ TEST(PictureLayerTest, InvalidateRasterWithoutUpdate) {
&host_client, &task_graph_runner, animation_host.get());
host->SetRootLayer(layer);
layer->SetIsDrawable(true);
- layer->SavePaintProperties();
gfx::Rect invalidation_bounds(layer_size);
@@ -145,7 +140,6 @@ TEST(PictureLayerTest, InvalidateRasterWithoutUpdate) {
std::unique_ptr<CompositorFrameSink> compositor_frame_sink(
FakeCompositorFrameSink::Create3d());
LayerTreeSettings layer_tree_settings = LayerTreeSettings();
- layer_tree_settings.image_decode_tasks_enabled = true;
FakeLayerTreeHostImpl host_impl(
layer_tree_settings, &impl_task_runner_provider, &task_graph_runner);
host_impl.SetVisible(true);
@@ -177,22 +171,20 @@ TEST(PictureLayerTest, ClearVisibleRectWhenNoTiling) {
&host_client, &task_graph_runner, animation_host.get());
host->SetRootLayer(layer);
layer->SetIsDrawable(true);
- layer->SavePaintProperties();
layer->Update();
EXPECT_EQ(0, host->SourceFrameNumber());
host->CommitComplete();
EXPECT_EQ(1, host->SourceFrameNumber());
- layer->SavePaintProperties();
layer->Update();
+ host->BuildPropertyTreesForTesting();
FakeImplTaskRunnerProvider impl_task_runner_provider;
std::unique_ptr<CompositorFrameSink> compositor_frame_sink(
FakeCompositorFrameSink::Create3d());
LayerTreeSettings layer_tree_settings = LayerTreeSettings();
- layer_tree_settings.image_decode_tasks_enabled = true;
FakeLayerTreeHostImpl host_impl(
layer_tree_settings, &impl_task_runner_provider, &task_graph_runner);
host_impl.SetVisible(true);
@@ -201,7 +193,7 @@ TEST(PictureLayerTest, ClearVisibleRectWhenNoTiling) {
host_impl.CreatePendingTree();
host_impl.pending_tree()->SetRootLayerForTesting(
FakePictureLayerImpl::Create(host_impl.pending_tree(), 1));
- host_impl.pending_tree()->BuildLayerListForTesting();
+ host_impl.pending_tree()->BuildLayerListAndPropertyTreesForTesting();
FakePictureLayerImpl* layer_impl = static_cast<FakePictureLayerImpl*>(
host_impl.pending_tree()->root_layer_for_testing());
@@ -220,7 +212,6 @@ TEST(PictureLayerTest, ClearVisibleRectWhenNoTiling) {
host_impl.active_tree()->UpdateDrawProperties(can_use_lcd_text);
layer->SetBounds(gfx::Size(11, 11));
- layer->SavePaintProperties();
host_impl.CreatePendingTree();
layer_impl = static_cast<FakePictureLayerImpl*>(
@@ -317,7 +308,6 @@ TEST(PictureLayerTest, NonMonotonicSourceFrameNumber) {
auto animation_host2 = AnimationHost::CreateForTesting(ThreadInstance::MAIN);
- // TODO(sad): InitParams will be movable.
LayerTreeHost::InitParams params2;
params2.client = &host_client1;
params2.settings = &settings;
@@ -360,5 +350,81 @@ TEST(PictureLayerTest, NonMonotonicSourceFrameNumber) {
animation_host2->SetMutatorHostClient(nullptr);
}
+// Verify that PictureLayer::DropRecordingSourceContentIfInvalid does not
+// assert when changing frames.
+TEST(PictureLayerTest, ChangingHostsWithCollidingFrames) {
+ LayerTreeSettings settings = LayerTreeSettings();
+ settings.single_thread_proxy_scheduler = false;
+
+ StubLayerTreeHostSingleThreadClient single_thread_client;
+ FakeLayerTreeHostClient host_client1;
+ FakeLayerTreeHostClient host_client2;
+ TestTaskGraphRunner task_graph_runner;
+
+ FakeContentLayerClient client;
+ client.set_bounds(gfx::Size());
+ scoped_refptr<FakePictureLayer> layer = FakePictureLayer::Create(&client);
+
+ auto animation_host = AnimationHost::CreateForTesting(ThreadInstance::MAIN);
+
+ LayerTreeHost::InitParams params;
+ params.client = &host_client1;
+ params.settings = &settings;
+ params.task_graph_runner = &task_graph_runner;
+ params.main_task_runner = base::ThreadTaskRunnerHandle::Get();
+ params.mutator_host = animation_host.get();
+ std::unique_ptr<LayerTreeHost> host1 =
+ LayerTreeHost::CreateSingleThreaded(&single_thread_client, &params);
+ host1->SetVisible(true);
+ host_client1.SetLayerTreeHost(host1.get());
+
+ auto animation_host2 = AnimationHost::CreateForTesting(ThreadInstance::MAIN);
+
+ LayerTreeHost::InitParams params2;
+ params2.client = &host_client1;
+ params2.settings = &settings;
+ params2.task_graph_runner = &task_graph_runner;
+ params2.main_task_runner = base::ThreadTaskRunnerHandle::Get();
+ params2.client = &host_client2;
+ params2.mutator_host = animation_host2.get();
+ std::unique_ptr<LayerTreeHost> host2 =
+ LayerTreeHost::CreateSingleThreaded(&single_thread_client, &params2);
+ host2->SetVisible(true);
+ host_client2.SetLayerTreeHost(host2.get());
+
+ // The PictureLayer is put in one LayerTreeHost.
+ host1->SetRootLayer(layer);
+ // Do a main frame, record the picture layers.
+ EXPECT_EQ(0, layer->update_count());
+ layer->SetBounds(gfx::Size(500, 500));
+ host1->Composite(base::TimeTicks::Now());
+ EXPECT_EQ(1, layer->update_count());
+ EXPECT_EQ(1, host1->SourceFrameNumber());
+ EXPECT_EQ(gfx::Size(500, 500), layer->bounds());
+
+ // Then moved to another LayerTreeHost.
+ host1->SetRootLayer(nullptr);
+ scoped_refptr<Layer> root = Layer::Create();
+ host2->SetRootLayer(root);
+ root->AddChild(layer);
+
+ // Make the layer not update.
+ layer->SetHideLayerAndSubtree(true);
+ EXPECT_EQ(gfx::Size(500, 500),
+ layer->GetRecordingSourceForTesting()->GetSize());
+
+ // Change its bounds while it's in a state that can't update.
+ layer->SetBounds(gfx::Size(600, 600));
+ host2->Composite(base::TimeTicks::Now());
+
+ // This layer should not have been updated because it is invisible.
+ EXPECT_EQ(1, layer->update_count());
+ EXPECT_EQ(1, host2->SourceFrameNumber());
+
+ // This layer should also drop its recording source because it was resized
+ // and not recorded.
+ EXPECT_EQ(gfx::Size(), layer->GetRecordingSourceForTesting()->GetSize());
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/layers/recording_source.cc b/chromium/cc/layers/recording_source.cc
index 9b1efbd7137..e3a477a5b83 100644
--- a/chromium/cc/layers/recording_source.cc
+++ b/chromium/cc/layers/recording_source.cc
@@ -29,7 +29,6 @@ namespace cc {
RecordingSource::RecordingSource()
: slow_down_raster_scale_factor_for_debug_(0),
- generate_discardable_images_metadata_(false),
requires_clear_(false),
is_solid_color_(false),
clear_canvas_with_debug_color_(kDefaultClearCanvasSetting),
@@ -56,8 +55,7 @@ void RecordingSource::FinishDisplayItemListUpdate() {
TRACE_EVENT0("cc", "RecordingSource::FinishDisplayItemListUpdate");
DetermineIfSolidColor();
display_list_->EmitTraceSnapshot();
- if (generate_discardable_images_metadata_)
- display_list_->GenerateDiscardableImagesMetadata();
+ display_list_->GenerateDiscardableImagesMetadata();
}
void RecordingSource::SetNeedsDisplayRect(const gfx::Rect& layer_rect) {
@@ -121,11 +119,6 @@ void RecordingSource::SetSlowdownRasterScaleFactor(int factor) {
slow_down_raster_scale_factor_for_debug_ = factor;
}
-void RecordingSource::SetGenerateDiscardableImagesMetadata(
- bool generate_metadata) {
- generate_discardable_images_metadata_ = generate_metadata;
-}
-
void RecordingSource::SetBackgroundColor(SkColor background_color) {
background_color_ = background_color;
}
@@ -153,10 +146,10 @@ void RecordingSource::DetermineIfSolidColor() {
return;
TRACE_EVENT1("cc", "RecordingSource::DetermineIfSolidColor", "opcount",
- display_list_->ApproximateOpCount());
+ display_list_->OpCount());
gfx::Size layer_size = GetSize();
skia::AnalysisCanvas canvas(layer_size.width(), layer_size.height());
- display_list_->Raster(&canvas, nullptr, gfx::Rect(layer_size), 1.f);
+ display_list_->Raster(&canvas);
is_solid_color_ = canvas.GetColorIfSolid(&solid_color_);
}
diff --git a/chromium/cc/layers/recording_source.h b/chromium/cc/layers/recording_source.h
index dadb0e77548..32550fe2004 100644
--- a/chromium/cc/layers/recording_source.h
+++ b/chromium/cc/layers/recording_source.h
@@ -46,7 +46,6 @@ class CC_EXPORT RecordingSource {
gfx::Size GetSize() const;
void SetEmptyBounds();
void SetSlowdownRasterScaleFactor(int factor);
- void SetGenerateDiscardableImagesMetadata(bool generate_metadata);
void SetBackgroundColor(SkColor background_color);
void SetRequiresClear(bool requires_clear);
@@ -63,7 +62,6 @@ class CC_EXPORT RecordingSource {
gfx::Rect recorded_viewport_;
gfx::Size size_;
int slow_down_raster_scale_factor_for_debug_;
- bool generate_discardable_images_metadata_;
bool requires_clear_;
bool is_solid_color_;
bool clear_canvas_with_debug_color_;
diff --git a/chromium/cc/layers/recording_source_unittest.cc b/chromium/cc/layers/recording_source_unittest.cc
index 2a034a77125..d090ccdd567 100644
--- a/chromium/cc/layers/recording_source_unittest.cc
+++ b/chromium/cc/layers/recording_source_unittest.cc
@@ -68,7 +68,6 @@ TEST(RecordingSourceTest, DiscardableImagesWithTransform) {
translate_transform);
recording_source->add_draw_image_with_transform(discardable_image[1][1],
rotate_transform);
- recording_source->SetGenerateDiscardableImagesMetadata(true);
recording_source->Rerecord();
bool can_use_lcd_text = true;
@@ -127,33 +126,11 @@ TEST(RecordingSourceTest, DiscardableImagesWithTransform) {
}
}
-TEST(RecordingSourceTest, NoGatherImageEmptyImages) {
- gfx::Rect recorded_viewport(0, 0, 256, 256);
-
- std::unique_ptr<FakeRecordingSource> recording_source =
- CreateRecordingSource(recorded_viewport);
- recording_source->SetGenerateDiscardableImagesMetadata(false);
- recording_source->Rerecord();
-
- scoped_refptr<RasterSource> raster_source =
- CreateRasterSource(recording_source.get());
-
- // If recording source do not gather images, raster source is not going to
- // get images.
- {
- std::vector<DrawImage> images;
- raster_source->GetDiscardableImagesInRect(recorded_viewport, 1.f,
- DefaultColorSpace(), &images);
- EXPECT_TRUE(images.empty());
- }
-}
-
TEST(RecordingSourceTest, EmptyImages) {
gfx::Rect recorded_viewport(0, 0, 256, 256);
std::unique_ptr<FakeRecordingSource> recording_source =
CreateRecordingSource(recorded_viewport);
- recording_source->SetGenerateDiscardableImagesMetadata(true);
recording_source->Rerecord();
scoped_refptr<RasterSource> raster_source =
@@ -208,7 +185,6 @@ TEST(RecordingSourceTest, NoDiscardableImages) {
recording_source->add_draw_image(non_discardable_image, gfx::Point(128, 0));
recording_source->add_draw_image(non_discardable_image, gfx::Point(0, 128));
recording_source->add_draw_image(non_discardable_image, gfx::Point(150, 150));
- recording_source->SetGenerateDiscardableImagesMetadata(true);
recording_source->Rerecord();
scoped_refptr<RasterSource> raster_source =
@@ -258,7 +234,6 @@ TEST(RecordingSourceTest, DiscardableImages) {
recording_source->add_draw_image(discardable_image[1][0], gfx::Point(0, 130));
recording_source->add_draw_image(discardable_image[1][1],
gfx::Point(140, 140));
- recording_source->SetGenerateDiscardableImagesMetadata(true);
recording_source->Rerecord();
scoped_refptr<RasterSource> raster_source =
@@ -331,7 +306,6 @@ TEST(RecordingSourceTest, DiscardableImagesBaseNonDiscardable) {
recording_source->add_draw_image(discardable_image[0][1], gfx::Point(260, 0));
recording_source->add_draw_image(discardable_image[1][1],
gfx::Point(260, 260));
- recording_source->SetGenerateDiscardableImagesMetadata(true);
recording_source->Rerecord();
scoped_refptr<RasterSource> raster_source =
diff --git a/chromium/cc/layers/render_surface_impl.cc b/chromium/cc/layers/render_surface_impl.cc
index a03fb006fec..e1330f14f8a 100644
--- a/chromium/cc/layers/render_surface_impl.cc
+++ b/chromium/cc/layers/render_surface_impl.cc
@@ -38,10 +38,12 @@ RenderSurfaceImpl::RenderSurfaceImpl(LayerTreeImpl* layer_tree_impl,
: layer_tree_impl_(layer_tree_impl),
stable_effect_id_(stable_effect_id),
effect_tree_index_(EffectTree::kInvalidNodeId),
+ num_contributors_(0),
has_contributing_layer_that_escapes_clip_(false),
surface_property_changed_(false),
ancestor_property_changed_(false),
contributes_to_drawn_surface_(false),
+ is_render_surface_list_member_(false),
nearest_occlusion_immune_ancestor_(nullptr) {
damage_tracker_ = DamageTracker::Create();
}
@@ -125,7 +127,7 @@ LayerImpl* RenderSurfaceImpl::MaskLayer() {
}
bool RenderSurfaceImpl::HasMask() const {
- return OwningEffectNode()->mask_layer_id != EffectTree::kInvalidNodeId;
+ return OwningEffectNode()->mask_layer_id != Layer::INVALID_ID;
}
const FilterOperations& RenderSurfaceImpl::Filters() const {
@@ -160,10 +162,6 @@ int RenderSurfaceImpl::ClipTreeIndex() const {
}
int RenderSurfaceImpl::EffectTreeIndex() const {
- DCHECK_EQ(
- effect_tree_index_,
- layer_tree_impl_->property_trees()
- ->effect_tree.FindNodeIndexFromOwningLayerId(stable_effect_id_));
return effect_tree_index_;
}
@@ -339,7 +337,7 @@ void RenderSurfaceImpl::NoteAncestorPropertyChanged() {
ancestor_property_changed_ = true;
}
-gfx::Rect RenderSurfaceImpl::GetDamageRect() {
+gfx::Rect RenderSurfaceImpl::GetDamageRect() const {
gfx::Rect damage_rect;
bool is_valid_rect = damage_tracker_->GetDamageRectIfValid(&damage_rect);
if (!is_valid_rect)
@@ -352,16 +350,12 @@ void RenderSurfaceImpl::ResetPropertyChangedFlags() {
ancestor_property_changed_ = false;
}
-void RenderSurfaceImpl::ClearLayerLists() {
- layer_list_.clear();
-}
-
int RenderSurfaceImpl::GetRenderPassId() {
return id();
}
std::unique_ptr<RenderPass> RenderSurfaceImpl::CreateRenderPass() {
- std::unique_ptr<RenderPass> pass = RenderPass::Create(layer_list_.size());
+ std::unique_ptr<RenderPass> pass = RenderPass::Create(num_contributors_);
gfx::Rect damage_rect = GetDamageRect();
damage_rect.Intersect(content_rect());
pass->SetNew(id(), content_rect(), damage_rect,
@@ -385,7 +379,7 @@ void RenderSurfaceImpl::AppendQuads(RenderPass* render_pass,
SharedQuadState* shared_quad_state =
render_pass->CreateAndAppendSharedQuadState();
shared_quad_state->SetAll(
- draw_transform(), content_rect().size(), content_rect(),
+ draw_transform(), content_rect(), content_rect(),
draw_properties_.clip_rect, draw_properties_.is_clipped,
draw_properties_.draw_opacity, BlendMode(), sorting_context_id);
@@ -416,15 +410,18 @@ void RenderSurfaceImpl::AppendQuads(RenderPass* render_pass,
TileMaskLayer(render_pass, shared_quad_state, visible_layer_rect);
return;
}
- mask_layer->GetContentsResourceId(&mask_resource_id, &mask_texture_size);
+ gfx::SizeF mask_uv_size;
+ mask_layer->GetContentsResourceId(&mask_resource_id, &mask_texture_size,
+ &mask_uv_size);
gfx::SizeF unclipped_mask_target_size = gfx::ScaleSize(
gfx::SizeF(OwningEffectNode()->unscaled_mask_target_size),
surface_contents_scale.x(), surface_contents_scale.y());
- // Convert content_rect from target space to normalized space.
- // Where unclipped_mask_target_size maps to gfx::Size(1, 1).
- mask_uv_rect = gfx::ScaleRect(gfx::RectF(content_rect()),
- 1.0f / unclipped_mask_target_size.width(),
- 1.0f / unclipped_mask_target_size.height());
+ // Convert content_rect from target space to normalized mask UV space.
+ // Where |unclipped_mask_target_size| maps to |mask_uv_size|.
+ mask_uv_rect = gfx::ScaleRect(
+ gfx::RectF(content_rect()),
+ mask_uv_size.width() / unclipped_mask_target_size.width(),
+ mask_uv_size.height() / unclipped_mask_target_size.height());
}
gfx::RectF tex_coord_rect(gfx::Rect(content_rect().size()));
@@ -461,18 +458,18 @@ void RenderSurfaceImpl::TileMaskLayer(RenderPass* render_pass,
shared_quad_state->quad_to_target_transform.matrix().preScale(
mask_quad_to_surface_contents_scale.x(),
mask_quad_to_surface_contents_scale.y(), 1.f);
- shared_quad_state->quad_layer_bounds =
- gfx::ScaleToCeiledSize(shared_quad_state->quad_layer_bounds,
- 1.f / mask_quad_to_surface_contents_scale.x(),
- 1.f / mask_quad_to_surface_contents_scale.y());
+ shared_quad_state->quad_layer_rect =
+ gfx::ScaleToEnclosingRect(shared_quad_state->quad_layer_rect,
+ 1.f / mask_quad_to_surface_contents_scale.x(),
+ 1.f / mask_quad_to_surface_contents_scale.y());
shared_quad_state->visible_quad_layer_rect =
- gfx::ScaleToEnclosedRect(shared_quad_state->visible_quad_layer_rect,
- mask_quad_to_surface_contents_scale.x(),
- mask_quad_to_surface_contents_scale.y());
- gfx::Rect content_rect_in_coverage_space = gfx::ScaleToEnclosedRect(
+ gfx::ScaleToEnclosingRect(shared_quad_state->visible_quad_layer_rect,
+ mask_quad_to_surface_contents_scale.x(),
+ mask_quad_to_surface_contents_scale.y());
+ gfx::Rect content_rect_in_coverage_space = gfx::ScaleToEnclosingRect(
content_rect(), 1.f / mask_quad_to_surface_contents_scale.x(),
1.f / mask_quad_to_surface_contents_scale.y());
- gfx::Rect visible_layer_rect_in_coverage_space = gfx::ScaleToEnclosedRect(
+ gfx::Rect visible_layer_rect_in_coverage_space = gfx::ScaleToEnclosingRect(
visible_layer_rect, 1.f / mask_quad_to_surface_contents_scale.x(),
1.f / mask_quad_to_surface_contents_scale.y());
diff --git a/chromium/cc/layers/render_surface_impl.h b/chromium/cc/layers/render_surface_impl.h
index 5cf15e86af2..f02f3b74e27 100644
--- a/chromium/cc/layers/render_surface_impl.h
+++ b/chromium/cc/layers/render_surface_impl.h
@@ -104,6 +104,13 @@ class CC_EXPORT RenderSurfaceImpl {
return has_contributing_layer_that_escapes_clip_;
}
+ void set_is_render_surface_list_member(bool is_render_surface_list_member) {
+ is_render_surface_list_member_ = is_render_surface_list_member;
+ }
+ bool is_render_surface_list_member() const {
+ return is_render_surface_list_member_;
+ }
+
void CalculateContentRectFromAccumulatedContentRect(int max_texture_size);
void SetContentRectToViewport();
void SetContentRectForTesting(const gfx::Rect& rect);
@@ -119,6 +126,14 @@ class CC_EXPORT RenderSurfaceImpl {
return accumulated_content_rect_;
}
+ void increment_num_contributors() { num_contributors_++; }
+ void decrement_num_contributors() {
+ num_contributors_--;
+ DCHECK_GE(num_contributors_, 0);
+ }
+ void reset_num_contributors() { num_contributors_ = 0; }
+ int num_contributors() const { return num_contributors_; }
+
const Occlusion& occlusion_in_content_space() const {
return occlusion_in_content_space_;
}
@@ -126,9 +141,6 @@ class CC_EXPORT RenderSurfaceImpl {
occlusion_in_content_space_ = occlusion;
}
- LayerImplList& layer_list() { return layer_list_; }
- void ClearLayerLists();
-
int id() const { return stable_effect_id_; }
LayerImpl* MaskLayer();
@@ -148,7 +160,7 @@ class CC_EXPORT RenderSurfaceImpl {
void NoteAncestorPropertyChanged();
DamageTracker* damage_tracker() const { return damage_tracker_.get(); }
- gfx::Rect GetDamageRect();
+ gfx::Rect GetDamageRect() const;
int GetRenderPassId();
@@ -204,14 +216,15 @@ class CC_EXPORT RenderSurfaceImpl {
// Is used to calculate the content rect from property trees.
gfx::Rect accumulated_content_rect_;
+ int num_contributors_;
// Is used to decide if the surface is clipped.
bool has_contributing_layer_that_escapes_clip_ : 1;
bool surface_property_changed_ : 1;
bool ancestor_property_changed_ : 1;
bool contributes_to_drawn_surface_ : 1;
+ bool is_render_surface_list_member_ : 1;
- LayerImplList layer_list_;
Occlusion occlusion_in_content_space_;
// The nearest ancestor target surface that will contain the contents of this
diff --git a/chromium/cc/layers/render_surface_impl_unittest.cc b/chromium/cc/layers/render_surface_impl_unittest.cc
index 49f2f7d6eb9..6422ffa19fd 100644
--- a/chromium/cc/layers/render_surface_impl_unittest.cc
+++ b/chromium/cc/layers/render_surface_impl_unittest.cc
@@ -29,8 +29,7 @@ TEST(RenderSurfaceLayerImplTest, Occlusion) {
impl.CalcDrawProps(viewport_size);
- RenderSurfaceImpl* render_surface_impl =
- owning_layer_impl->GetRenderSurface();
+ RenderSurfaceImpl* render_surface_impl = GetRenderSurface(owning_layer_impl);
ASSERT_TRUE(render_surface_impl);
{
@@ -69,6 +68,7 @@ TEST(RenderSurfaceLayerImplTest, Occlusion) {
TEST(RenderSurfaceLayerImplTest, AppendQuadsWithScaledMask) {
gfx::Size layer_size(1000, 1000);
gfx::Size viewport_size(1000, 1000);
+ float scale_factor = 2;
scoped_refptr<FakeRasterSource> raster_source =
FakeRasterSource::CreateFilledSolidColor(layer_size);
@@ -83,14 +83,17 @@ TEST(RenderSurfaceLayerImplTest, AppendQuadsWithScaledMask) {
surface->test_properties()->force_render_surface = true;
gfx::Transform scale;
- scale.Scale(2, 2);
+ scale.Scale(scale_factor, scale_factor);
surface->test_properties()->transform = scale;
- surface->test_properties()->SetMaskLayer(FakeMaskLayerImpl::Create(
+ std::unique_ptr<FakeMaskLayerImpl> mask_layer = FakeMaskLayerImpl::Create(
impl.host_impl()->active_tree(), 4, raster_source,
- Layer::LayerMaskType::SINGLE_TEXTURE_MASK));
- surface->test_properties()->mask_layer->SetDrawsContent(true);
- surface->test_properties()->mask_layer->SetBounds(layer_size);
+ Layer::LayerMaskType::SINGLE_TEXTURE_MASK);
+ mask_layer->set_resource_size(
+ gfx::ScaleToCeiledSize(layer_size, scale_factor));
+ mask_layer->SetDrawsContent(true);
+ mask_layer->SetBounds(layer_size);
+ surface->test_properties()->SetMaskLayer(std::move(mask_layer));
std::unique_ptr<LayerImpl> child =
LayerImpl::Create(impl.host_impl()->active_tree(), 5);
@@ -110,7 +113,7 @@ TEST(RenderSurfaceLayerImplTest, AppendQuadsWithScaledMask) {
->root_layer_for_testing()
->test_properties()
->children[0];
- RenderSurfaceImpl* render_surface_impl = surface_raw->GetRenderSurface();
+ RenderSurfaceImpl* render_surface_impl = GetRenderSurface(surface_raw);
std::unique_ptr<RenderPass> render_pass = RenderPass::Create();
AppendQuadsData append_quads_data;
render_surface_impl->AppendQuads(render_pass.get(), &append_quads_data);
diff --git a/chromium/cc/layers/render_surface_unittest.cc b/chromium/cc/layers/render_surface_unittest.cc
index a8662d8aab0..05412a98f24 100644
--- a/chromium/cc/layers/render_surface_unittest.cc
+++ b/chromium/cc/layers/render_surface_unittest.cc
@@ -10,6 +10,7 @@
#include "cc/test/fake_impl_task_runner_provider.h"
#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/geometry_test_utils.h"
+#include "cc/test/layer_test_common.h"
#include "cc/test/mock_occlusion_tracker.h"
#include "cc/test/test_task_graph_runner.h"
#include "cc/trees/layer_tree_impl.h"
@@ -53,7 +54,7 @@ TEST(RenderSurfaceTest, VerifySurfaceChangesAreTrackedProperly) {
host_impl.active_tree()->UpdateDrawProperties(false /* update_lcd_text */);
RenderSurfaceImpl* render_surface =
- host_impl.active_tree()->root_layer_for_testing()->GetRenderSurface();
+ GetRenderSurface(host_impl.active_tree()->root_layer_for_testing());
ASSERT_TRUE(render_surface);
// Currently, the content_rect, clip_rect, and
@@ -86,7 +87,6 @@ TEST(RenderSurfaceTest, VerifySurfaceChangesAreTrackedProperly) {
render_surface->SetDrawOpacity(0.5f));
EXECUTE_AND_VERIFY_SURFACE_DID_NOT_CHANGE(
render_surface->SetDrawTransform(dummy_matrix));
- EXECUTE_AND_VERIFY_SURFACE_DID_NOT_CHANGE(render_surface->ClearLayerLists());
}
TEST(RenderSurfaceTest, SanityCheckSurfaceCreatesCorrectSharedQuadState) {
@@ -114,9 +114,9 @@ TEST(RenderSurfaceTest, SanityCheckSurfaceCreatesCorrectSharedQuadState) {
host_impl.active_tree()->UpdateDrawProperties(false /* update_lcd_text */);
ASSERT_TRUE(
- host_impl.active_tree()->LayerById(owning_layer_id)->GetRenderSurface());
+ GetRenderSurface(host_impl.active_tree()->LayerById(owning_layer_id)));
RenderSurfaceImpl* render_surface =
- host_impl.active_tree()->LayerById(owning_layer_id)->GetRenderSurface();
+ GetRenderSurface(host_impl.active_tree()->LayerById(owning_layer_id));
gfx::Rect content_rect(0, 0, 50, 50);
gfx::Rect clip_rect(5, 5, 40, 40);
@@ -172,9 +172,9 @@ TEST(RenderSurfaceTest, SanityCheckSurfaceCreatesCorrectRenderPass) {
host_impl.active_tree()->UpdateDrawProperties(false /* update_lcd_text */);
ASSERT_TRUE(
- host_impl.active_tree()->LayerById(owning_layer_id)->GetRenderSurface());
+ GetRenderSurface(host_impl.active_tree()->LayerById(owning_layer_id)));
RenderSurfaceImpl* render_surface =
- host_impl.active_tree()->LayerById(owning_layer_id)->GetRenderSurface();
+ GetRenderSurface(host_impl.active_tree()->LayerById(owning_layer_id));
gfx::Rect content_rect(0, 0, 50, 50);
gfx::Transform origin;
diff --git a/chromium/cc/layers/scrollbar_layer_impl_base.cc b/chromium/cc/layers/scrollbar_layer_impl_base.cc
index da53036fea0..681a0401f42 100644
--- a/chromium/cc/layers/scrollbar_layer_impl_base.cc
+++ b/chromium/cc/layers/scrollbar_layer_impl_base.cc
@@ -18,7 +18,6 @@ ScrollbarLayerImplBase::ScrollbarLayerImplBase(
bool is_left_side_vertical_scrollbar,
bool is_overlay)
: LayerImpl(tree_impl, id),
- scroll_layer_id_(Layer::INVALID_ID),
is_overlay_scrollbar_(is_overlay),
thumb_thickness_scale_factor_(1.f),
current_pos_(0.f),
@@ -36,21 +35,19 @@ void ScrollbarLayerImplBase::PushPropertiesTo(LayerImpl* layer) {
LayerImpl::PushPropertiesTo(layer);
DCHECK(layer->ToScrollbarLayer());
layer->ToScrollbarLayer()->set_is_overlay_scrollbar(is_overlay_scrollbar_);
- layer->ToScrollbarLayer()->SetScrollLayerId(ScrollLayerId());
+ layer->ToScrollbarLayer()->SetScrollElementId(scroll_element_id());
}
ScrollbarLayerImplBase* ScrollbarLayerImplBase::ToScrollbarLayer() {
return this;
}
-void ScrollbarLayerImplBase::SetScrollLayerId(int scroll_layer_id) {
- if (scroll_layer_id_ == scroll_layer_id)
+void ScrollbarLayerImplBase::SetScrollElementId(ElementId scroll_element_id) {
+ if (scroll_element_id_ == scroll_element_id)
return;
layer_tree_impl()->UnregisterScrollbar(this);
-
- scroll_layer_id_ = scroll_layer_id;
-
+ scroll_element_id_ = scroll_element_id;
layer_tree_impl()->RegisterScrollbar(this);
}
@@ -63,10 +60,18 @@ bool ScrollbarLayerImplBase::SetCurrentPos(float current_pos) {
}
bool ScrollbarLayerImplBase::CanScrollOrientation() const {
- LayerImpl* scroll_layer = layer_tree_impl()->LayerById(scroll_layer_id_);
+ // TODO(pdr): Refactor this to not depend on layers by using the associated
+ // scroll node's user_scrollable values.
+ LayerImpl* scroll_layer =
+ layer_tree_impl()->LayerByElementId(scroll_element_id_);
if (!scroll_layer)
return false;
+
return scroll_layer->user_scrollable(orientation()) &&
+ // Ensure clip_layer_length_ smaller than scroll_layer_length_ not
+ // caused by floating error.
+ !MathUtil::IsFloatNearlyTheSame(clip_layer_length_,
+ scroll_layer_length_) &&
clip_layer_length_ < scroll_layer_length_;
}
@@ -102,7 +107,8 @@ bool ScrollbarLayerImplBase::SetThumbThicknessScaleFactor(float factor) {
return true;
}
-gfx::Rect ScrollbarLayerImplBase::ComputeThumbQuadRect() const {
+gfx::Rect ScrollbarLayerImplBase::ComputeThumbQuadRectWithThumbThicknessScale(
+ float thumb_thickness_scale_factor) const {
// Thumb extent is the length of the thumb in the scrolling direction, thumb
// thickness is in the perpendicular direction. Here's an example of a
// horizontal scrollbar - inputs are above the scrollbar, computed values
@@ -180,7 +186,7 @@ gfx::Rect ScrollbarLayerImplBase::ComputeThumbQuadRect() const {
}
float thumb_thickness_adjustment =
- thumb_thickness * (1.f - thumb_thickness_scale_factor_);
+ thumb_thickness * (1.f - thumb_thickness_scale_factor);
gfx::RectF thumb_rect;
if (orientation_ == HORIZONTAL) {
@@ -201,6 +207,16 @@ gfx::Rect ScrollbarLayerImplBase::ComputeThumbQuadRect() const {
return gfx::ToEnclosingRect(thumb_rect);
}
+gfx::Rect ScrollbarLayerImplBase::ComputeExpandedThumbQuadRect() const {
+ DCHECK(is_overlay_scrollbar());
+ return ComputeThumbQuadRectWithThumbThicknessScale(1.f);
+}
+
+gfx::Rect ScrollbarLayerImplBase::ComputeThumbQuadRect() const {
+ return ComputeThumbQuadRectWithThumbThicknessScale(
+ thumb_thickness_scale_factor_);
+}
+
void ScrollbarLayerImplBase::SetOverlayScrollbarLayerOpacityAnimated(
float opacity) {
DCHECK(is_overlay_scrollbar());
@@ -208,23 +224,11 @@ void ScrollbarLayerImplBase::SetOverlayScrollbarLayerOpacityAnimated(
return;
PropertyTrees* property_trees = layer_tree_impl()->property_trees();
- int effect_node_index =
- property_trees->effect_tree.FindNodeIndexFromOwningLayerId(id());
- // If this method is called during LayerImpl::PushPropertiesTo, we may not yet
- // have valid owning_layer_id_to_node_index entries in effect tree as property
- // trees are pushed after layers during activation. We can skip updating
- // opacity in that case as we are only registering a scrollbar and because
- // opacity will be overwritten anyway when property trees are pushed.
- if (effect_node_index == EffectTree::kInvalidNodeId ||
- effect_node_index != effect_tree_index())
- return;
EffectNode* node = property_trees->effect_tree.Node(effect_tree_index());
if (node->opacity == opacity)
return;
- layer_tree_impl()->AddToOpacityAnimationsMap(id(), opacity);
-
node->opacity = opacity;
node->effect_changed = true;
property_trees->changed = true;
@@ -232,4 +236,9 @@ void ScrollbarLayerImplBase::SetOverlayScrollbarLayerOpacityAnimated(
layer_tree_impl()->set_needs_update_draw_properties();
}
+LayerTreeSettings::ScrollbarAnimator
+ScrollbarLayerImplBase::GetScrollbarAnimator() const {
+ return layer_tree_impl()->settings().scrollbar_animator;
+}
+
} // namespace cc
diff --git a/chromium/cc/layers/scrollbar_layer_impl_base.h b/chromium/cc/layers/scrollbar_layer_impl_base.h
index 0b9b403950b..e6bb9b4e482 100644
--- a/chromium/cc/layers/scrollbar_layer_impl_base.h
+++ b/chromium/cc/layers/scrollbar_layer_impl_base.h
@@ -5,11 +5,13 @@
#ifndef CC_LAYERS_SCROLLBAR_LAYER_IMPL_BASE_H_
#define CC_LAYERS_SCROLLBAR_LAYER_IMPL_BASE_H_
+#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "cc/cc_export.h"
#include "cc/input/scrollbar.h"
#include "cc/layers/layer.h"
#include "cc/layers/layer_impl.h"
+#include "cc/trees/layer_tree_settings.h"
namespace cc {
@@ -17,9 +19,8 @@ class LayerTreeImpl;
class CC_EXPORT ScrollbarLayerImplBase : public LayerImpl {
public:
- int ScrollLayerId() const { return scroll_layer_id_; }
-
- void SetScrollLayerId(int scroll_layer_id);
+ ElementId scroll_element_id() const { return scroll_element_id_; }
+ void SetScrollElementId(ElementId scroll_element_id);
float current_pos() const { return current_pos_; }
bool SetCurrentPos(float current_pos);
@@ -47,7 +48,8 @@ class CC_EXPORT ScrollbarLayerImplBase : public LayerImpl {
ScrollbarLayerImplBase* ToScrollbarLayer() override;
// Thumb quad rect in layer space.
- virtual gfx::Rect ComputeThumbQuadRect() const;
+ gfx::Rect ComputeThumbQuadRect() const;
+ gfx::Rect ComputeExpandedThumbQuadRect() const;
float thumb_thickness_scale_factor() {
return thumb_thickness_scale_factor_;
@@ -60,6 +62,8 @@ class CC_EXPORT ScrollbarLayerImplBase : public LayerImpl {
// on overlay scrollbar layers.
void SetOverlayScrollbarLayerOpacityAnimated(float opacity);
+ virtual LayerTreeSettings::ScrollbarAnimator GetScrollbarAnimator() const;
+
protected:
ScrollbarLayerImplBase(LayerTreeImpl* tree_impl,
int id,
@@ -76,7 +80,10 @@ class CC_EXPORT ScrollbarLayerImplBase : public LayerImpl {
virtual bool IsThumbResizable() const = 0;
private:
- int scroll_layer_id_;
+ gfx::Rect ComputeThumbQuadRectWithThumbThicknessScale(
+ float thumb_thickness_scale_factor) const;
+
+ ElementId scroll_element_id_;
bool is_overlay_scrollbar_;
float thumb_thickness_scale_factor_;
@@ -93,7 +100,7 @@ class CC_EXPORT ScrollbarLayerImplBase : public LayerImpl {
DISALLOW_COPY_AND_ASSIGN(ScrollbarLayerImplBase);
};
-typedef std::set<ScrollbarLayerImplBase*> ScrollbarSet;
+using ScrollbarSet = base::flat_set<ScrollbarLayerImplBase*>;
} // namespace cc
diff --git a/chromium/cc/layers/scrollbar_layer_interface.h b/chromium/cc/layers/scrollbar_layer_interface.h
index 30c335ba011..7839c8e68cb 100644
--- a/chromium/cc/layers/scrollbar_layer_interface.h
+++ b/chromium/cc/layers/scrollbar_layer_interface.h
@@ -13,8 +13,8 @@ namespace cc {
class CC_EXPORT ScrollbarLayerInterface {
public:
- virtual int ScrollLayerId() const = 0;
- virtual void SetScrollLayer(int layer_id) = 0;
+ virtual ElementId scroll_element_id() const = 0;
+ virtual void SetScrollElementId(ElementId element_id) = 0;
virtual ScrollbarOrientation orientation() const = 0;
diff --git a/chromium/cc/layers/scrollbar_layer_unittest.cc b/chromium/cc/layers/scrollbar_layer_unittest.cc
index 3e6e56ec142..ff5d38a5f55 100644
--- a/chromium/cc/layers/scrollbar_layer_unittest.cc
+++ b/chromium/cc/layers/scrollbar_layer_unittest.cc
@@ -26,6 +26,7 @@
#include "cc/test/fake_painted_scrollbar_layer.h"
#include "cc/test/fake_scrollbar.h"
#include "cc/test/geometry_test_utils.h"
+#include "cc/test/layer_test_common.h"
#include "cc/test/layer_tree_test.h"
#include "cc/test/mock_occlusion_tracker.h"
#include "cc/test/stub_layer_tree_host_single_thread_client.h"
@@ -150,10 +151,10 @@ class ScrollbarLayerTest : public testing::Test {
const bool kIsLeftSideVerticalScrollbar = false;
child2 = SolidColorScrollbarLayer::Create(
scrollbar->Orientation(), thumb_thickness, track_start,
- kIsLeftSideVerticalScrollbar, child1->id());
+ kIsLeftSideVerticalScrollbar, child1->element_id());
} else {
- child2 =
- PaintedScrollbarLayer::Create(std::move(scrollbar), child1->id());
+ child2 = PaintedScrollbarLayer::Create(std::move(scrollbar),
+ child1->element_id());
}
layer_tree_root->AddChild(child1);
layer_tree_root->InsertChild(child2, reverse_order ? 0 : 1);
@@ -197,7 +198,7 @@ TEST_F(ScrollbarLayerTest, RepaintOverlayWhenResourceDisposed) {
FakePaintedOverlayScrollbar* fake_scrollbar = scrollbar.get();
scoped_refptr<PaintedOverlayScrollbarLayer> scrollbar_layer =
PaintedOverlayScrollbarLayer::Create(std::move(scrollbar),
- layer_tree_root->id());
+ layer_tree_root->element_id());
// Setup.
{
@@ -209,7 +210,6 @@ TEST_F(ScrollbarLayerTest, RepaintOverlayWhenResourceDisposed) {
layer_tree_root->SetBounds(gfx::Size(100, 200));
content_layer->SetBounds(gfx::Size(100, 200));
scrollbar_layer->set_visible_layer_rect(gfx::Rect(0, 0, 100, 200));
- scrollbar_layer->SavePaintProperties();
}
// First call to update should create a resource. The scrollbar itself thinks
@@ -290,9 +290,10 @@ TEST_F(ScrollbarLayerTest, ScrollOffsetSynchronization) {
std::unique_ptr<Scrollbar> scrollbar(new FakeScrollbar);
scoped_refptr<Layer> layer_tree_root = Layer::Create();
scoped_refptr<Layer> scroll_layer = Layer::Create();
+ scroll_layer->SetElementId(LayerIdToElementIdForTesting(scroll_layer->id()));
scoped_refptr<Layer> content_layer = Layer::Create();
- scoped_refptr<Layer> scrollbar_layer =
- PaintedScrollbarLayer::Create(std::move(scrollbar), scroll_layer->id());
+ scoped_refptr<Layer> scrollbar_layer = PaintedScrollbarLayer::Create(
+ std::move(scrollbar), scroll_layer->element_id());
// Choose bounds to give max_scroll_offset = (30, 50).
layer_tree_root->SetBounds(gfx::Size(70, 150));
@@ -306,8 +307,6 @@ TEST_F(ScrollbarLayerTest, ScrollOffsetSynchronization) {
scroll_layer->AddChild(content_layer);
layer_tree_root->AddChild(scrollbar_layer);
- layer_tree_root->SavePaintProperties();
- content_layer->SavePaintProperties();
layer_tree_host_->UpdateLayers();
LayerImpl* layer_impl_tree_root =
layer_tree_host_->CommitAndCreateLayerImplTree();
@@ -322,12 +321,9 @@ TEST_F(ScrollbarLayerTest, ScrollOffsetSynchronization) {
cc_scrollbar_layer->clip_layer_length());
layer_tree_root->SetBounds(gfx::Size(700, 1500));
- layer_tree_root->SavePaintProperties();
scroll_layer->SetBounds(gfx::Size(1000, 2000));
scroll_layer->SetScrollOffset(gfx::ScrollOffset(100, 200));
- scroll_layer->SavePaintProperties();
content_layer->SetBounds(gfx::Size(1000, 2000));
- content_layer->SavePaintProperties();
layer_tree_host_->UpdateLayers();
layer_impl_tree_root = layer_tree_host_->CommitAndCreateLayerImplTree();
@@ -360,7 +356,7 @@ TEST_F(ScrollbarLayerTest, UpdatePropertiesOfScrollBarWhenThumbRemoved) {
scoped_refptr<Layer> root_layer = Layer::Create();
scoped_refptr<Layer> content_layer = Layer::Create();
scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer =
- FakePaintedScrollbarLayer::Create(false, true, root_layer->id());
+ FakePaintedScrollbarLayer::Create(false, true, root_layer->element_id());
root_layer->SetScrollClipLayerId(root_clip_layer->id());
// Give the root-clip a size that will result in MaxScrollOffset = (80, 0).
@@ -375,7 +371,7 @@ TEST_F(ScrollbarLayerTest, UpdatePropertiesOfScrollBarWhenThumbRemoved) {
root_layer->SetScrollOffset(gfx::ScrollOffset(0, 0));
scrollbar_layer->SetBounds(gfx::Size(70, 10));
- scrollbar_layer->SetScrollLayer(root_layer->id());
+ scrollbar_layer->SetScrollElementId(root_layer->element_id());
scrollbar_layer->fake_scrollbar()->set_location(gfx::Point(20, 10));
scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10));
scrollbar_layer->fake_scrollbar()->set_thumb_thickness(10);
@@ -383,6 +379,7 @@ TEST_F(ScrollbarLayerTest, UpdatePropertiesOfScrollBarWhenThumbRemoved) {
LayerImpl* root_clip_layer_impl = nullptr;
PaintedScrollbarLayerImpl* scrollbar_layer_impl = nullptr;
+ layer_tree_host_->BuildPropertyTreesForTesting();
UPDATE_AND_EXTRACT_LAYER_POINTERS();
EXPECT_EQ(gfx::Rect(10, 0, 4, 10).ToString(),
scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
@@ -399,8 +396,9 @@ TEST_F(ScrollbarLayerTest, ThumbRect) {
scoped_refptr<Layer> root_layer = Layer::Create();
scoped_refptr<Layer> content_layer = Layer::Create();
scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer =
- FakePaintedScrollbarLayer::Create(false, true, root_layer->id());
+ FakePaintedScrollbarLayer::Create(false, true, root_layer->element_id());
+ root_layer->SetElementId(LayerIdToElementIdForTesting(root_layer->id()));
root_layer->SetScrollClipLayerId(root_clip_layer->id());
// Give the root-clip a size that will result in MaxScrollOffset = (80, 0).
root_clip_layer->SetBounds(gfx::Size(20, 50));
@@ -414,7 +412,7 @@ TEST_F(ScrollbarLayerTest, ThumbRect) {
root_layer->SetScrollOffset(gfx::ScrollOffset(0, 0));
scrollbar_layer->SetBounds(gfx::Size(70, 10));
- scrollbar_layer->SetScrollLayer(root_layer->id());
+ scrollbar_layer->SetScrollElementId(root_layer->element_id());
scrollbar_layer->fake_scrollbar()->set_location(gfx::Point(20, 10));
scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10));
scrollbar_layer->fake_scrollbar()->set_thumb_thickness(10);
@@ -439,6 +437,7 @@ TEST_F(ScrollbarLayerTest, ThumbRect) {
// Over-scroll (thumb position should clamp on the far side).
root_layer->SetScrollOffset(gfx::ScrollOffset(85, 0));
+ layer_tree_host_->UpdateLayers();
UPDATE_AND_EXTRACT_LAYER_POINTERS();
EXPECT_EQ(gfx::Rect(56, 0, 4, 10).ToString(),
@@ -477,7 +476,7 @@ TEST_F(ScrollbarLayerTest, ThumbRectForOverlayLeftSideVerticalScrollbar) {
// Create an overlay left side vertical scrollbar.
scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer =
FakePaintedScrollbarLayer::Create(false, true, VERTICAL, true, true,
- root_layer->id());
+ root_layer->element_id());
root_layer->SetScrollClipLayerId(root_clip_layer->id());
root_clip_layer->SetBounds(gfx::Size(50, 20));
root_layer->SetBounds(gfx::Size(50, 100));
@@ -488,7 +487,7 @@ TEST_F(ScrollbarLayerTest, ThumbRectForOverlayLeftSideVerticalScrollbar) {
root_layer->SetScrollOffset(gfx::ScrollOffset(0, 0));
scrollbar_layer->SetBounds(gfx::Size(10, 20));
- scrollbar_layer->SetScrollLayer(root_layer->id());
+ scrollbar_layer->SetScrollElementId(root_layer->element_id());
scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(0, 0, 10, 20));
scrollbar_layer->fake_scrollbar()->set_thumb_thickness(10);
scrollbar_layer->fake_scrollbar()->set_thumb_length(4);
@@ -591,13 +590,14 @@ TEST_F(ScrollbarLayerTest, LayerDrivenSolidColorDrawQuads) {
scoped_refptr<Layer> layer_tree_root = Layer::Create();
scoped_refptr<Layer> scroll_layer = Layer::Create();
+ scroll_layer->SetElementId(LayerIdToElementIdForTesting(scroll_layer->id()));
scroll_layer->SetScrollClipLayerId(layer_tree_root->id());
scoped_refptr<Layer> child1 = Layer::Create();
scoped_refptr<Layer> child2;
const bool kIsLeftSideVerticalScrollbar = false;
child2 = SolidColorScrollbarLayer::Create(
scrollbar->Orientation(), kThumbThickness, kTrackStart,
- kIsLeftSideVerticalScrollbar, scroll_layer->id());
+ kIsLeftSideVerticalScrollbar, scroll_layer->element_id());
scroll_layer->AddChild(child1);
scroll_layer->InsertChild(child2, 1);
layer_tree_root->AddChild(scroll_layer);
@@ -644,16 +644,19 @@ TEST_F(ScrollbarLayerTest, ScrollbarLayerOpacity) {
scoped_refptr<Layer> layer_tree_root = Layer::Create();
scoped_refptr<Layer> scroll_layer = Layer::Create();
scroll_layer->SetScrollClipLayerId(layer_tree_root->id());
+ scroll_layer->SetElementId(ElementId(200));
scoped_refptr<Layer> child1 = Layer::Create();
- scoped_refptr<Layer> scrollbar_layer;
+ scoped_refptr<SolidColorScrollbarLayer> scrollbar_layer;
const bool kIsLeftSideVerticalScrollbar = false;
scrollbar_layer = SolidColorScrollbarLayer::Create(
scrollbar->Orientation(), kThumbThickness, kTrackStart,
- kIsLeftSideVerticalScrollbar, scroll_layer->id());
+ kIsLeftSideVerticalScrollbar, scroll_layer->element_id());
+ scrollbar_layer->SetElementId(ElementId(300));
scroll_layer->AddChild(child1);
scroll_layer->InsertChild(scrollbar_layer, 1);
layer_tree_root->AddChild(scroll_layer);
layer_tree_host_->SetRootLayer(layer_tree_root);
+ scrollbar_layer->SetScrollElementId(scroll_layer->element_id());
// Choose layer bounds to give max_scroll_offset = (8, 8).
layer_tree_root->SetBounds(gfx::Size(2, 2));
@@ -662,14 +665,8 @@ TEST_F(ScrollbarLayerTest, ScrollbarLayerOpacity) {
// Building property trees twice shouldn't change the size of
// PropertyTrees::always_use_active_tree_opacity_effect_ids.
layer_tree_host_->BuildPropertyTreesForTesting();
- EXPECT_EQ(layer_tree_host_->property_trees()
- ->always_use_active_tree_opacity_effect_ids.size(),
- 1u);
layer_tree_host_->property_trees()->needs_rebuild = true;
layer_tree_host_->BuildPropertyTreesForTesting();
- EXPECT_EQ(layer_tree_host_->property_trees()
- ->always_use_active_tree_opacity_effect_ids.size(),
- 1u);
// A solid color scrollbar layer's opacity is initialized to 0 on main thread
layer_tree_host_->UpdateLayers();
@@ -724,14 +721,14 @@ TEST_F(ScrollbarLayerTest, ScrollbarLayerPushProperties) {
scoped_refptr<Layer> layer_tree_root = Layer::Create();
scoped_refptr<Layer> scroll_layer = Layer::Create();
+ scroll_layer->SetElementId(LayerIdToElementIdForTesting(scroll_layer->id()));
scroll_layer->SetScrollClipLayerId(layer_tree_root->id());
scoped_refptr<Layer> child1 = Layer::Create();
scoped_refptr<Layer> scrollbar_layer;
const bool kIsLeftSideVerticalScrollbar = false;
scrollbar_layer = SolidColorScrollbarLayer::Create(
scrollbar->Orientation(), kThumbThickness, kTrackStart,
- kIsLeftSideVerticalScrollbar, scroll_layer->id());
- scroll_layer->SetScrollClipLayerId(layer_tree_root->id());
+ kIsLeftSideVerticalScrollbar, scroll_layer->element_id());
scroll_layer->AddChild(child1);
scroll_layer->InsertChild(scrollbar_layer, 1);
layer_tree_root->AddChild(scroll_layer);
@@ -740,11 +737,15 @@ TEST_F(ScrollbarLayerTest, ScrollbarLayerPushProperties) {
layer_tree_root->SetBounds(gfx::Size(2, 2));
scroll_layer->SetBounds(gfx::Size(10, 10));
layer_tree_host_->UpdateLayers();
- layer_tree_host_->CommitAndCreateLayerImplTree();
LayerTreeHostImpl* host_impl = layer_tree_host_->host_impl();
- EXPECT_TRUE(host_impl->ScrollbarAnimationControllerForId(scroll_layer->id()));
+ host_impl->CreatePendingTree();
+ layer_tree_host_->CommitAndCreatePendingTree();
+ host_impl->ActivateSyncTree();
+ EXPECT_TRUE(host_impl->ScrollbarAnimationControllerForElementId(
+ scroll_layer->element_id()));
scroll_layer->SetBounds(gfx::Size(20, 20));
+ scroll_layer->ShowScrollbars();
scroll_layer->SetForceRenderSurfaceForTesting(true);
layer_tree_host_->UpdateLayers();
host_impl->CreatePendingTree();
@@ -756,6 +757,44 @@ TEST_F(ScrollbarLayerTest, ScrollbarLayerPushProperties) {
EXPECT_EQ(node->opacity, 1.f);
}
+TEST_F(ScrollbarLayerTest, SubPixelCanScrollOrientation) {
+ gfx::Size viewport_size(980, 980);
+
+ LayerTestCommon::LayerImplTest impl;
+
+ LayerImpl* clip_layer = impl.AddChildToRoot<LayerImpl>();
+ LayerImpl* scroll_layer = impl.AddChild<LayerImpl>(clip_layer);
+
+ scroll_layer->SetScrollClipLayer(clip_layer->id());
+ scroll_layer->SetElementId(LayerIdToElementIdForTesting(scroll_layer->id()));
+
+ const int kTrackStart = 0;
+ const int kThumbThickness = 10;
+ const bool kIsLeftSideVerticalScrollbar = false;
+ const bool kIsOverlayScrollbar = false;
+
+ SolidColorScrollbarLayerImpl* scrollbar_layer =
+ impl.AddChild<SolidColorScrollbarLayerImpl>(
+ scroll_layer, HORIZONTAL, kThumbThickness, kTrackStart,
+ kIsLeftSideVerticalScrollbar, kIsOverlayScrollbar);
+
+ scrollbar_layer->SetScrollElementId(scroll_layer->element_id());
+ clip_layer->SetBounds(gfx::Size(980, 980));
+ scroll_layer->SetBounds(gfx::Size(980, 980));
+
+ impl.CalcDrawProps(viewport_size);
+
+ // Fake clip layer length to scrollbar to mock rounding error.
+ scrollbar_layer->SetClipLayerLength(979.999939f);
+
+ EXPECT_FALSE(scrollbar_layer->CanScrollOrientation());
+
+ // Fake clip layer length to scrollable.
+ scrollbar_layer->SetClipLayerLength(979.0f);
+
+ EXPECT_TRUE(scrollbar_layer->CanScrollOrientation());
+}
+
class ScrollbarLayerSolidColorThumbTest : public testing::Test {
public:
ScrollbarLayerSolidColorThumbTest() {
@@ -868,6 +907,7 @@ class ScrollbarLayerTestResourceCreationAndRelease : public ScrollbarLayerTest {
int expected_deleted,
bool use_solid_color_scrollbar) {
std::unique_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, false));
+ scoped_refptr<Layer> root_clip_layer = Layer::Create();
scoped_refptr<Layer> layer_tree_root = Layer::Create();
scoped_refptr<Layer> content_layer = Layer::Create();
scoped_refptr<Layer> scrollbar_layer;
@@ -877,10 +917,10 @@ class ScrollbarLayerTestResourceCreationAndRelease : public ScrollbarLayerTest {
const bool kIsLeftSideVerticalScrollbar = false;
scrollbar_layer = SolidColorScrollbarLayer::Create(
scrollbar->Orientation(), kThumbThickness, kTrackStart,
- kIsLeftSideVerticalScrollbar, layer_tree_root->id());
+ kIsLeftSideVerticalScrollbar, layer_tree_root->element_id());
} else {
- scrollbar_layer = PaintedScrollbarLayer::Create(std::move(scrollbar),
- layer_tree_root->id());
+ scrollbar_layer = PaintedScrollbarLayer::Create(
+ std::move(scrollbar), layer_tree_root->element_id());
}
layer_tree_root->AddChild(content_layer);
layer_tree_root->AddChild(scrollbar_layer);
@@ -889,6 +929,7 @@ class ScrollbarLayerTestResourceCreationAndRelease : public ScrollbarLayerTest {
scrollbar_layer->SetIsDrawable(true);
scrollbar_layer->SetBounds(gfx::Size(100, 100));
+ layer_tree_root->SetScrollClipLayerId(root_clip_layer->id());
layer_tree_root->SetScrollOffset(gfx::ScrollOffset(10, 20));
layer_tree_root->SetBounds(gfx::Size(100, 200));
content_layer->SetBounds(gfx::Size(100, 200));
@@ -898,7 +939,6 @@ class ScrollbarLayerTestResourceCreationAndRelease : public ScrollbarLayerTest {
EXPECT_EQ(scrollbar_layer->GetLayerTreeHostForTesting(),
layer_tree_host_.get());
- scrollbar_layer->SavePaintProperties();
for (int update_counter = 0; update_counter < num_updates; update_counter++)
scrollbar_layer->Update();
@@ -939,7 +979,8 @@ TEST_F(ScrollbarLayerTestResourceCreationAndRelease, TestResourceUpdate) {
scoped_refptr<Layer> layer_tree_root = Layer::Create();
scoped_refptr<Layer> content_layer = Layer::Create();
scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer =
- FakePaintedScrollbarLayer::Create(false, true, layer_tree_root->id());
+ FakePaintedScrollbarLayer::Create(false, true,
+ layer_tree_root->element_id());
layer_tree_root->AddChild(content_layer);
layer_tree_root->AddChild(scrollbar_layer);
@@ -959,7 +1000,6 @@ TEST_F(ScrollbarLayerTestResourceCreationAndRelease, TestResourceUpdate) {
size_t resource_count;
int expected_created, expected_deleted;
- scrollbar_layer->SavePaintProperties();
resource_count = 2;
expected_created = 2;
@@ -1099,7 +1139,8 @@ class ScaledScrollbarLayerTestResourceCreation : public ScrollbarLayerTest {
scoped_refptr<Layer> layer_tree_root = Layer::Create();
scoped_refptr<Layer> content_layer = Layer::Create();
scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer =
- FakePaintedScrollbarLayer::Create(false, true, layer_tree_root->id());
+ FakePaintedScrollbarLayer::Create(false, true,
+ layer_tree_root->element_id());
layer_tree_root->AddChild(content_layer);
layer_tree_root->AddChild(scrollbar_layer);
@@ -1119,7 +1160,6 @@ class ScaledScrollbarLayerTestResourceCreation : public ScrollbarLayerTest {
layer_tree_host_->SetDeviceScaleFactor(test_scale);
- scrollbar_layer->SavePaintProperties();
scrollbar_layer->Update();
// Verify that we have not generated any content uploads that are larger
@@ -1169,7 +1209,7 @@ class ScaledScrollbarLayerTestScaledRasterization : public ScrollbarLayerTest {
scoped_refptr<Layer> layer_tree_root = Layer::Create();
scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer =
FakePaintedScrollbarLayer::Create(paint_during_update, has_thumb,
- layer_tree_root->id());
+ layer_tree_root->element_id());
layer_tree_root->AddChild(scrollbar_layer);
@@ -1184,7 +1224,6 @@ class ScaledScrollbarLayerTestScaledRasterization : public ScrollbarLayerTest {
layer_tree_host_->SetDeviceScaleFactor(test_scale);
gfx::Rect screen_space_clip_rect;
- scrollbar_layer->SavePaintProperties();
scrollbar_layer->Update();
@@ -1193,10 +1232,8 @@ class ScaledScrollbarLayerTestScaledRasterization : public ScrollbarLayerTest {
DCHECK(bitmap);
- AutoLockUIResourceBitmap locked_bitmap(*bitmap);
-
const SkColor* pixels =
- reinterpret_cast<const SkColor*>(locked_bitmap.GetPixels());
+ reinterpret_cast<const SkColor*>(bitmap->GetPixels());
SkColor color = argb_to_skia(
scrollbar_layer->fake_scrollbar()->paint_fill_color());
int width = bitmap->GetSize().width();
diff --git a/chromium/cc/layers/solid_color_scrollbar_layer.cc b/chromium/cc/layers/solid_color_scrollbar_layer.cc
index 2eb5484c855..926f4efee38 100644
--- a/chromium/cc/layers/solid_color_scrollbar_layer.cc
+++ b/chromium/cc/layers/solid_color_scrollbar_layer.cc
@@ -27,10 +27,10 @@ scoped_refptr<SolidColorScrollbarLayer> SolidColorScrollbarLayer::Create(
int thumb_thickness,
int track_start,
bool is_left_side_vertical_scrollbar,
- int scroll_layer_id) {
+ ElementId scroll_element_id) {
return make_scoped_refptr(new SolidColorScrollbarLayer(
orientation, thumb_thickness, track_start,
- is_left_side_vertical_scrollbar, scroll_layer_id));
+ is_left_side_vertical_scrollbar, scroll_element_id));
}
SolidColorScrollbarLayer::SolidColorScrollbarLayerInputs::
@@ -38,8 +38,8 @@ SolidColorScrollbarLayer::SolidColorScrollbarLayerInputs::
int thumb_thickness,
int track_start,
bool is_left_side_vertical_scrollbar,
- int scroll_layer_id)
- : scroll_layer_id(scroll_layer_id),
+ ElementId scroll_element_id)
+ : scroll_element_id(scroll_element_id),
orientation(orientation),
thumb_thickness(thumb_thickness),
track_start(track_start),
@@ -53,12 +53,12 @@ SolidColorScrollbarLayer::SolidColorScrollbarLayer(
int thumb_thickness,
int track_start,
bool is_left_side_vertical_scrollbar,
- int scroll_layer_id)
+ ElementId scroll_element_id)
: solid_color_scrollbar_layer_inputs_(orientation,
thumb_thickness,
track_start,
is_left_side_vertical_scrollbar,
- scroll_layer_id) {
+ scroll_element_id) {
Layer::SetOpacity(0.f);
}
@@ -79,8 +79,8 @@ void SolidColorScrollbarLayer::PushPropertiesTo(LayerImpl* layer) {
SolidColorScrollbarLayerImpl* scrollbar_layer =
static_cast<SolidColorScrollbarLayerImpl*>(layer);
- scrollbar_layer->SetScrollLayerId(
- solid_color_scrollbar_layer_inputs_.scroll_layer_id);
+ scrollbar_layer->SetScrollElementId(
+ solid_color_scrollbar_layer_inputs_.scroll_element_id);
}
void SolidColorScrollbarLayer::SetNeedsDisplayRect(const gfx::Rect& rect) {
@@ -91,19 +91,15 @@ bool SolidColorScrollbarLayer::OpacityCanAnimateOnImplThread() const {
return true;
}
-bool SolidColorScrollbarLayer::AlwaysUseActiveTreeOpacity() const {
- return true;
-}
-
-int SolidColorScrollbarLayer::ScrollLayerId() const {
- return solid_color_scrollbar_layer_inputs_.scroll_layer_id;
+ElementId SolidColorScrollbarLayer::scroll_element_id() const {
+ return solid_color_scrollbar_layer_inputs_.scroll_element_id;
}
-void SolidColorScrollbarLayer::SetScrollLayer(int layer_id) {
- if (layer_id == solid_color_scrollbar_layer_inputs_.scroll_layer_id)
+void SolidColorScrollbarLayer::SetScrollElementId(ElementId element_id) {
+ if (element_id == solid_color_scrollbar_layer_inputs_.scroll_element_id)
return;
- solid_color_scrollbar_layer_inputs_.scroll_layer_id = layer_id;
+ solid_color_scrollbar_layer_inputs_.scroll_element_id = element_id;
SetNeedsFullTreeSync();
}
diff --git a/chromium/cc/layers/solid_color_scrollbar_layer.h b/chromium/cc/layers/solid_color_scrollbar_layer.h
index 319674c22ad..c3994b38349 100644
--- a/chromium/cc/layers/solid_color_scrollbar_layer.h
+++ b/chromium/cc/layers/solid_color_scrollbar_layer.h
@@ -22,11 +22,10 @@ class CC_EXPORT SolidColorScrollbarLayer : public ScrollbarLayerInterface,
int thumb_thickness,
int track_start,
bool is_left_side_vertical_scrollbar,
- int scroll_layer_id);
+ ElementId scroll_element_id);
// Layer overrides.
bool OpacityCanAnimateOnImplThread() const override;
- bool AlwaysUseActiveTreeOpacity() const override;
ScrollbarLayerInterface* ToScrollbarLayer() override;
void SetOpacity(float opacity) override;
@@ -35,8 +34,8 @@ class CC_EXPORT SolidColorScrollbarLayer : public ScrollbarLayerInterface,
void SetNeedsDisplayRect(const gfx::Rect& rect) override;
// ScrollbarLayerInterface
- int ScrollLayerId() const override;
- void SetScrollLayer(int layer_id) override;
+ ElementId scroll_element_id() const override;
+ void SetScrollElementId(ElementId element_id) override;
ScrollbarOrientation orientation() const override;
@@ -57,7 +56,7 @@ class CC_EXPORT SolidColorScrollbarLayer : public ScrollbarLayerInterface,
int thumb_thickness,
int track_start,
bool is_left_side_vertical_scrollbar,
- int scroll_layer_id);
+ ElementId scroll_element_id);
~SolidColorScrollbarLayer() override;
private:
@@ -69,10 +68,10 @@ class CC_EXPORT SolidColorScrollbarLayer : public ScrollbarLayerInterface,
int thumb_thickness,
int track_start,
bool is_left_side_vertical_scrollbar,
- int scroll_layer_id);
+ ElementId scroll_element_id);
~SolidColorScrollbarLayerInputs();
- int scroll_layer_id;
+ ElementId scroll_element_id;
ScrollbarOrientation orientation;
int thumb_thickness;
int track_start;
diff --git a/chromium/cc/layers/surface_layer.cc b/chromium/cc/layers/surface_layer.cc
index 000832fe116..573f97b9b13 100644
--- a/chromium/cc/layers/surface_layer.cc
+++ b/chromium/cc/layers/surface_layer.cc
@@ -8,6 +8,7 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
+#include "base/single_thread_task_runner.h"
#include "base/trace_event/trace_event.h"
#include "cc/layers/surface_layer_impl.h"
#include "cc/output/swap_promise.h"
diff --git a/chromium/cc/layers/surface_layer_impl.cc b/chromium/cc/layers/surface_layer_impl.cc
index 7a1bfbd9795..e42bca07ed5 100644
--- a/chromium/cc/layers/surface_layer_impl.cc
+++ b/chromium/cc/layers/surface_layer_impl.cc
@@ -65,15 +65,28 @@ void SurfaceLayerImpl::PushPropertiesTo(LayerImpl* layer) {
void SurfaceLayerImpl::AppendQuads(RenderPass* render_pass,
AppendQuadsData* append_quads_data) {
AppendRainbowDebugBorder(render_pass);
- auto* primary = CreateSurfaceDrawQuad(
- render_pass, SurfaceDrawQuadType::PRIMARY, primary_surface_info_,
- &append_quads_data->embedded_surfaces);
+ SharedQuadState* common_shared_quad_state = nullptr;
+ auto* primary =
+ CreateSurfaceDrawQuad(render_pass, SurfaceDrawQuadType::PRIMARY,
+ primary_surface_info_, &common_shared_quad_state);
// Emitting a fallback SurfaceDrawQuad is unnecessary if the primary and
// fallback surface Ids match.
- if (primary && fallback_surface_info_.id() != primary_surface_info_.id()) {
+ bool needs_fallback =
+ fallback_surface_info_.is_valid() &&
+ (fallback_surface_info_.id() != primary_surface_info_.id());
+ if (primary && needs_fallback) {
+ // Add the primary surface ID as a dependency.
+ append_quads_data->activation_dependencies.push_back(
+ primary_surface_info_.id());
+ // We can use the same SharedQuadState as the primary SurfaceDrawQuad if
+ // we don't need a different transform on the fallback.
+ bool use_common_shared_quad_state =
+ !stretch_content_to_fill_bounds_ &&
+ primary_surface_info_.device_scale_factor() ==
+ fallback_surface_info_.device_scale_factor();
primary->fallback_quad = CreateSurfaceDrawQuad(
render_pass, SurfaceDrawQuadType::FALLBACK, fallback_surface_info_,
- nullptr /* embedded_surfaces */);
+ use_common_shared_quad_state ? &common_shared_quad_state : nullptr);
}
}
@@ -81,7 +94,7 @@ SurfaceDrawQuad* SurfaceLayerImpl::CreateSurfaceDrawQuad(
RenderPass* render_pass,
SurfaceDrawQuadType surface_draw_quad_type,
const SurfaceInfo& surface_info,
- std::vector<SurfaceId>* embedded_surfaces) {
+ SharedQuadState** common_shared_quad_state) {
if (!surface_info.is_valid())
return nullptr;
@@ -105,24 +118,31 @@ SurfaceDrawQuad* SurfaceLayerImpl::CreateSurfaceDrawQuad(
surface_info.device_scale_factor();
}
- visible_quad_rect = gfx::ScaleToEnclosedRect(
+ visible_quad_rect = gfx::ScaleToEnclosingRect(
visible_quad_rect, layer_to_content_scale_x, layer_to_content_scale_y);
visible_quad_rect = gfx::IntersectRects(quad_rect, visible_quad_rect);
if (visible_quad_rect.IsEmpty())
return nullptr;
+ // If a |common_shared_quad_state| is provided then use that. Otherwise,
+ // allocate a new SharedQuadState. Assign the new SharedQuadState to
+ // *|common_shared_quad_state| so that it may be reused by another emitted
+ // SurfaceDrawQuad.
SharedQuadState* shared_quad_state =
- render_pass->CreateAndAppendSharedQuadState();
- PopulateScaledSharedQuadState(shared_quad_state, layer_to_content_scale_x,
- layer_to_content_scale_y);
+ common_shared_quad_state ? *common_shared_quad_state : nullptr;
+ if (!shared_quad_state) {
+ shared_quad_state = render_pass->CreateAndAppendSharedQuadState();
+ PopulateScaledSharedQuadState(shared_quad_state, layer_to_content_scale_x,
+ layer_to_content_scale_y);
+ }
+ if (common_shared_quad_state)
+ *common_shared_quad_state = shared_quad_state;
SurfaceDrawQuad* surface_draw_quad =
render_pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
surface_draw_quad->SetNew(shared_quad_state, quad_rect, visible_quad_rect,
surface_info.id(), surface_draw_quad_type, nullptr);
- if (embedded_surfaces)
- embedded_surfaces->push_back(surface_info.id());
return surface_draw_quad;
}
diff --git a/chromium/cc/layers/surface_layer_impl.h b/chromium/cc/layers/surface_layer_impl.h
index 9b853df5253..3c518827799 100644
--- a/chromium/cc/layers/surface_layer_impl.h
+++ b/chromium/cc/layers/surface_layer_impl.h
@@ -30,6 +30,11 @@ class CC_EXPORT SurfaceLayerImpl : public LayerImpl {
return primary_surface_info_;
}
+ // A fallback Surface is a Surface that is already known to exist in the
+ // display compositor. If surface synchronization is enabled, the display
+ // compositor will use the fallback if the primary surface is unavailable
+ // at the time of surface aggregation. If surface synchronization is not
+ // enabled, then a fallback surface will not be specified.
void SetFallbackSurfaceInfo(const SurfaceInfo& surface_info);
const SurfaceInfo& fallback_surface_info() const {
return fallback_surface_info_;
@@ -51,7 +56,7 @@ class CC_EXPORT SurfaceLayerImpl : public LayerImpl {
RenderPass* render_pass,
SurfaceDrawQuadType surface_draw_quad_type,
const SurfaceInfo& surface_info,
- std::vector<SurfaceId>* embedded_surfaces);
+ SharedQuadState** common_shared_quad_state);
void GetDebugBorderProperties(SkColor* color, float* width) const override;
void AppendRainbowDebugBorder(RenderPass* render_pass);
diff --git a/chromium/cc/layers/surface_layer_impl_unittest.cc b/chromium/cc/layers/surface_layer_impl_unittest.cc
index 5c6f942a66f..8aa8f8fa64e 100644
--- a/chromium/cc/layers/surface_layer_impl_unittest.cc
+++ b/chromium/cc/layers/surface_layer_impl_unittest.cc
@@ -20,12 +20,12 @@ namespace {
static constexpr FrameSinkId kArbitraryFrameSinkId(1, 1);
TEST(SurfaceLayerImplTest, OcclusionWithDeviceScaleFactor) {
- float device_scale_factor = 1.25f;
+ float device_scale_factor = 1.33f;
- gfx::Size layer_size(1000, 1000);
+ gfx::Size layer_size(512, 512);
gfx::Size scaled_surface_size(
gfx::ScaleToCeiledSize(layer_size, device_scale_factor));
- gfx::Size viewport_size(1250, 1325);
+ gfx::Size viewport_size(681, 750);
const LocalSurfaceId kArbitraryLocalSurfaceId(
9, base::UnguessableToken::Create());
@@ -40,10 +40,10 @@ TEST(SurfaceLayerImplTest, OcclusionWithDeviceScaleFactor) {
surface_layer_impl->SetPrimarySurfaceInfo(
SurfaceInfo(surface_id, device_scale_factor, scaled_surface_size));
- LayerImplList layer_list;
+ RenderSurfaceList render_surface_list;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
impl.root_layer_for_testing(), viewport_size, device_scale_factor,
- &layer_list);
+ &render_surface_list);
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
{
@@ -67,7 +67,7 @@ TEST(SurfaceLayerImplTest, OcclusionWithDeviceScaleFactor) {
{
SCOPED_TRACE("Partial occlusion");
- gfx::Rect occluded(gfx::ScaleToEnclosingRect(gfx::Rect(200, 0, 800, 1000),
+ gfx::Rect occluded(gfx::ScaleToEnclosingRect(gfx::Rect(200, 0, 312, 512),
device_scale_factor));
impl.AppendQuadsWithOcclusion(surface_layer_impl, occluded);
@@ -80,7 +80,7 @@ TEST(SurfaceLayerImplTest, OcclusionWithDeviceScaleFactor) {
}
{
SCOPED_TRACE("No outside occlusion");
- gfx::Rect occluded(gfx::ScaleToEnclosingRect(gfx::Rect(0, 1000, 1250, 300),
+ gfx::Rect occluded(gfx::ScaleToEnclosingRect(gfx::Rect(0, 681, 681, 69),
device_scale_factor));
impl.AppendQuadsWithOcclusion(surface_layer_impl, occluded);
@@ -147,6 +147,8 @@ TEST(SurfaceLayerImplTest, SurfaceStretchedToLayerBounds) {
impl.AddChildToRoot<SurfaceLayerImpl>();
const LocalSurfaceId kArbitraryLocalSurfaceId(
9, base::UnguessableToken::Create());
+ const LocalSurfaceId kArbitraryLocalSurfaceId2(
+ 10, base::UnguessableToken::Create());
// Given condition: layer and surface have different size and different
// aspect ratios.
@@ -162,8 +164,11 @@ TEST(SurfaceLayerImplTest, SurfaceStretchedToLayerBounds) {
surface_layer_impl->SetBounds(layer_size);
surface_layer_impl->SetDrawsContent(true);
SurfaceId surface_id(kArbitraryFrameSinkId, kArbitraryLocalSurfaceId);
+ SurfaceId surface_id2(kArbitraryFrameSinkId, kArbitraryLocalSurfaceId2);
surface_layer_impl->SetPrimarySurfaceInfo(
SurfaceInfo(surface_id, surface_scale, surface_size));
+ surface_layer_impl->SetFallbackSurfaceInfo(
+ SurfaceInfo(surface_id2, surface_scale, surface_size));
surface_layer_impl->SetStretchContentToFillBounds(true);
impl.CalcDrawProps(viewport_size);
@@ -171,10 +176,10 @@ TEST(SurfaceLayerImplTest, SurfaceStretchedToLayerBounds) {
std::unique_ptr<RenderPass> render_pass = RenderPass::Create();
AppendQuadsData data;
surface_layer_impl->AppendQuads(render_pass.get(), &data);
- EXPECT_THAT(data.embedded_surfaces, UnorderedElementsAre(surface_id));
+ EXPECT_THAT(data.activation_dependencies, UnorderedElementsAre(surface_id));
const QuadList& quads = render_pass->quad_list;
- ASSERT_EQ(1u, quads.size());
+ ASSERT_EQ(2u, quads.size());
const SharedQuadState* shared_quad_state = quads.front()->shared_quad_state;
// We expect that the transform for the quad stretches the quad to cover the
@@ -224,6 +229,8 @@ TEST(SurfaceLayerImplTest, SurfaceLayerImplEmitsTwoDrawQuadsIfUniqueFallback) {
float surface_scale2 = 2.f;
gfx::Size surface_size2(400, 400);
SurfaceInfo fallback_surface_info(surface_id2, surface_scale2, surface_size2);
+ SurfaceInfo fallback_surface_info2(surface_id2, surface_scale1,
+ surface_size2);
gfx::Size layer_size(400, 100);
@@ -238,18 +245,37 @@ TEST(SurfaceLayerImplTest, SurfaceLayerImplEmitsTwoDrawQuadsIfUniqueFallback) {
impl.CalcDrawProps(viewport_size);
std::unique_ptr<RenderPass> render_pass = RenderPass::Create();
- AppendQuadsData data;
- surface_layer_impl->AppendQuads(render_pass.get(), &data);
- // The the primary SurfaceInfo will be added to embedded_surfaces.
- EXPECT_THAT(data.embedded_surfaces, UnorderedElementsAre(surface_id1));
+ {
+ AppendQuadsData data;
+ surface_layer_impl->AppendQuads(render_pass.get(), &data);
+ // The the primary SurfaceInfo will be added to activation_dependencies.
+ EXPECT_THAT(data.activation_dependencies,
+ UnorderedElementsAre(surface_id1));
+ }
- ASSERT_EQ(2u, render_pass->quad_list.size());
+ // Update the fallback SurfaceInfo and re-emit DrawQuads.
+ {
+ AppendQuadsData data;
+ surface_layer_impl->SetFallbackSurfaceInfo(fallback_surface_info2);
+ surface_layer_impl->AppendQuads(render_pass.get(), &data);
+ // The the primary SurfaceInfo will be added to activation_dependencies.
+ EXPECT_THAT(data.activation_dependencies,
+ UnorderedElementsAre(surface_id1));
+ }
+
+ ASSERT_EQ(4u, render_pass->quad_list.size());
const SurfaceDrawQuad* surface_draw_quad1 =
SurfaceDrawQuad::MaterialCast(render_pass->quad_list.ElementAt(0));
ASSERT_TRUE(surface_draw_quad1);
const SurfaceDrawQuad* surface_draw_quad2 =
SurfaceDrawQuad::MaterialCast(render_pass->quad_list.ElementAt(1));
ASSERT_TRUE(surface_draw_quad2);
+ const SurfaceDrawQuad* surface_draw_quad3 =
+ SurfaceDrawQuad::MaterialCast(render_pass->quad_list.ElementAt(2));
+ ASSERT_TRUE(surface_draw_quad3);
+ const SurfaceDrawQuad* surface_draw_quad4 =
+ SurfaceDrawQuad::MaterialCast(render_pass->quad_list.ElementAt(3));
+ ASSERT_TRUE(surface_draw_quad4);
EXPECT_EQ(SurfaceDrawQuadType::PRIMARY,
surface_draw_quad1->surface_draw_quad_type);
@@ -258,6 +284,22 @@ TEST(SurfaceLayerImplTest, SurfaceLayerImplEmitsTwoDrawQuadsIfUniqueFallback) {
EXPECT_EQ(SurfaceDrawQuadType::FALLBACK,
surface_draw_quad2->surface_draw_quad_type);
EXPECT_EQ(surface_id2, surface_draw_quad2->surface_id);
+ // If the device scale factor of the primary and fallback are different then
+ // they do not share a SharedQuadState.
+ EXPECT_NE(surface_draw_quad1->shared_quad_state,
+ surface_draw_quad2->shared_quad_state);
+
+ EXPECT_EQ(SurfaceDrawQuadType::PRIMARY,
+ surface_draw_quad3->surface_draw_quad_type);
+ EXPECT_EQ(surface_id1, surface_draw_quad3->surface_id);
+ EXPECT_EQ(surface_draw_quad4, surface_draw_quad3->fallback_quad);
+ EXPECT_EQ(SurfaceDrawQuadType::FALLBACK,
+ surface_draw_quad4->surface_draw_quad_type);
+ EXPECT_EQ(surface_id2, surface_draw_quad4->surface_id);
+ // If the device scale factor of the primary and fallback are the same then
+ // they share a SharedQuadState.
+ EXPECT_EQ(surface_draw_quad3->shared_quad_state,
+ surface_draw_quad4->shared_quad_state);
}
// This test verifies that one SurfaceDrawQuad is emitted if a
@@ -292,7 +334,11 @@ TEST(SurfaceLayerImplTest,
std::unique_ptr<RenderPass> render_pass = RenderPass::Create();
AppendQuadsData data;
surface_layer_impl->AppendQuads(render_pass.get(), &data);
- EXPECT_THAT(data.embedded_surfaces, UnorderedElementsAre(surface_id1));
+ // As the primary and fallback SurfaceInfos match, there is no reason to
+ // add the primary surface ID to |activation_dependencies| because it is not
+ // an unresolved dependency. The fallback surface will already be added as a
+ // reference in referenced_surfaces.
+ EXPECT_THAT(data.activation_dependencies, testing::IsEmpty());
ASSERT_EQ(1u, render_pass->quad_list.size());
const SurfaceDrawQuad* surface_draw_quad1 =
diff --git a/chromium/cc/layers/surface_layer_unittest.cc b/chromium/cc/layers/surface_layer_unittest.cc
index 0ee4e836500..4c354a7a5f6 100644
--- a/chromium/cc/layers/surface_layer_unittest.cc
+++ b/chromium/cc/layers/surface_layer_unittest.cc
@@ -32,6 +32,9 @@
namespace cc {
namespace {
+using testing::_;
+using testing::Eq;
+
static constexpr FrameSinkId kArbitraryFrameSinkId(1, 1);
class SurfaceLayerTest : public testing::Test {
@@ -63,33 +66,20 @@ class SurfaceLayerTest : public testing::Test {
FakeLayerTreeHostImpl host_impl_;
};
-class TestSurfaceReferenceFactory : public SequenceSurfaceReferenceFactory {
- protected:
- void SatisfySequence(const SurfaceSequence& seq) const override {
- *out_seq_ = seq;
- }
-
- void RequireSequence(const SurfaceId& id,
- const SurfaceSequence& seq) const override {
- *out_id_ = id;
- out_set_->insert(seq);
- }
-
+class MockSurfaceReferenceFactory : public SequenceSurfaceReferenceFactory {
public:
- TestSurfaceReferenceFactory(SurfaceSequence* out_seq,
- SurfaceId* out_id,
- std::set<SurfaceSequence>* out_set)
- : out_seq_(out_seq), out_id_(out_id), out_set_(out_set) {}
+ MockSurfaceReferenceFactory() {}
+
+ // SequenceSurfaceReferenceFactory implementation.
+ MOCK_CONST_METHOD1(SatisfySequence, void(const SurfaceSequence&));
+ MOCK_CONST_METHOD2(RequireSequence,
+ void(const SurfaceId&, const SurfaceSequence&));
protected:
- ~TestSurfaceReferenceFactory() override = default;
+ ~MockSurfaceReferenceFactory() override = default;
private:
- SurfaceSequence* out_seq_;
- SurfaceId* out_id_;
- std::set<SurfaceSequence>* out_set_;
-
- DISALLOW_COPY_AND_ASSIGN(TestSurfaceReferenceFactory);
+ DISALLOW_COPY_AND_ASSIGN(MockSurfaceReferenceFactory);
};
// Check that one surface can be referenced by multiple LayerTreeHosts, and
@@ -97,17 +87,26 @@ class TestSurfaceReferenceFactory : public SequenceSurfaceReferenceFactory {
TEST_F(SurfaceLayerTest, MultipleFramesOneSurface) {
const base::UnguessableToken kArbitraryToken =
base::UnguessableToken::Create();
- SurfaceSequence blank_change; // Receives sequence if commit doesn't happen.
-
- SurfaceId required_id;
- std::set<SurfaceSequence> required_seq;
- scoped_refptr<SurfaceReferenceFactory> ref_factory =
- new TestSurfaceReferenceFactory(&blank_change, &required_id,
- &required_seq);
- auto layer = SurfaceLayer::Create(ref_factory);
- SurfaceInfo info(
+ const SurfaceInfo info(
SurfaceId(kArbitraryFrameSinkId, LocalSurfaceId(1, kArbitraryToken)), 1.f,
gfx::Size(1, 1));
+ const SurfaceSequence expected_seq1(FrameSinkId(1, 1), 1u);
+ const SurfaceSequence expected_seq2(FrameSinkId(2, 2), 1u);
+ const SurfaceId expected_id(kArbitraryFrameSinkId,
+ LocalSurfaceId(1, kArbitraryToken));
+
+ scoped_refptr<MockSurfaceReferenceFactory> ref_factory =
+ new testing::StrictMock<MockSurfaceReferenceFactory>();
+
+ // We are going to set up the SurfaceLayers and LayerTreeHosts. Each layer
+ // will require a sequence and no sequence should be satisfied for now.
+ EXPECT_CALL(*ref_factory, RequireSequence(Eq(expected_id), Eq(expected_seq1)))
+ .Times(1);
+ EXPECT_CALL(*ref_factory, RequireSequence(Eq(expected_id), Eq(expected_seq2)))
+ .Times(1);
+ EXPECT_CALL(*ref_factory, SatisfySequence(_)).Times(0);
+
+ auto layer = SurfaceLayer::Create(ref_factory);
layer->SetPrimarySurfaceInfo(info);
layer_tree_host_->GetSurfaceSequenceGenerator()->set_frame_sink_id(
FrameSinkId(1, 1));
@@ -117,57 +116,40 @@ TEST_F(SurfaceLayerTest, MultipleFramesOneSurface) {
std::unique_ptr<FakeLayerTreeHost> layer_tree_host2 =
FakeLayerTreeHost::Create(&fake_client_, &task_graph_runner_,
animation_host2.get());
- auto layer2 = SurfaceLayer::Create(std::move(ref_factory));
+ auto layer2 = SurfaceLayer::Create(ref_factory);
layer2->SetPrimarySurfaceInfo(info);
layer_tree_host2->GetSurfaceSequenceGenerator()->set_frame_sink_id(
FrameSinkId(2, 2));
layer_tree_host2->SetRootLayer(layer2);
- // Layers haven't been removed, so no sequence should be satisfied.
- EXPECT_FALSE(blank_change.is_valid());
-
- SurfaceSequence expected1(FrameSinkId(1, 1), 1u);
- SurfaceSequence expected2(FrameSinkId(2, 2), 1u);
+ testing::Mock::VerifyAndClearExpectations(ref_factory.get());
+ // Destroy the second LayerTreeHost. The sequence generated by its
+ // SurfaceLayer must be satisfied and no new sequences must be required.
+ EXPECT_CALL(*ref_factory, SatisfySequence(Eq(expected_seq2))).Times(1);
layer_tree_host2->SetRootLayer(nullptr);
layer_tree_host2.reset();
animation_host2 = nullptr;
-
- // Layer was removed so sequence from second LayerTreeHost should be
- // satisfied.
base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(blank_change == expected2);
-
- // Set of sequences that need to be satisfied should include sequences from
- // both trees.
- EXPECT_TRUE(required_id == SurfaceId(kArbitraryFrameSinkId,
- LocalSurfaceId(1, kArbitraryToken)));
- EXPECT_EQ(2u, required_seq.size());
- EXPECT_TRUE(required_seq.count(expected1));
- EXPECT_TRUE(required_seq.count(expected2));
+ testing::Mock::VerifyAndClearExpectations(ref_factory.get());
+ // Destroy the first LayerTreeHost. The sequence generated by its
+ // SurfaceLayer must be satisfied and no new sequences must be required.
+ EXPECT_CALL(*ref_factory, SatisfySequence(expected_seq1)).Times(1);
+ EXPECT_CALL(*ref_factory, RequireSequence(_, _)).Times(0);
layer_tree_host_->SetRootLayer(nullptr);
layer_tree_host_.reset();
-
- // Layer was removed so sequence from first LayerTreeHost should be
- // satisfied.
base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(blank_change == expected1);
-
- // No more SurfaceSequences should have been generated that need to have be
- // satisfied.
- EXPECT_EQ(2u, required_seq.size());
+ testing::Mock::VerifyAndClearExpectations(ref_factory.get());
}
// This test verifies that the primary and fallback SurfaceInfo are pushed
// across from SurfaceLayer to SurfaceLayerImpl.
TEST_F(SurfaceLayerTest, SurfaceInfoPushProperties) {
- SurfaceSequence blank_change;
- SurfaceId required_id;
- std::set<SurfaceSequence> required_sequences;
+ // We use a nice mock here because we are not really interested in calls to
+ // MockSurfaceReferenceFactory and we don't want warnings printed.
scoped_refptr<SurfaceReferenceFactory> ref_factory =
- new TestSurfaceReferenceFactory(&blank_change, &required_id,
- &required_sequences);
+ new testing::NiceMock<MockSurfaceReferenceFactory>();
scoped_refptr<SurfaceLayer> layer = SurfaceLayer::Create(ref_factory);
layer_tree_host_->SetRootLayer(layer);
@@ -208,24 +190,34 @@ class SurfaceLayerSwapPromise : public LayerTreeTest {
void BeginTest() override {
layer_tree_host()->GetSurfaceSequenceGenerator()->set_frame_sink_id(
FrameSinkId(1, 1));
- layer_ = SurfaceLayer::Create(new TestSurfaceReferenceFactory(
- &satisfied_sequence_, &required_id_, &required_set_));
+ ref_factory_ = new testing::StrictMock<MockSurfaceReferenceFactory>();
+
+ // Create a SurfaceLayer but don't add it to the tree yet. No sequence
+ // should be required / satisfied.
+ EXPECT_CALL(*ref_factory_, SatisfySequence(_)).Times(0);
+ EXPECT_CALL(*ref_factory_, RequireSequence(_, _)).Times(0);
+ layer_ = SurfaceLayer::Create(ref_factory_);
SurfaceInfo info(
SurfaceId(kArbitraryFrameSinkId, LocalSurfaceId(1, kArbitraryToken)),
1.f, gfx::Size(1, 1));
layer_->SetPrimarySurfaceInfo(info);
-
- // Layer hasn't been added to tree so no SurfaceSequence generated yet.
- EXPECT_EQ(0u, required_set_.size());
-
+ testing::Mock::VerifyAndClearExpectations(ref_factory_.get());
+
+ // Add the layer to the tree. A sequence must be required.
+ SurfaceSequence expected_seq(kArbitraryFrameSinkId, 1u);
+ SurfaceId expected_id(kArbitraryFrameSinkId,
+ LocalSurfaceId(1, kArbitraryToken));
+ EXPECT_CALL(*ref_factory_, SatisfySequence(_)).Times(0);
+ EXPECT_CALL(*ref_factory_,
+ RequireSequence(Eq(expected_id), Eq(expected_seq)))
+ .Times(1);
layer_tree_host()->SetRootLayer(layer_);
+ testing::Mock::VerifyAndClearExpectations(ref_factory_.get());
- // Should have SurfaceSequence from first tree.
- SurfaceSequence expected(kArbitraryFrameSinkId, 1u);
- EXPECT_TRUE(required_id_ == SurfaceId(kArbitraryFrameSinkId,
- LocalSurfaceId(1, kArbitraryToken)));
- EXPECT_EQ(1u, required_set_.size());
- EXPECT_TRUE(required_set_.count(expected));
+ // By the end of the test, the required sequence must be satisfied and no
+ // more sequence must be required.
+ EXPECT_CALL(*ref_factory_, SatisfySequence(Eq(expected_seq))).Times(1);
+ EXPECT_CALL(*ref_factory_, RequireSequence(_, _)).Times(0);
gfx::Size bounds(100, 100);
layer_tree_host()->SetViewportSize(bounds);
@@ -245,15 +237,15 @@ class SurfaceLayerSwapPromise : public LayerTreeTest {
base::Unretained(this)));
}
+ void AfterTest() override {}
+
protected:
int commit_count_;
bool sequence_was_satisfied_;
scoped_refptr<SurfaceLayer> layer_;
scoped_refptr<Layer> blank_layer_;
- SurfaceSequence satisfied_sequence_;
+ scoped_refptr<MockSurfaceReferenceFactory> ref_factory_;
- SurfaceId required_id_;
- std::set<SurfaceSequence> required_set_;
const base::UnguessableToken kArbitraryToken =
base::UnguessableToken::Create();
};
@@ -276,14 +268,6 @@ class SurfaceLayerSwapPromiseWithDraw : public SurfaceLayerSwapPromise {
break;
}
}
-
- void AfterTest() override {
- EXPECT_TRUE(required_id_ == SurfaceId(kArbitraryFrameSinkId,
- LocalSurfaceId(1, kArbitraryToken)));
- EXPECT_EQ(1u, required_set_.size());
- EXPECT_TRUE(satisfied_sequence_ ==
- SurfaceSequence(kArbitraryFrameSinkId, 1u));
- }
};
SINGLE_AND_MULTI_THREAD_TEST_F(SurfaceLayerSwapPromiseWithDraw);
@@ -315,14 +299,6 @@ class SurfaceLayerSwapPromiseWithoutDraw : public SurfaceLayerSwapPromise {
break;
}
}
-
- void AfterTest() override {
- EXPECT_TRUE(required_id_ == SurfaceId(kArbitraryFrameSinkId,
- LocalSurfaceId(1, kArbitraryToken)));
- EXPECT_EQ(1u, required_set_.size());
- EXPECT_TRUE(satisfied_sequence_ ==
- SurfaceSequence(kArbitraryFrameSinkId, 1u));
- }
};
MULTI_THREAD_TEST_F(SurfaceLayerSwapPromiseWithoutDraw);
diff --git a/chromium/cc/layers/texture_layer_unittest.cc b/chromium/cc/layers/texture_layer_unittest.cc
index dc9c60d3795..a13964af827 100644
--- a/chromium/cc/layers/texture_layer_unittest.cc
+++ b/chromium/cc/layers/texture_layer_unittest.cc
@@ -638,18 +638,15 @@ class TextureLayerImplWithMailboxThreadedCallback : public LayerTreeTest {
std::unique_ptr<TestCompositorFrameSink> CreateCompositorFrameSink(
scoped_refptr<ContextProvider> compositor_context_provider,
scoped_refptr<ContextProvider> worker_context_provider) override {
+ constexpr bool kDisableDisplayVsync = false;
bool synchronous_composite =
!HasImplThread() &&
!layer_tree_host()->GetSettings().single_thread_proxy_scheduler;
- // Allow relaim resources for this test so that mailboxes in the display
- // will be returned inside the commit that replaces them.
- bool force_disable_reclaim_resources = false;
return base::MakeUnique<TestCompositorFrameSink>(
compositor_context_provider, std::move(worker_context_provider),
shared_bitmap_manager(), gpu_memory_buffer_manager(),
layer_tree_host()->GetSettings().renderer_settings,
- ImplThreadTaskRunner(), synchronous_composite,
- force_disable_reclaim_resources);
+ ImplThreadTaskRunner(), synchronous_composite, kDisableDisplayVsync);
}
void AdvanceTestCase() {
@@ -1188,16 +1185,6 @@ class TextureLayerChangeInvisibleMailboxTest
void MailboxReleased(const gpu::SyncToken& sync_token, bool lost_resource) {
EXPECT_TRUE(sync_token.HasData());
++mailbox_returned_;
- switch (mailbox_returned_) {
- case 1:
- break;
- case 2:
- EXPECT_EQ(commit_count_, 5);
- EndTest();
- break;
- default:
- NOTREACHED();
- }
}
void SetupTree() override {
@@ -1227,7 +1214,7 @@ class TextureLayerChangeInvisibleMailboxTest
void BeginTest() override { PostSetNeedsCommitToMainThread(); }
- void DidCommitAndDrawFrame() override {
+ void DidReceiveCompositorFrameAck() override {
++commit_count_;
switch (commit_count_) {
case 1:
@@ -1262,6 +1249,8 @@ class TextureLayerChangeInvisibleMailboxTest
texture_layer_->ClearClient();
break;
case 5:
+ EXPECT_EQ(2, mailbox_returned_);
+ EndTest();
break;
default:
NOTREACHED();
@@ -1284,8 +1273,7 @@ class TextureLayerChangeInvisibleMailboxTest
int commit_count_;
};
-// Flaky when multi-threaded. crbug.com/702868
-SINGLE_THREAD_TEST_F(TextureLayerChangeInvisibleMailboxTest);
+SINGLE_AND_MULTI_THREAD_TEST_F(TextureLayerChangeInvisibleMailboxTest);
// Test that TextureLayerImpl::ReleaseResources can be called which releases
// the mailbox back to TextureLayerClient.
diff --git a/chromium/cc/layers/ui_resource_layer_unittest.cc b/chromium/cc/layers/ui_resource_layer_unittest.cc
index 17dc4dadfe7..6c05ec16246 100644
--- a/chromium/cc/layers/ui_resource_layer_unittest.cc
+++ b/chromium/cc/layers/ui_resource_layer_unittest.cc
@@ -60,7 +60,6 @@ TEST_F(UIResourceLayerTest, SetBitmap) {
Mock::VerifyAndClearExpectations(layer_tree_host());
EXPECT_EQ(test_layer->GetLayerTreeHostForTesting(), layer_tree_host());
- test_layer->SavePaintProperties();
test_layer->Update();
EXPECT_FALSE(test_layer->DrawsContent());
@@ -84,7 +83,6 @@ TEST_F(UIResourceLayerTest, SetUIResourceId) {
Mock::VerifyAndClearExpectations(layer_tree_host());
EXPECT_EQ(test_layer->GetLayerTreeHostForTesting(), layer_tree_host());
- test_layer->SavePaintProperties();
test_layer->Update();
EXPECT_FALSE(test_layer->DrawsContent());
@@ -162,7 +160,6 @@ TEST_F(UIResourceLayerTest, SharedBitmap) {
layer_tree_host()->SetRootLayer(layer1);
layer1->SetBitmap(bitmap);
bitmap.reset();
- layer1->SavePaintProperties();
layer1->Update();
EXPECT_TRUE(layer1->DrawsContent());
const auto resource_id = layer1->resource_id();
@@ -171,7 +168,6 @@ TEST_F(UIResourceLayerTest, SharedBitmap) {
scoped_refptr<TestUIResourceLayer> layer2 = TestUIResourceLayer::Create();
layer_tree_host()->SetRootLayer(layer2);
layer2->SetBitmap(bitmap_copy);
- layer2->SavePaintProperties();
layer2->Update();
EXPECT_TRUE(layer2->DrawsContent());
EXPECT_EQ(resource_id, layer2->resource_id());
@@ -189,7 +185,6 @@ TEST_F(UIResourceLayerTest, SharedBitmap) {
// change the shared bitmap to something else then back to the original.
LayerTestCommon::LayerImplTest impl;
impl.host()->SetRootLayer(layer1);
- layer1->SavePaintProperties();
layer1->Update();
EXPECT_TRUE(layer1->DrawsContent());
const auto other_lth_resource_id = layer1->resource_id();
diff --git a/chromium/cc/layers/video_layer_impl.cc b/chromium/cc/layers/video_layer_impl.cc
index 53b90ee4fa5..7b29b323965 100644
--- a/chromium/cc/layers/video_layer_impl.cc
+++ b/chromium/cc/layers/video_layer_impl.cc
@@ -168,9 +168,10 @@ void VideoLayerImpl::AppendQuads(RenderPass* render_pass,
SharedQuadState* shared_quad_state =
render_pass->CreateAndAppendSharedQuadState();
- shared_quad_state->SetAll(transform, rotated_size, visible_layer_rect(),
- clip_rect(), is_clipped(), draw_opacity(),
- SkBlendMode::kSrcOver, GetSortingContextId());
+ shared_quad_state->SetAll(transform, gfx::Rect(rotated_size),
+ visible_layer_rect(), clip_rect(), is_clipped(),
+ draw_opacity(), SkBlendMode::kSrcOver,
+ GetSortingContextId());
AppendDebugBorderQuad(
render_pass, rotated_size, shared_quad_state, append_quads_data);
diff --git a/chromium/cc/output/bsp_tree_perftest.cc b/chromium/cc/output/bsp_tree_perftest.cc
index 3b954d1d41e..f8f16d0d0ae 100644
--- a/chromium/cc/output/bsp_tree_perftest.cc
+++ b/chromium/cc/output/bsp_tree_perftest.cc
@@ -71,10 +71,8 @@ class BspTreePerfTest : public LayerTreeTest {
LayerTreeImpl* active_tree = host_impl->active_tree();
// First build the tree and then we'll start running tests on layersorter
// itself
- bool can_render_to_separate_surface = true;
int max_texture_size = 8096;
- DoCalcDrawPropertiesImpl(can_render_to_separate_surface, max_texture_size,
- active_tree, host_impl);
+ DoCalcDrawPropertiesImpl(max_texture_size, active_tree, host_impl);
LayerImplList base_list;
BuildLayerImplList(active_tree->root_layer_for_testing(), &base_list);
@@ -104,23 +102,21 @@ class BspTreePerfTest : public LayerTreeTest {
EndTest();
}
- void DoCalcDrawPropertiesImpl(bool can_render_to_separate_surface,
- int max_texture_size,
+ void DoCalcDrawPropertiesImpl(int max_texture_size,
LayerTreeImpl* active_tree,
LayerTreeHostImpl* host_impl) {
- LayerImplList update_list;
+ RenderSurfaceList update_list;
LayerTreeHostCommon::CalcDrawPropsImplInputs inputs(
- active_tree->root_layer_for_testing(), active_tree->DrawViewportSize(),
- host_impl->DrawTransform(), active_tree->device_scale_factor(),
+ active_tree->root_layer_for_testing(),
+ active_tree->DeviceViewport().size(), host_impl->DrawTransform(),
+ active_tree->device_scale_factor(),
active_tree->current_page_scale_factor(),
active_tree->InnerViewportContainerLayer(),
active_tree->InnerViewportScrollLayer(),
active_tree->OuterViewportScrollLayer(),
active_tree->elastic_overscroll()->Current(active_tree->IsActiveTree()),
active_tree->OverscrollElasticityLayer(), max_texture_size,
- can_render_to_separate_surface,
host_impl->settings().layer_transforms_should_scale_layer_contents,
- false, // don't use layer lists for perf tests
&update_list, active_tree->property_trees());
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
}
diff --git a/chromium/cc/output/ca_layer_overlay.cc b/chromium/cc/output/ca_layer_overlay.cc
index 1acd9528c56..972c8c405f7 100644
--- a/chromium/cc/output/ca_layer_overlay.cc
+++ b/chromium/cc/output/ca_layer_overlay.cc
@@ -74,34 +74,23 @@ bool FilterOperationSupported(const FilterOperation& operation) {
}
}
-static const FilterOperations* FiltersForPass(
- int render_pass_id,
- const RenderPassFilterList& filter_list) {
- auto it = std::lower_bound(
- filter_list.begin(), filter_list.end(),
- std::pair<int, FilterOperations*>(render_pass_id, nullptr));
- if (it != filter_list.end() && it->first == render_pass_id)
- return it->second;
- return nullptr;
-}
-
CALayerResult FromRenderPassQuad(
ResourceProvider* resource_provider,
const RenderPassDrawQuad* quad,
- const RenderPassFilterList& render_pass_filters,
- const RenderPassFilterList& render_pass_background_filters,
+ const base::flat_map<int, FilterOperations*>& render_pass_filters,
+ const base::flat_map<int, FilterOperations*>&
+ render_pass_background_filters,
CALayerOverlay* ca_layer_overlay) {
- if (FiltersForPass(quad->render_pass_id, render_pass_background_filters)) {
+ if (render_pass_background_filters.count(quad->render_pass_id)) {
return CA_LAYER_FAILED_RENDER_PASS_BACKGROUND_FILTERS;
}
if (quad->shared_quad_state->sorting_context_id != 0)
return CA_LAYER_FAILED_RENDER_PASS_SORTING_CONTEXT_ID;
- const FilterOperations* filters =
- FiltersForPass(quad->render_pass_id, render_pass_filters);
- if (filters) {
- for (const FilterOperation& operation : filters->operations()) {
+ auto it = render_pass_filters.find(quad->render_pass_id);
+ if (it != render_pass_filters.end()) {
+ for (const FilterOperation& operation : it->second->operations()) {
bool success = FilterOperationSupported(operation);
if (!success)
return CA_LAYER_FAILED_RENDER_PASS_FILTER_OPERATION;
@@ -188,8 +177,9 @@ class CALayerOverlayProcessor {
ResourceProvider* resource_provider,
const gfx::RectF& display_rect,
const DrawQuad* quad,
- const RenderPassFilterList& render_pass_filters,
- const RenderPassFilterList& render_pass_background_filters,
+ const base::flat_map<int, FilterOperations*>& render_pass_filters,
+ const base::flat_map<int, FilterOperations*>&
+ render_pass_background_filters,
CALayerOverlay* ca_layer_overlay,
bool* skip,
bool* render_pass_draw_quad) {
@@ -286,8 +276,9 @@ bool ProcessForCALayerOverlays(
ResourceProvider* resource_provider,
const gfx::RectF& display_rect,
const QuadList& quad_list,
- const RenderPassFilterList& render_pass_filters,
- const RenderPassFilterList& render_pass_background_filters,
+ const base::flat_map<int, FilterOperations*>& render_pass_filters,
+ const base::flat_map<int, FilterOperations*>&
+ render_pass_background_filters,
CALayerOverlayList* ca_layer_overlays) {
CALayerResult result = CA_LAYER_SUCCESS;
ca_layer_overlays->reserve(quad_list.size());
diff --git a/chromium/cc/output/ca_layer_overlay.h b/chromium/cc/output/ca_layer_overlay.h
index 513ba667d01..da003f9f02e 100644
--- a/chromium/cc/output/ca_layer_overlay.h
+++ b/chromium/cc/output/ca_layer_overlay.h
@@ -5,6 +5,7 @@
#ifndef CC_OUTPUT_CA_LAYER_OVERLAY_H_
#define CC_OUTPUT_CA_LAYER_OVERLAY_H_
+#include "base/containers/flat_map.h"
#include "base/memory/ref_counted.h"
#include "cc/quads/render_pass.h"
#include "third_party/skia/include/core/SkColor.h"
@@ -76,8 +77,9 @@ bool ProcessForCALayerOverlays(
ResourceProvider* resource_provider,
const gfx::RectF& display_rect,
const QuadList& quad_list,
- const RenderPassFilterList& render_pass_filters,
- const RenderPassFilterList& render_pass_background_filters,
+ const base::flat_map<int, FilterOperations*>& render_pass_filters,
+ const base::flat_map<int, FilterOperations*>&
+ render_pass_background_filters,
CALayerOverlayList* ca_layer_overlays);
} // namespace cc
diff --git a/chromium/cc/output/compositor_frame.cc b/chromium/cc/output/compositor_frame.cc
index b1438ee856b..82479cf3b43 100644
--- a/chromium/cc/output/compositor_frame.cc
+++ b/chromium/cc/output/compositor_frame.cc
@@ -13,4 +13,5 @@ CompositorFrame::CompositorFrame(CompositorFrame&& other) = default;
CompositorFrame::~CompositorFrame() {}
CompositorFrame& CompositorFrame::operator=(CompositorFrame&& other) = default;
+
} // namespace cc
diff --git a/chromium/cc/output/compositor_frame_metadata.h b/chromium/cc/output/compositor_frame_metadata.h
index a3ebfc26483..9e73fc5b926 100644
--- a/chromium/cc/output/compositor_frame_metadata.h
+++ b/chromium/cc/output/compositor_frame_metadata.h
@@ -85,8 +85,18 @@ class CC_EXPORT CompositorFrameMetadata {
// retain. Thus, this field will likely go away.
std::vector<SurfaceId> referenced_surfaces;
- // This is the set of SurfaceIds embedded in DrawQuads.
- std::vector<SurfaceId> embedded_surfaces;
+ // This is the set of dependent SurfaceIds that should be active in the
+ // display compositor before this CompositorFrame can be activated. Note
+ // that if |can_activate_before_dependencies| then the display compositor
+ // can choose to activate a CompositorFrame before all dependencies are
+ // available.
+ // Note: |activation_dependencies| and |referenced_surfaces| are disjoint
+ // sets of surface IDs. If a surface ID is known to exist and can be
+ // used without additional synchronization, then it is placed in
+ // |referenced_surfaces|. |activation_dependencies| is the set of
+ // surface IDs that this frame would like to block on until they
+ // become available or a deadline hits.
+ std::vector<SurfaceId> activation_dependencies;
// This indicates whether this CompositorFrame can be activated before
// dependencies have been resolved.
diff --git a/chromium/cc/output/compositor_frame_sink.h b/chromium/cc/output/compositor_frame_sink.h
index 650f7191c2e..28b72581b5e 100644
--- a/chromium/cc/output/compositor_frame_sink.h
+++ b/chromium/cc/output/compositor_frame_sink.h
@@ -25,6 +25,7 @@ class GpuMemoryBufferManager;
namespace cc {
+struct BeginFrameAck;
class CompositorFrame;
class CompositorFrameSinkClient;
class LocalSurfaceId;
@@ -41,9 +42,13 @@ class CC_EXPORT CompositorFrameSink {
struct Capabilities {
Capabilities() = default;
- // Whether ForceReclaimResources can be called to reclaim all resources
- // from the CompositorFrameSink.
- bool can_force_reclaim_resources = false;
+ // True if we must always swap, even if there is no damage to the frame.
+ // Needed for both the browser compositor as well as layout tests.
+ // TODO(ericrk): This should be test-only for layout tests, but tab
+ // capture has issues capturing offscreen tabs whithout this. We should
+ // remove this dependency. crbug.com/680196
+ bool must_always_swap = false;
+
// True if sync points for resources are needed when swapping delegated
// frames.
bool delegated_sync_points_required = true;
@@ -102,10 +107,6 @@ class CC_EXPORT CompositorFrameSink {
return shared_bitmap_manager_;
}
- // If supported, this causes a ReclaimResources for all resources that are
- // currently in use.
- virtual void ForceReclaimResources() {}
-
// If supported, this sets the LocalSurfaceId the CompositorFrameSink will use
// to submit a CompositorFrame.
virtual void SetLocalSurfaceId(const LocalSurfaceId& local_surface_id) {}
@@ -121,6 +122,10 @@ class CC_EXPORT CompositorFrameSink {
// processed in order to unthrottle the next frame.
virtual void SubmitCompositorFrame(CompositorFrame frame) = 0;
+ // Signals that a BeginFrame issued by the BeginFrameSource provided to the
+ // client did not lead to a CompositorFrame submission.
+ virtual void DidNotProduceFrame(const BeginFrameAck& ack) = 0;
+
protected:
// Bound to the ContextProvider to hear about when it is lost and inform the
// |client_|.
diff --git a/chromium/cc/output/compositor_frame_sink_unittest.cc b/chromium/cc/output/compositor_frame_sink_unittest.cc
index 6a72c8d58bb..127eb43f9c9 100644
--- a/chromium/cc/output/compositor_frame_sink_unittest.cc
+++ b/chromium/cc/output/compositor_frame_sink_unittest.cc
@@ -28,6 +28,7 @@ class TestCompositorFrameSink : public CompositorFrameSink {
void SubmitCompositorFrame(CompositorFrame frame) override {
client_->DidReceiveCompositorFrameAck();
}
+ void DidNotProduceFrame(const BeginFrameAck& ack) override {}
};
TEST(CompositorFrameSinkTest, ContextLossInformsClient) {
diff --git a/chromium/cc/output/dc_layer_overlay.cc b/chromium/cc/output/dc_layer_overlay.cc
index eda508e6e13..7cf68722011 100644
--- a/chromium/cc/output/dc_layer_overlay.cc
+++ b/chromium/cc/output/dc_layer_overlay.cc
@@ -4,6 +4,7 @@
#include "cc/output/dc_layer_overlay.h"
+#include "base/metrics/histogram_macros.h"
#include "cc/base/math_util.h"
#include "cc/quads/solid_color_draw_quad.h"
#include "cc/quads/yuv_video_draw_quad.h"
@@ -68,6 +69,11 @@ gfx::RectF GetOcclusionBounds(const gfx::RectF& target_quad,
return occlusion_bounding_box;
}
+void RecordDCLayerResult(DCLayerOverlayProcessor::DCLayerResult result) {
+ UMA_HISTOGRAM_ENUMERATION("GPU.DirectComposition.DCLayerResult", result,
+ DCLayerOverlayProcessor::DC_LAYER_FAILED_MAX);
+}
+
} // namespace
DCLayerOverlay::DCLayerOverlay() : filter(GL_LINEAR) {}
@@ -85,7 +91,7 @@ DCLayerOverlayProcessor::DCLayerResult DCLayerOverlayProcessor::FromDrawQuad(
if (quad->shared_quad_state->blend_mode != SkBlendMode::kSrcOver)
return DC_LAYER_FAILED_QUAD_BLEND_MODE;
- DCLayerResult result = DC_LAYER_FAILED_UNKNOWN;
+ DCLayerResult result;
switch (quad->material) {
case DrawQuad::YUV_VIDEO_CONTENT:
result =
@@ -93,7 +99,7 @@ DCLayerOverlayProcessor::DCLayerResult DCLayerOverlayProcessor::FromDrawQuad(
ca_layer_overlay);
break;
default:
- return DC_LAYER_FAILED_UNKNOWN;
+ return DC_LAYER_FAILED_UNSUPPORTED_QUAD;
}
if (result != DC_LAYER_SUCCESS)
return result;
@@ -128,13 +134,16 @@ void DCLayerOverlayProcessor::Process(ResourceProvider* resource_provider,
DCLayerOverlay ca_layer;
DCLayerResult result = FromDrawQuad(resource_provider, display_rect,
quad_list->begin(), it, &ca_layer);
- if (result != DC_LAYER_SUCCESS)
+ if (result != DC_LAYER_SUCCESS) {
+ RecordDCLayerResult(result);
continue;
+ }
if (!it->shared_quad_state->quad_to_target_transform
.Preserves2dAxisAlignment() &&
!base::FeatureList::IsEnabled(
features::kDirectCompositionComplexOverlays)) {
+ RecordDCLayerResult(DC_LAYER_FAILED_COMPLEX_TRANSFORM);
continue;
}
@@ -152,6 +161,7 @@ void DCLayerOverlayProcessor::Process(ResourceProvider* resource_provider,
quad_list->EraseAndInvalidateAllPointers(it);
} else if (!base::FeatureList::IsEnabled(
features::kDirectCompositionUnderlays)) {
+ RecordDCLayerResult(DC_LAYER_FAILED_OCCLUDED);
continue;
} else {
// The quad is occluded, so replace it with a black solid color quad and
diff --git a/chromium/cc/output/dc_layer_overlay.h b/chromium/cc/output/dc_layer_overlay.h
index 5ae861a22d8..6daeedc02e7 100644
--- a/chromium/cc/output/dc_layer_overlay.h
+++ b/chromium/cc/output/dc_layer_overlay.h
@@ -66,12 +66,17 @@ typedef std::vector<DCLayerOverlay> DCLayerOverlayList;
class DCLayerOverlayProcessor {
public:
+ // This is used for a histogram to determine why overlays are or aren't
+ // used, so don't remove entries and make sure to update enums.xml if
+ // it changes.
enum DCLayerResult {
DC_LAYER_SUCCESS,
+ DC_LAYER_FAILED_UNSUPPORTED_QUAD,
DC_LAYER_FAILED_QUAD_BLEND_MODE,
DC_LAYER_FAILED_TEXTURE_NOT_CANDIDATE,
DC_LAYER_FAILED_OCCLUDED,
- DC_LAYER_FAILED_UNKNOWN
+ DC_LAYER_FAILED_COMPLEX_TRANSFORM,
+ DC_LAYER_FAILED_MAX,
};
void Process(ResourceProvider* resource_provider,
diff --git a/chromium/cc/output/direct_renderer.cc b/chromium/cc/output/direct_renderer.cc
index 024f5653f36..5339f829c2b 100644
--- a/chromium/cc/output/direct_renderer.cc
+++ b/chromium/cc/output/direct_renderer.cc
@@ -6,7 +6,6 @@
#include <stddef.h>
-#include <unordered_map>
#include <utility>
#include <vector>
@@ -178,31 +177,31 @@ void DirectRenderer::DecideRenderPassAllocationsForFrame(
const RenderPassList& render_passes_in_draw_order) {
render_pass_bypass_quads_.clear();
- std::unordered_map<int, gfx::Size> render_passes_in_frame;
- RenderPass* root_render_pass = render_passes_in_draw_order.back().get();
- for (size_t i = 0; i < render_passes_in_draw_order.size(); ++i) {
- RenderPass* pass = render_passes_in_draw_order[i].get();
+ auto& root_render_pass = render_passes_in_draw_order.back();
+
+ base::flat_map<int, gfx::Size> render_passes_in_frame;
+ for (const auto& pass : render_passes_in_draw_order) {
if (pass != root_render_pass) {
- if (const TileDrawQuad* tile_quad = CanPassBeDrawnDirectly(pass)) {
+ if (const TileDrawQuad* tile_quad = CanPassBeDrawnDirectly(pass.get())) {
+ // If the render pass is drawn directly, it will not be drawn from as
+ // a render pass so it's not added to the map.
render_pass_bypass_quads_[pass->id] = *tile_quad;
continue;
}
}
- render_passes_in_frame.insert(
- std::pair<int, gfx::Size>(pass->id, RenderPassTextureSize(pass)));
+ render_passes_in_frame[pass->id] = RenderPassTextureSize(pass.get());
}
std::vector<int> passes_to_delete;
- for (auto pass_iter = render_pass_textures_.begin();
- pass_iter != render_pass_textures_.end(); ++pass_iter) {
- auto it = render_passes_in_frame.find(pass_iter->first);
+ for (const auto& pair : render_pass_textures_) {
+ auto it = render_passes_in_frame.find(pair.first);
if (it == render_passes_in_frame.end()) {
- passes_to_delete.push_back(pass_iter->first);
+ passes_to_delete.push_back(pair.first);
continue;
}
gfx::Size required_size = it->second;
- ScopedResource* texture = pass_iter->second.get();
+ ScopedResource* texture = pair.second.get();
DCHECK(texture);
bool size_appropriate = texture->size().width() >= required_size.width() &&
@@ -290,14 +289,9 @@ void DirectRenderer::DrawFrame(RenderPassList* render_passes_in_draw_order,
for (const auto& pass : *render_passes_in_draw_order) {
if (!pass->filters.IsEmpty())
- render_pass_filters_.push_back(std::make_pair(pass->id, &pass->filters));
- if (!pass->background_filters.IsEmpty()) {
- render_pass_background_filters_.push_back(
- std::make_pair(pass->id, &pass->background_filters));
- }
- std::sort(render_pass_filters_.begin(), render_pass_filters_.end());
- std::sort(render_pass_background_filters_.begin(),
- render_pass_background_filters_.end());
+ render_pass_filters_[pass->id] = &pass->filters;
+ if (!pass->background_filters.IsEmpty())
+ render_pass_background_filters_[pass->id] = &pass->background_filters;
}
// Draw all non-root render passes except for the root render pass.
@@ -462,24 +456,14 @@ void DirectRenderer::DoDrawPolygon(const DrawPolygon& poly,
const FilterOperations* DirectRenderer::FiltersForPass(
int render_pass_id) const {
- auto it = std::lower_bound(
- render_pass_filters_.begin(), render_pass_filters_.end(),
- std::pair<int, FilterOperations*>(render_pass_id, nullptr));
- if (it != render_pass_filters_.end() && it->first == render_pass_id)
- return it->second;
- return nullptr;
+ auto it = render_pass_filters_.find(render_pass_id);
+ return it == render_pass_filters_.end() ? nullptr : it->second;
}
const FilterOperations* DirectRenderer::BackgroundFiltersForPass(
int render_pass_id) const {
- auto it = std::lower_bound(
- render_pass_background_filters_.begin(),
- render_pass_background_filters_.end(),
- std::pair<int, FilterOperations*>(render_pass_id, nullptr));
- if (it != render_pass_background_filters_.end() &&
- it->first == render_pass_id)
- return it->second;
- return nullptr;
+ auto it = render_pass_background_filters_.find(render_pass_id);
+ return it == render_pass_background_filters_.end() ? nullptr : it->second;
}
void DirectRenderer::FlushPolygons(
diff --git a/chromium/cc/output/direct_renderer.h b/chromium/cc/output/direct_renderer.h
index 864c1863b29..b5e58e443b7 100644
--- a/chromium/cc/output/direct_renderer.h
+++ b/chromium/cc/output/direct_renderer.h
@@ -6,10 +6,10 @@
#define CC_OUTPUT_DIRECT_RENDERER_H_
#include <memory>
-#include <unordered_map>
#include <vector>
#include "base/callback.h"
+#include "base/containers/flat_map.h"
#include "base/macros.h"
#include "cc/base/filter_operations.h"
#include "cc/cc_export.h"
@@ -198,13 +198,15 @@ class CC_EXPORT DirectRenderer {
// DirectComposition layers needed to be used.
int frames_since_using_dc_layers_ = 0;
- // TODO(danakj): Just use a vector of pairs here? Hash map is way overkill.
- std::unordered_map<int, std::unique_ptr<ScopedResource>>
- render_pass_textures_;
- std::unordered_map<int, TileDrawQuad> render_pass_bypass_quads_;
+ // A map from RenderPass id to the texture used to draw the RenderPass from.
+ base::flat_map<int, std::unique_ptr<ScopedResource>> render_pass_textures_;
+ // A map from RenderPass id to the single quad present in and replacing the
+ // RenderPass.
+ base::flat_map<int, TileDrawQuad> render_pass_bypass_quads_;
- RenderPassFilterList render_pass_filters_;
- RenderPassFilterList render_pass_background_filters_;
+ // A map from RenderPass id to the filters used when drawing the RenderPass.
+ base::flat_map<int, FilterOperations*> render_pass_filters_;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters_;
bool visible_ = false;
bool disable_color_checks_for_testing_ = false;
diff --git a/chromium/cc/output/gl_renderer.cc b/chromium/cc/output/gl_renderer.cc
index 3446cc7d721..03a5ae29725 100644
--- a/chromium/cc/output/gl_renderer.cc
+++ b/chromium/cc/output/gl_renderer.cc
@@ -375,14 +375,12 @@ class GLRenderer::SyncQuery {
GLRenderer::GLRenderer(const RendererSettings* settings,
OutputSurface* output_surface,
ResourceProvider* resource_provider,
- TextureMailboxDeleter* texture_mailbox_deleter,
- int highp_threshold_min)
+ TextureMailboxDeleter* texture_mailbox_deleter)
: DirectRenderer(settings, output_surface, resource_provider),
shared_geometry_quad_(QuadVertexRect()),
gl_(output_surface->context_provider()->ContextGL()),
context_support_(output_surface->context_provider()->ContextSupport()),
texture_mailbox_deleter_(texture_mailbox_deleter),
- highp_threshold_min_(highp_threshold_min),
gl_composited_texture_quad_border_(
settings->gl_composited_texture_quad_border),
bound_geometry_(NO_BINDING),
@@ -677,6 +675,9 @@ static sk_sp<SkImage> ApplyImageFilter(
return nullptr;
}
+ // Big filters can sometimes fallback to CPU. Therefore, we need
+ // to disable subnormal floats for performance and security reasons.
+ ScopedSubnormalFloatDisabler disabler;
SkMatrix local_matrix;
local_matrix.setTranslate(origin.x(), origin.y());
local_matrix.postScale(scale.x(), scale.y());
@@ -946,6 +947,9 @@ sk_sp<SkImage> GLRenderer::ApplyBackgroundFilters(
return nullptr;
}
+ // Big filters can sometimes fallback to CPU. Therefore, we need
+ // to disable subnormal floats for performance and security reasons.
+ ScopedSubnormalFloatDisabler disabler;
SkMatrix local_matrix;
local_matrix.setScale(quad->filters_scale.x(), quad->filters_scale.y());
@@ -1000,7 +1004,7 @@ const TileDrawQuad* GLRenderer::CanPassBeDrawnDirectly(const RenderPass* pass) {
quad->rect != pass->output_rect)
return nullptr;
// The quad is expected to be the entire layer so that AA edges are correct.
- if (gfx::Rect(quad->shared_quad_state->quad_layer_bounds) != quad->rect)
+ if (quad->shared_quad_state->quad_layer_rect != quad->rect)
return nullptr;
if (quad->material != DrawQuad::TILED_CONTENT)
return nullptr;
@@ -1102,8 +1106,11 @@ bool GLRenderer::InitializeRPDQParameters(
static_cast<float>(dst_rect.width()),
static_cast<float>(dst_rect.height()));
gfx::Transform quad_rect_matrix;
+ gfx::Rect quad_layer_rect(quad->shared_quad_state->quad_layer_rect);
+ if (params->filters)
+ quad_layer_rect = params->filters->MapRect(quad_layer_rect, local_matrix);
QuadRectTransform(&quad_rect_matrix, params->quad_to_target_transform,
- params->dst_rect);
+ gfx::RectF(quad_layer_rect));
params->contents_device_transform =
params->window_matrix * params->projection_matrix * quad_rect_matrix;
params->contents_device_transform.FlattenTo2d();
@@ -1112,10 +1119,10 @@ bool GLRenderer::InitializeRPDQParameters(
if (!params->contents_device_transform.IsInvertible())
return false;
+ // TODO(sunxd): unify the anti-aliasing logic of RPDQ and TileDrawQuad.
params->surface_quad = SharedGeometryQuad();
-
gfx::QuadF device_layer_quad;
- if (settings_->allow_antialiasing) {
+ if (settings_->allow_antialiasing && quad->IsEdge()) {
bool clipped = false;
device_layer_quad = MathUtil::MapQuad(params->contents_device_transform,
params->surface_quad, &clipped);
@@ -1305,7 +1312,7 @@ void GLRenderer::UpdateRPDQBlendMode(DrawRenderPassDrawQuadParams* params) {
void GLRenderer::ChooseRPDQProgram(DrawRenderPassDrawQuadParams* params) {
TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
- gl_, &highp_threshold_cache_, highp_threshold_min_,
+ gl_, &highp_threshold_cache_, settings_->highp_threshold_min,
params->quad->shared_quad_state->visible_quad_layer_rect.bottom_right());
BlendMode shader_blend_mode =
@@ -1481,10 +1488,10 @@ bool is_bottom(const gfx::QuadF* clip_region, const DrawQuad* quad) {
return true;
return std::abs(clip_region->p3().y() -
- quad->shared_quad_state->quad_layer_bounds.height()) <
+ quad->shared_quad_state->quad_layer_rect.height()) <
kAntiAliasingEpsilon &&
std::abs(clip_region->p4().y() -
- quad->shared_quad_state->quad_layer_bounds.height()) <
+ quad->shared_quad_state->quad_layer_rect.height()) <
kAntiAliasingEpsilon;
}
@@ -1505,10 +1512,10 @@ bool is_right(const gfx::QuadF* clip_region, const DrawQuad* quad) {
return true;
return std::abs(clip_region->p2().x() -
- quad->shared_quad_state->quad_layer_bounds.width()) <
+ quad->shared_quad_state->quad_layer_rect.width()) <
kAntiAliasingEpsilon &&
std::abs(clip_region->p3().x() -
- quad->shared_quad_state->quad_layer_bounds.width()) <
+ quad->shared_quad_state->quad_layer_rect.width()) <
kAntiAliasingEpsilon;
}
} // anonymous namespace
@@ -1890,7 +1897,8 @@ void GLRenderer::DrawContentQuadAA(const ContentDrawQuadBase* quad,
float vertex_tex_scale_y = tile_rect.height() / clamp_geom_rect.height();
TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
- gl_, &highp_threshold_cache_, highp_threshold_min_, quad->texture_size);
+ gl_, &highp_threshold_cache_, settings_->highp_threshold_min,
+ quad->texture_size);
auto local_quad = gfx::QuadF(gfx::RectF(tile_rect));
float edge[24];
@@ -1991,7 +1999,8 @@ void GLRenderer::DrawContentQuadNoAA(const ContentDrawQuadBase* quad,
}
TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
- gl_, &highp_threshold_cache_, highp_threshold_min_, quad->texture_size);
+ gl_, &highp_threshold_cache_, settings_->highp_threshold_min,
+ quad->texture_size);
SetUseProgram(
ProgramKey::Tile(tex_coord_precision, sampler, NO_AA,
@@ -2051,7 +2060,7 @@ void GLRenderer::DrawYUVVideoQuad(const YUVVideoDrawQuad* quad,
SetBlendEnabled(quad->ShouldDrawWithBlending());
TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
- gl_, &highp_threshold_cache_, highp_threshold_min_,
+ gl_, &highp_threshold_cache_, settings_->highp_threshold_min,
quad->shared_quad_state->visible_quad_layer_rect.bottom_right());
YUVAlphaTextureMode alpha_texture_mode = quad->a_plane_resource_id()
? YUV_HAS_ALPHA_TEXTURE
@@ -2222,7 +2231,7 @@ void GLRenderer::DrawStreamVideoQuad(const StreamVideoDrawQuad* quad,
.egl_image_external);
TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
- gl_, &highp_threshold_cache_, highp_threshold_min_,
+ gl_, &highp_threshold_cache_, settings_->highp_threshold_min,
quad->shared_quad_state->visible_quad_layer_rect.bottom_right());
ResourceProvider::ScopedReadLockGL lock(resource_provider_,
@@ -2360,7 +2369,7 @@ void GLRenderer::EnqueueTextureQuad(const TextureDrawQuad* quad,
}
TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
- gl_, &highp_threshold_cache_, highp_threshold_min_,
+ gl_, &highp_threshold_cache_, settings_->highp_threshold_min,
quad->shared_quad_state->visible_quad_layer_rect.bottom_right());
ResourceProvider::ScopedReadLockGL lock(resource_provider_,
@@ -2830,7 +2839,6 @@ void GLRenderer::FinishedReadback(unsigned source_buffer,
if (src_pixels) {
bitmap.reset(new SkBitmap);
bitmap->allocN32Pixels(size.width(), size.height());
- std::unique_ptr<SkAutoLockPixels> lock(new SkAutoLockPixels(*bitmap));
uint8_t* dest_pixels = static_cast<uint8_t*>(bitmap->getPixels());
size_t row_bytes = size.width() * 4;
@@ -3230,15 +3238,19 @@ void GLRenderer::ScheduleDCLayers() {
current_frame()->dc_layer_overlay_list) {
DCHECK(!dc_layer_overlay.rpdq);
- unsigned texture_id = 0;
+ int i = 0;
+ unsigned texture_ids[DrawQuad::Resources::kMaxResourceIdCount] = {};
+ int ids_to_send = 0;
+
for (const auto& contents_resource_id : dc_layer_overlay.resources) {
if (contents_resource_id) {
pending_overlay_resources_.push_back(
base::MakeUnique<ResourceProvider::ScopedReadLockGL>(
resource_provider_, contents_resource_id));
- if (!texture_id)
- texture_id = pending_overlay_resources_.back()->texture_id();
+ texture_ids[i] = pending_overlay_resources_.back()->texture_id();
+ ids_to_send = i + 1;
}
+ i++;
}
GLfloat contents_rect[4] = {
dc_layer_overlay.contents_rect.x(), dc_layer_overlay.contents_rect.y(),
@@ -3266,9 +3278,10 @@ void GLRenderer::ScheduleDCLayers() {
dc_layer_overlay.shared_state->opacity, is_clipped, clip_rect,
z_order, transform);
}
- gl_->ScheduleDCLayerCHROMIUM(
- texture_id, contents_rect, dc_layer_overlay.background_color,
- dc_layer_overlay.edge_aa_mask, bounds_rect, filter);
+ gl_->ScheduleDCLayerCHROMIUM(ids_to_send, texture_ids, contents_rect,
+ dc_layer_overlay.background_color,
+ dc_layer_overlay.edge_aa_mask, bounds_rect,
+ filter);
}
// Take the number of copied render passes in this frame, and use 3 times that
@@ -3450,7 +3463,8 @@ void GLRenderer::ScheduleRenderPassDrawQuad(
if (!overlay_resource_pool_) {
overlay_resource_pool_ = ResourcePool::CreateForGpuMemoryBufferResources(
resource_provider_, base::ThreadTaskRunnerHandle::Get().get(),
- gfx::BufferUsage::SCANOUT, base::TimeDelta::FromSeconds(3));
+ gfx::BufferUsage::SCANOUT, base::TimeDelta::FromSeconds(3),
+ settings_->disallow_non_exact_resource_reuse);
}
Resource* resource = nullptr;
diff --git a/chromium/cc/output/gl_renderer.h b/chromium/cc/output/gl_renderer.h
index 3562271d64c..e00b475fcd7 100644
--- a/chromium/cc/output/gl_renderer.h
+++ b/chromium/cc/output/gl_renderer.h
@@ -6,6 +6,7 @@
#define CC_OUTPUT_GL_RENDERER_H_
#include <deque>
+#include <unordered_map>
#include <vector>
#include "base/cancelable_callback.h"
@@ -51,8 +52,7 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
GLRenderer(const RendererSettings* settings,
OutputSurface* output_surface,
ResourceProvider* resource_provider,
- TextureMailboxDeleter* texture_mailbox_deleter,
- int highp_threshold_min);
+ TextureMailboxDeleter* texture_mailbox_deleter);
~GLRenderer() override;
bool use_swap_with_bounds() const { return use_swap_with_bounds_; }
@@ -322,7 +322,6 @@ class CC_EXPORT GLRenderer : public DirectRenderer {
bool blend_shadow_ = false;
const Program* current_program_ = nullptr;
TexturedQuadDrawCache draw_cache_;
- int highp_threshold_min_ = 0;
int highp_threshold_cache_ = 0;
struct PendingAsyncReadPixels;
diff --git a/chromium/cc/output/gl_renderer_unittest.cc b/chromium/cc/output/gl_renderer_unittest.cc
index ff42c7e6d07..f5802441730 100644
--- a/chromium/cc/output/gl_renderer_unittest.cc
+++ b/chromium/cc/output/gl_renderer_unittest.cc
@@ -374,7 +374,7 @@ class FakeRendererGL : public GLRenderer {
FakeRendererGL(const RendererSettings* settings,
OutputSurface* output_surface,
ResourceProvider* resource_provider)
- : GLRenderer(settings, output_surface, resource_provider, nullptr, 0) {}
+ : GLRenderer(settings, output_surface, resource_provider, nullptr) {}
FakeRendererGL(const RendererSettings* settings,
OutputSurface* output_surface,
@@ -383,8 +383,7 @@ class FakeRendererGL : public GLRenderer {
: GLRenderer(settings,
output_surface,
resource_provider,
- texture_mailbox_deleter,
- 0) {}
+ texture_mailbox_deleter) {}
void SetOverlayProcessor(OverlayProcessor* processor) {
overlay_processor_.reset(processor);
@@ -1977,7 +1976,7 @@ TEST_F(GLRendererTest, OverlaySyncTokensAreProcessed) {
TextureDrawQuad* overlay_quad =
root_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
SharedQuadState* shared_state = root_pass->CreateAndAppendSharedQuadState();
- shared_state->SetAll(gfx::Transform(), viewport_size,
+ shared_state->SetAll(gfx::Transform(), gfx::Rect(viewport_size),
gfx::Rect(viewport_size), gfx::Rect(viewport_size),
false, 1, SkBlendMode::kSrcOver, 0);
overlay_quad->SetNew(shared_state, gfx::Rect(viewport_size),
@@ -2179,7 +2178,7 @@ TEST_F(GLRendererTest, DCLayerOverlaySwitch) {
gfx::RectF tex_coord_rect(0, 0, 1, 1);
SharedQuadState* shared_state =
root_pass->CreateAndAppendSharedQuadState();
- shared_state->SetAll(gfx::Transform(), rect.size(), rect, rect, false, 1,
+ shared_state->SetAll(gfx::Transform(), rect, rect, rect, false, 1,
SkBlendMode::kSrcOver, 0);
YUVVideoDrawQuad* quad =
root_pass->CreateAndAppendDrawQuad<YUVVideoDrawQuad>();
@@ -2237,9 +2236,8 @@ class GLRendererWithMockContextTest : public ::testing::Test {
output_surface_->BindToClient(&output_surface_client_);
resource_provider_ = FakeResourceProvider::Create(
output_surface_->context_provider(), nullptr);
- renderer_ =
- base::MakeUnique<GLRenderer>(&settings_, output_surface_.get(),
- resource_provider_.get(), nullptr, 0);
+ renderer_ = base::MakeUnique<GLRenderer>(&settings_, output_surface_.get(),
+ resource_provider_.get(), nullptr);
renderer_->Initialize();
}
diff --git a/chromium/cc/output/overlay_processor.cc b/chromium/cc/output/overlay_processor.cc
index 594111bd786..bd3097fc375 100644
--- a/chromium/cc/output/overlay_processor.cc
+++ b/chromium/cc/output/overlay_processor.cc
@@ -62,8 +62,9 @@ gfx::Rect OverlayProcessor::GetAndResetOverlayDamage() {
bool OverlayProcessor::ProcessForCALayers(
ResourceProvider* resource_provider,
RenderPass* render_pass,
- const RenderPassFilterList& render_pass_filters,
- const RenderPassFilterList& render_pass_background_filters,
+ const base::flat_map<int, FilterOperations*>& render_pass_filters,
+ const base::flat_map<int, FilterOperations*>&
+ render_pass_background_filters,
OverlayCandidateList* overlay_candidates,
CALayerOverlayList* ca_layer_overlays,
gfx::Rect* damage_rect) {
@@ -90,8 +91,9 @@ bool OverlayProcessor::ProcessForCALayers(
bool OverlayProcessor::ProcessForDCLayers(
ResourceProvider* resource_provider,
RenderPass* render_pass,
- const RenderPassFilterList& render_pass_filters,
- const RenderPassFilterList& render_pass_background_filters,
+ const base::flat_map<int, FilterOperations*>& render_pass_filters,
+ const base::flat_map<int, FilterOperations*>&
+ render_pass_background_filters,
OverlayCandidateList* overlay_candidates,
DCLayerOverlayList* dc_layer_overlays,
gfx::Rect* damage_rect) {
@@ -111,8 +113,9 @@ bool OverlayProcessor::ProcessForDCLayers(
void OverlayProcessor::ProcessForOverlays(
ResourceProvider* resource_provider,
RenderPass* render_pass,
- const RenderPassFilterList& render_pass_filters,
- const RenderPassFilterList& render_pass_background_filters,
+ const base::flat_map<int, FilterOperations*>& render_pass_filters,
+ const base::flat_map<int, FilterOperations*>&
+ render_pass_background_filters,
OverlayCandidateList* candidates,
CALayerOverlayList* ca_layer_overlays,
DCLayerOverlayList* dc_layer_overlays,
@@ -125,14 +128,16 @@ void OverlayProcessor::ProcessForOverlays(
SendPromotionHintsBeforeReturning notifier(resource_provider, candidates);
#endif
+ // Reset |previous_frame_underlay_rect_| in case UpdateDamageRect() not being
+ // invoked.
+ const gfx::Rect previous_frame_underlay_rect = previous_frame_underlay_rect_;
+ previous_frame_underlay_rect_ = gfx::Rect();
+
// If we have any copy requests, we can't remove any quads for overlays or
// CALayers because the framebuffer would be missing the removed quads'
// contents.
if (!render_pass->copy_requests.empty()) {
dc_processor_.ClearOverlayState();
- // If overlay processing was skipped for a frame there's no way to be sure
- // of the state of the previous frame, so reset.
- previous_frame_underlay_rect_ = gfx::Rect();
return;
}
@@ -155,7 +160,7 @@ void OverlayProcessor::ProcessForOverlays(
content_bounds))
continue;
- UpdateDamageRect(candidates, damage_rect);
+ UpdateDamageRect(candidates, previous_frame_underlay_rect, damage_rect);
return;
}
}
@@ -168,8 +173,10 @@ void OverlayProcessor::ProcessForOverlays(
// not to swap the framebuffer there will still be a transparent hole in the
// previous frame. This only handles the common case of a single underlay quad
// for fullscreen video.
-void OverlayProcessor::UpdateDamageRect(OverlayCandidateList* candidates,
- gfx::Rect* damage_rect) {
+void OverlayProcessor::UpdateDamageRect(
+ OverlayCandidateList* candidates,
+ const gfx::Rect& previous_frame_underlay_rect,
+ gfx::Rect* damage_rect) {
gfx::Rect output_surface_overlay_damage_rect;
gfx::Rect this_frame_underlay_rect;
for (const OverlayCandidate& overlay : *candidates) {
@@ -186,7 +193,7 @@ void OverlayProcessor::UpdateDamageRect(OverlayCandidateList* candidates,
}
}
- if (this_frame_underlay_rect == previous_frame_underlay_rect_)
+ if (this_frame_underlay_rect == previous_frame_underlay_rect)
damage_rect->Subtract(this_frame_underlay_rect);
previous_frame_underlay_rect_ = this_frame_underlay_rect;
diff --git a/chromium/cc/output/overlay_processor.h b/chromium/cc/output/overlay_processor.h
index a00574e45c1..6262893755b 100644
--- a/chromium/cc/output/overlay_processor.h
+++ b/chromium/cc/output/overlay_processor.h
@@ -7,6 +7,7 @@
#include <memory>
+#include "base/containers/flat_map.h"
#include "base/macros.h"
#include "cc/cc_export.h"
#include "cc/output/ca_layer_overlay.h"
@@ -46,8 +47,9 @@ class CC_EXPORT OverlayProcessor {
void ProcessForOverlays(
ResourceProvider* resource_provider,
RenderPass* root_render_pass,
- const RenderPassFilterList& render_pass_filters,
- const RenderPassFilterList& render_pass_background_filters,
+ const base::flat_map<int, FilterOperations*>& render_pass_filters,
+ const base::flat_map<int, FilterOperations*>&
+ render_pass_background_filters,
OverlayCandidateList* overlay_candidates,
CALayerOverlayList* ca_layer_overlays,
DCLayerOverlayList* dc_layer_overlays,
@@ -64,21 +66,24 @@ class CC_EXPORT OverlayProcessor {
bool ProcessForCALayers(
ResourceProvider* resource_provider,
RenderPass* render_pass,
- const RenderPassFilterList& render_pass_filters,
- const RenderPassFilterList& render_pass_background_filters,
+ const base::flat_map<int, FilterOperations*>& render_pass_filters,
+ const base::flat_map<int, FilterOperations*>&
+ render_pass_background_filters,
OverlayCandidateList* overlay_candidates,
CALayerOverlayList* ca_layer_overlays,
gfx::Rect* damage_rect);
bool ProcessForDCLayers(
ResourceProvider* resource_provider,
RenderPass* render_pass,
- const RenderPassFilterList& render_pass_filters,
- const RenderPassFilterList& render_pass_background_filters,
+ const base::flat_map<int, FilterOperations*>& render_pass_filters,
+ const base::flat_map<int, FilterOperations*>&
+ render_pass_background_filters,
OverlayCandidateList* overlay_candidates,
DCLayerOverlayList* dc_layer_overlays,
gfx::Rect* damage_rect);
// Update |damage_rect| by removing damage casued by |candidates|.
void UpdateDamageRect(OverlayCandidateList* candidates,
+ const gfx::Rect& previous_frame_underlay_rect,
gfx::Rect* damage_rect);
DCLayerOverlayProcessor dc_processor_;
diff --git a/chromium/cc/output/overlay_strategy_fullscreen.cc b/chromium/cc/output/overlay_strategy_fullscreen.cc
index 2dd3e474268..e9401ec25c1 100644
--- a/chromium/cc/output/overlay_strategy_fullscreen.cc
+++ b/chromium/cc/output/overlay_strategy_fullscreen.cc
@@ -47,10 +47,6 @@ bool OverlayStrategyFullscreen::Attempt(
return false;
}
- if (candidate.transform != gfx::OVERLAY_TRANSFORM_NONE) {
- return false;
- }
-
if (!candidate.display_rect.origin().IsOrigin() ||
gfx::ToRoundedSize(candidate.display_rect.size()) !=
render_pass->output_rect.size() ||
diff --git a/chromium/cc/output/overlay_strategy_single_on_top.cc b/chromium/cc/output/overlay_strategy_single_on_top.cc
index 0cc5d998564..8cfda2864da 100644
--- a/chromium/cc/output/overlay_strategy_single_on_top.cc
+++ b/chromium/cc/output/overlay_strategy_single_on_top.cc
@@ -37,8 +37,6 @@ bool OverlayStrategySingleOnTop::Attempt(
for (auto it = quad_list->begin(); it != quad_list->end(); ++it) {
OverlayCandidate candidate;
if (OverlayCandidate::FromDrawQuad(resource_provider, *it, &candidate) &&
- // TODO(dcastagna): Remove this once drm platform supports transforms.
- candidate.transform == gfx::OVERLAY_TRANSFORM_NONE &&
!OverlayCandidate::IsOccluded(candidate, quad_list->cbegin(), it)) {
// We currently reject quads with alpha that do not request alpha blending
// since the alpha channel might not be set to 1 and we're not disabling
diff --git a/chromium/cc/output/overlay_unittest.cc b/chromium/cc/output/overlay_unittest.cc
index 9c077e90564..3a6156455b7 100644
--- a/chromium/cc/output/overlay_unittest.cc
+++ b/chromium/cc/output/overlay_unittest.cc
@@ -7,6 +7,7 @@
#include <utility>
#include <vector>
+#include "base/containers/flat_map.h"
#include "base/memory/ptr_util.h"
#include "base/test/scoped_feature_list.h"
#include "cc/base/filter_operation.h"
@@ -417,8 +418,8 @@ static void CompareRenderPassLists(const RenderPassList& expected_list,
exp_iter != expected->quad_list.cend();
++exp_iter, ++act_iter) {
EXPECT_EQ(exp_iter->rect.ToString(), act_iter->rect.ToString());
- EXPECT_EQ(exp_iter->shared_quad_state->quad_layer_bounds.ToString(),
- act_iter->shared_quad_state->quad_layer_bounds.ToString());
+ EXPECT_EQ(exp_iter->shared_quad_state->quad_layer_rect.ToString(),
+ act_iter->shared_quad_state->quad_layer_rect.ToString());
}
}
}
@@ -502,8 +503,8 @@ TEST_F(FullscreenOverlayTest, SuccessfulOverlay) {
// Check for potential candidates.
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -528,8 +529,8 @@ TEST_F(FullscreenOverlayTest, AlphaFail) {
// Check for potential candidates.
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -551,8 +552,8 @@ TEST_F(FullscreenOverlayTest, ResourceSizeInPixelsFail) {
// Check for potential candidates.
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -578,8 +579,8 @@ TEST_F(FullscreenOverlayTest, OnTopFail) {
// Check for potential candidates.
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -601,8 +602,8 @@ TEST_F(FullscreenOverlayTest, NotCoveringFullscreenFail) {
// Check for potential candidates.
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -631,8 +632,8 @@ TEST_F(FullscreenOverlayTest, RemoveFullscreenQuadFromQuadList) {
// Check for potential candidates.
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -661,8 +662,8 @@ TEST_F(SingleOverlayOnTopTest, SuccessfulOverlay) {
// Check for potential candidates.
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -709,8 +710,8 @@ TEST_F(SingleOverlayOnTopTest, PrioritizeBiggerOne) {
// Check for potential candidates.
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -750,8 +751,8 @@ TEST_F(SingleOverlayOnTopTest, DamageRect) {
output_surface_plane.overlay_handled = true;
candidate_list.push_back(output_surface_plane);
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -773,8 +774,8 @@ TEST_F(SingleOverlayOnTopTest, NoCandidates) {
RenderPass::CopyAll(pass_list, &original_pass_list);
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass_list.back().get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -802,8 +803,8 @@ TEST_F(SingleOverlayOnTopTest, OccludedCandidates) {
RenderPass::CopyAll(pass_list, &original_pass_list);
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass_list.back().get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -828,8 +829,8 @@ TEST_F(SingleOverlayOnTopTest, MultipleRenderPasses) {
// Check for potential candidates.
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -847,8 +848,8 @@ TEST_F(SingleOverlayOnTopTest, AcceptBlending) {
quad->opaque_rect = gfx::Rect(0, 0, 0, 0);
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
damage_rect_ = quad->rect;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
@@ -867,8 +868,8 @@ TEST_F(SingleOverlayOnTopTest, RejectBackgroundColor) {
quad->background_color = SK_ColorBLACK;
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -884,8 +885,8 @@ TEST_F(SingleOverlayOnTopTest, RejectBlendMode) {
pass->shared_quad_state_list.back()->blend_mode = SkBlendMode::kScreen;
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -901,8 +902,8 @@ TEST_F(SingleOverlayOnTopTest, RejectOpacity) {
pass->shared_quad_state_list.back()->opacity = 0.5f;
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -919,8 +920,8 @@ TEST_F(SingleOverlayOnTopTest, RejectNonAxisAlignedTransform) {
->quad_to_target_transform.RotateAboutXAxis(45.f);
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -937,8 +938,8 @@ TEST_F(SingleOverlayOnTopTest, AllowClipped) {
pass->shared_quad_state_list.back()->clip_rect = kOverlayClipRect;
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -956,8 +957,8 @@ TEST_F(UnderlayTest, AllowVerticalFlip) {
pass->shared_quad_state_list.back()->quad_to_target_transform.Scale(2.0f,
-1.0f);
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -978,8 +979,8 @@ TEST_F(UnderlayTest, AllowHorizontalFlip) {
2.0f);
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -998,8 +999,8 @@ TEST_F(SingleOverlayOnTopTest, AllowPositiveScaleTransform) {
pass->shared_quad_state_list.back()->quad_to_target_transform.Scale(2.0f,
1.0f);
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -1007,23 +1008,23 @@ TEST_F(SingleOverlayOnTopTest, AllowPositiveScaleTransform) {
EXPECT_EQ(1U, candidate_list.size());
}
-TEST_F(SingleOverlayOnTopTest, RejectTransform) {
+TEST_F(SingleOverlayOnTopTest, AcceptMirrorYTransform) {
gfx::Rect rect = kOverlayRect;
rect.Offset(0, -rect.height());
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateCandidateQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(), rect);
- pass->shared_quad_state_list.back()
- ->quad_to_target_transform.RotateAboutZAxis(90.f);
+ pass->shared_quad_state_list.back()->quad_to_target_transform.Scale(1.f,
+ -1.f);
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
&damage_rect_, &content_bounds_);
- ASSERT_EQ(0U, candidate_list.size());
+ ASSERT_EQ(1U, candidate_list.size());
}
TEST_F(UnderlayTest, Allow90DegreeRotation) {
@@ -1036,8 +1037,8 @@ TEST_F(UnderlayTest, Allow90DegreeRotation) {
->quad_to_target_transform.RotateAboutZAxis(90.f);
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -1056,8 +1057,8 @@ TEST_F(UnderlayTest, Allow180DegreeRotation) {
->quad_to_target_transform.RotateAboutZAxis(180.f);
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -1076,8 +1077,8 @@ TEST_F(UnderlayTest, Allow270DegreeRotation) {
->quad_to_target_transform.RotateAboutZAxis(270.f);
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -1100,8 +1101,8 @@ TEST_F(SingleOverlayOnTopTest, AllowNotTopIfNotOccluded) {
kOverlayBottomRightRect);
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -1124,8 +1125,8 @@ TEST_F(SingleOverlayOnTopTest, AllowTransparentOnTop) {
kOverlayBottomRightRect);
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -1146,8 +1147,8 @@ TEST_F(SingleOverlayOnTopTest, AllowTransparentColorOnTop) {
kOverlayBottomRightRect);
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -1167,8 +1168,8 @@ TEST_F(SingleOverlayOnTopTest, RejectOpaqueColorOnTop) {
kOverlayBottomRightRect);
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -1186,8 +1187,8 @@ TEST_F(SingleOverlayOnTopTest, RejectTransparentColorOnTopWithoutBlending) {
kOverlayBottomRightRect);
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -1202,8 +1203,8 @@ TEST_F(SingleOverlayOnTopTest, RejectVideoSwapTransform) {
pass.get(), kSwapTransform);
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -1218,8 +1219,8 @@ TEST_F(UnderlayTest, AllowVideoXMirrorTransform) {
pass.get(), kXMirrorTransform);
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -1234,8 +1235,8 @@ TEST_F(UnderlayTest, AllowVideoBothMirrorTransform) {
pass.get(), kBothMirrorTransform);
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -1250,8 +1251,8 @@ TEST_F(UnderlayTest, AllowVideoNormalTransform) {
pass.get(), kNormalTransform);
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -1266,8 +1267,8 @@ TEST_F(SingleOverlayOnTopTest, AllowVideoYMirrorTransform) {
pass.get(), kYMirrorTransform);
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -1287,8 +1288,8 @@ TEST_F(UnderlayTest, OverlayLayerUnderMainLayer) {
kOverlayBottomRightRect);
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -1310,8 +1311,8 @@ TEST_F(UnderlayTest, AllowOnTop) {
pass->shared_quad_state_list.back(), pass.get());
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -1332,8 +1333,8 @@ TEST_F(UnderlayTest, InitialUnderlayDamageNotSubtracted) {
damage_rect_ = kOverlayRect;
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -1358,8 +1359,8 @@ TEST_F(UnderlayTest, DamageSubtractedForConsecutiveIdenticalUnderlays) {
pass->shared_quad_state_list.back(), pass.get());
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -1388,8 +1389,8 @@ TEST_F(UnderlayTest, DamageNotSubtractedForNonIdenticalConsecutiveUnderlays) {
damage_rect_ = overlay_rects[i];
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -1399,6 +1400,38 @@ TEST_F(UnderlayTest, DamageNotSubtractedForNonIdenticalConsecutiveUnderlays) {
}
}
+// Underlay damage can only be subtracted if the previous frame's underlay
+// exists.
+TEST_F(UnderlayTest, DamageNotSubtractedForNonConsecutiveIdenticalUnderlays) {
+ bool has_fullscreen_candidate[] = {true, false, true};
+
+ for (int i = 0; i < 3; ++i) {
+ std::unique_ptr<RenderPass> pass = CreateRenderPass();
+
+ if (has_fullscreen_candidate[i]) {
+ CreateFullscreenCandidateQuad(resource_provider_.get(),
+ pass->shared_quad_state_list.back(),
+ pass.get());
+ }
+
+ damage_rect_ = kOverlayRect;
+
+ // Add something behind it.
+ CreateFullscreenOpaqueQuad(resource_provider_.get(),
+ pass->shared_quad_state_list.back(), pass.get());
+
+ OverlayCandidateList candidate_list;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
+ overlay_processor_->ProcessForOverlays(
+ resource_provider_.get(), pass.get(), render_pass_filters,
+ render_pass_background_filters, &candidate_list, nullptr, nullptr,
+ &damage_rect_, &content_bounds_);
+ }
+
+ EXPECT_EQ(kOverlayRect, damage_rect_);
+}
+
TEST_F(UnderlayTest, DamageNotSubtractedWhenQuadsAboveOverlap) {
for (int i = 0; i < 2; ++i) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
@@ -1412,8 +1445,8 @@ TEST_F(UnderlayTest, DamageNotSubtractedWhenQuadsAboveOverlap) {
damage_rect_ = kOverlayRect;
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -1440,8 +1473,8 @@ TEST_F(UnderlayTest, DamageSubtractedWhenQuadsAboveDontOverlap) {
damage_rect_ = kOverlayBottomRightRect;
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -1459,8 +1492,8 @@ TEST_F(UnderlayCastTest, NoOverlayContentBounds) {
kOverlayTopLeftRect);
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -1475,8 +1508,8 @@ TEST_F(UnderlayCastTest, FullScreenOverlayContentBounds) {
kOverlayRect);
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -1505,8 +1538,8 @@ TEST_F(UnderlayCastTest, BlackOutsideOverlayContentBounds) {
SK_ColorBLACK);
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -1526,8 +1559,8 @@ TEST_F(UnderlayCastTest, OverlayOccludedContentBounds) {
kOverlayRect);
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -1550,8 +1583,8 @@ TEST_F(UnderlayCastTest, OverlayOccludedUnionContentBounds) {
kOverlayRect);
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -1580,8 +1613,8 @@ TEST_F(UnderlayCastTest, RoundOverlayContentBounds) {
gfx::Rect(0, 0, 10, 10), SK_ColorWHITE);
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -1611,8 +1644,8 @@ TEST_F(UnderlayCastTest, RoundContentBounds) {
gfx::Rect(0, 0, 255, 255), SK_ColorWHITE);
OverlayCandidateList candidate_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &candidate_list, nullptr, nullptr,
@@ -1645,8 +1678,8 @@ TEST_F(CALayerOverlayTest, AllowNonAxisAlignedTransform) {
gfx::Rect damage_rect;
CALayerOverlayList ca_layer_list;
OverlayCandidateList overlay_list(BackbufferOverlayList(pass.get()));
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &overlay_list, &ca_layer_list, nullptr,
@@ -1668,8 +1701,8 @@ TEST_F(CALayerOverlayTest, ThreeDTransform) {
gfx::Rect damage_rect;
CALayerOverlayList ca_layer_list;
OverlayCandidateList overlay_list(BackbufferOverlayList(pass.get()));
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &overlay_list, &ca_layer_list, nullptr,
@@ -1694,8 +1727,8 @@ TEST_F(CALayerOverlayTest, AllowContainingClip) {
gfx::Rect damage_rect;
CALayerOverlayList ca_layer_list;
OverlayCandidateList overlay_list(BackbufferOverlayList(pass.get()));
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &overlay_list, &ca_layer_list, nullptr,
@@ -1717,8 +1750,8 @@ TEST_F(CALayerOverlayTest, NontrivialClip) {
gfx::Rect damage_rect;
CALayerOverlayList ca_layer_list;
OverlayCandidateList overlay_list(BackbufferOverlayList(pass.get()));
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &overlay_list, &ca_layer_list, nullptr,
@@ -1742,8 +1775,8 @@ TEST_F(CALayerOverlayTest, SkipTransparent) {
gfx::Rect damage_rect;
CALayerOverlayList ca_layer_list;
OverlayCandidateList overlay_list(BackbufferOverlayList(pass.get()));
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
render_pass_background_filters, &overlay_list, &ca_layer_list, nullptr,
@@ -1768,8 +1801,8 @@ TEST_F(DCLayerOverlayTest, AllowNonAxisAlignedTransform) {
gfx::Rect damage_rect;
DCLayerOverlayList dc_layer_list;
OverlayCandidateList overlay_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
damage_rect_ = gfx::Rect(1, 1, 10, 10);
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
@@ -1798,8 +1831,8 @@ TEST_F(DCLayerOverlayTest, Occluded) {
gfx::Rect damage_rect;
DCLayerOverlayList dc_layer_list;
OverlayCandidateList overlay_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
damage_rect_ = gfx::Rect(1, 1, 10, 10);
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
@@ -1825,8 +1858,8 @@ TEST_F(DCLayerOverlayTest, Occluded) {
gfx::Rect damage_rect;
DCLayerOverlayList dc_layer_list;
OverlayCandidateList overlay_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
damage_rect_ = gfx::Rect(1, 1, 10, 10);
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
@@ -1853,8 +1886,8 @@ TEST_F(DCLayerOverlayTest, DamageRect) {
gfx::Rect damage_rect;
DCLayerOverlayList dc_layer_list;
OverlayCandidateList overlay_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
damage_rect_ = gfx::Rect(1, 1, 10, 10);
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
@@ -1899,8 +1932,8 @@ TEST_F(DCLayerOverlayTest, ClipRect) {
DCLayerOverlayList dc_layer_list;
OverlayCandidateList overlay_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
damage_rect_ = gfx::Rect(1, 1, 10, 10);
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
@@ -1934,8 +1967,8 @@ TEST_F(DCLayerOverlayTest, TransparentOnTop) {
DCLayerOverlayList dc_layer_list;
OverlayCandidateList overlay_list;
- RenderPassFilterList render_pass_filters;
- RenderPassFilterList render_pass_background_filters;
+ base::flat_map<int, FilterOperations*> render_pass_filters;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters;
damage_rect_ = gfx::Rect(1, 1, 10, 10);
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), pass.get(), render_pass_filters,
@@ -1954,7 +1987,7 @@ class OverlayInfoRendererGL : public GLRenderer {
OverlayInfoRendererGL(const RendererSettings* settings,
OutputSurface* output_surface,
ResourceProvider* resource_provider)
- : GLRenderer(settings, output_surface, resource_provider, NULL, 0),
+ : GLRenderer(settings, output_surface, resource_provider, NULL),
expect_overlays_(false) {}
MOCK_METHOD2(DoDrawQuad,
@@ -2494,8 +2527,8 @@ class CALayerOverlayRPDQTest : public CALayerOverlayTest {
int render_pass_id_;
FilterOperations filters_;
FilterOperations background_filters_;
- RenderPassFilterList render_pass_filters_;
- RenderPassFilterList render_pass_background_filters_;
+ base::flat_map<int, FilterOperations*> render_pass_filters_;
+ base::flat_map<int, FilterOperations*> render_pass_background_filters_;
CALayerOverlayList ca_layer_list_;
OverlayCandidateList overlay_list_;
};
@@ -2521,7 +2554,7 @@ TEST_F(CALayerOverlayRPDQTest, RenderPassDrawQuadAllValidFilters) {
filters_.Append(FilterOperation::CreateBlurFilter(0.9f));
filters_.Append(FilterOperation::CreateDropShadowFilter(gfx::Point(10, 20),
1.0f, SK_ColorGREEN));
- render_pass_filters_.push_back(std::make_pair(render_pass_id_, &filters_));
+ render_pass_filters_[render_pass_id_] = &filters_;
quad_->SetNew(pass_->shared_quad_state_list.back(), kOverlayRect,
kOverlayRect, render_pass_id_, 0, gfx::RectF(), gfx::Size(),
gfx::Vector2dF(1, 1), gfx::PointF(), gfx::RectF());
@@ -2532,7 +2565,7 @@ TEST_F(CALayerOverlayRPDQTest, RenderPassDrawQuadAllValidFilters) {
TEST_F(CALayerOverlayRPDQTest, RenderPassDrawQuadOpacityFilterScale) {
filters_.Append(FilterOperation::CreateOpacityFilter(0.8f));
- render_pass_filters_.push_back(std::make_pair(render_pass_id_, &filters_));
+ render_pass_filters_[render_pass_id_] = &filters_;
quad_->SetNew(pass_->shared_quad_state_list.back(), kOverlayRect,
kOverlayRect, render_pass_id_, 0, gfx::RectF(), gfx::Size(),
gfx::Vector2dF(1, 2), gfx::PointF(), gfx::RectF());
@@ -2542,7 +2575,7 @@ TEST_F(CALayerOverlayRPDQTest, RenderPassDrawQuadOpacityFilterScale) {
TEST_F(CALayerOverlayRPDQTest, RenderPassDrawQuadBlurFilterScale) {
filters_.Append(FilterOperation::CreateBlurFilter(0.8f));
- render_pass_filters_.push_back(std::make_pair(render_pass_id_, &filters_));
+ render_pass_filters_[render_pass_id_] = &filters_;
quad_->SetNew(pass_->shared_quad_state_list.back(), kOverlayRect,
kOverlayRect, render_pass_id_, 0, gfx::RectF(), gfx::Size(),
gfx::Vector2dF(1, 2), gfx::PointF(), gfx::RectF());
@@ -2553,7 +2586,7 @@ TEST_F(CALayerOverlayRPDQTest, RenderPassDrawQuadBlurFilterScale) {
TEST_F(CALayerOverlayRPDQTest, RenderPassDrawQuadDropShadowFilterScale) {
filters_.Append(FilterOperation::CreateDropShadowFilter(gfx::Point(10, 20),
1.0f, SK_ColorGREEN));
- render_pass_filters_.push_back(std::make_pair(render_pass_id_, &filters_));
+ render_pass_filters_[render_pass_id_] = &filters_;
quad_->SetNew(pass_->shared_quad_state_list.back(), kOverlayRect,
kOverlayRect, render_pass_id_, 0, gfx::RectF(), gfx::Size(),
gfx::Vector2dF(1, 2), gfx::PointF(), gfx::RectF());
@@ -2563,8 +2596,7 @@ TEST_F(CALayerOverlayRPDQTest, RenderPassDrawQuadDropShadowFilterScale) {
TEST_F(CALayerOverlayRPDQTest, RenderPassDrawQuadBackgroundFilter) {
background_filters_.Append(FilterOperation::CreateGrayscaleFilter(0.1f));
- render_pass_background_filters_.push_back(
- std::make_pair(render_pass_id_, &background_filters_));
+ render_pass_background_filters_[render_pass_id_] = &background_filters_;
quad_->SetNew(pass_->shared_quad_state_list.back(), kOverlayRect,
kOverlayRect, render_pass_id_, 0, gfx::RectF(), gfx::Size(),
gfx::Vector2dF(1, 1), gfx::PointF(), gfx::RectF());
@@ -2582,7 +2614,7 @@ TEST_F(CALayerOverlayRPDQTest, RenderPassDrawQuadMask) {
TEST_F(CALayerOverlayRPDQTest, RenderPassDrawQuadUnsupportedFilter) {
filters_.Append(FilterOperation::CreateZoomFilter(0.9f, 1));
- render_pass_filters_.push_back(std::make_pair(render_pass_id_, &filters_));
+ render_pass_filters_[render_pass_id_] = &filters_;
quad_->SetNew(pass_->shared_quad_state_list.back(), kOverlayRect,
kOverlayRect, render_pass_id_, 0, gfx::RectF(), gfx::Size(),
gfx::Vector2dF(1, 1), gfx::PointF(), gfx::RectF());
diff --git a/chromium/cc/output/renderer_pixeltest.cc b/chromium/cc/output/renderer_pixeltest.cc
index 6fc2ac45522..e8215673291 100644
--- a/chromium/cc/output/renderer_pixeltest.cc
+++ b/chromium/cc/output/renderer_pixeltest.cc
@@ -62,7 +62,7 @@ SharedQuadState* CreateTestSharedQuadState(
gfx::Transform quad_to_target_transform,
const gfx::Rect& rect,
RenderPass* render_pass) {
- const gfx::Size layer_bounds = rect.size();
+ const gfx::Rect layer_rect = rect;
const gfx::Rect visible_layer_rect = rect;
const gfx::Rect clip_rect = rect;
const bool is_clipped = false;
@@ -70,9 +70,9 @@ SharedQuadState* CreateTestSharedQuadState(
const SkBlendMode blend_mode = SkBlendMode::kSrcOver;
int sorting_context_id = 0;
SharedQuadState* shared_state = render_pass->CreateAndAppendSharedQuadState();
- shared_state->SetAll(quad_to_target_transform, layer_bounds,
- visible_layer_rect, clip_rect, is_clipped, opacity,
- blend_mode, sorting_context_id);
+ shared_state->SetAll(quad_to_target_transform, layer_rect, visible_layer_rect,
+ clip_rect, is_clipped, opacity, blend_mode,
+ sorting_context_id);
return shared_state;
}
@@ -81,16 +81,16 @@ SharedQuadState* CreateTestSharedQuadStateClipped(
const gfx::Rect& rect,
const gfx::Rect& clip_rect,
RenderPass* render_pass) {
- const gfx::Size layer_bounds = rect.size();
+ const gfx::Rect layer_rect = rect;
const gfx::Rect visible_layer_rect = clip_rect;
const bool is_clipped = true;
const float opacity = 1.0f;
const SkBlendMode blend_mode = SkBlendMode::kSrcOver;
int sorting_context_id = 0;
SharedQuadState* shared_state = render_pass->CreateAndAppendSharedQuadState();
- shared_state->SetAll(quad_to_target_transform, layer_bounds,
- visible_layer_rect, clip_rect, is_clipped, opacity,
- blend_mode, sorting_context_id);
+ shared_state->SetAll(quad_to_target_transform, layer_rect, visible_layer_rect,
+ clip_rect, is_clipped, opacity, blend_mode,
+ sorting_context_id);
return shared_state;
}
@@ -1983,12 +1983,10 @@ TYPED_TEST(RendererPixelTest, RenderPassAndMaskWithPartialQuad) {
ResourceId mask_resource_id = this->resource_provider_->CreateResource(
mask_rect.size(), ResourceProvider::TEXTURE_HINT_IMMUTABLE, RGBA_8888,
gfx::ColorSpace());
- {
- SkAutoLockPixels lock(bitmap);
- this->resource_provider_->CopyToResource(
- mask_resource_id, reinterpret_cast<uint8_t*>(bitmap.getPixels()),
- mask_rect.size());
- }
+
+ this->resource_provider_->CopyToResource(
+ mask_resource_id, reinterpret_cast<uint8_t*>(bitmap.getPixels()),
+ mask_rect.size());
// This RenderPassDrawQuad does not include the full |viewport_rect| which is
// the size of the child render pass.
@@ -2078,12 +2076,10 @@ TYPED_TEST(RendererPixelTest, RenderPassAndMaskWithPartialQuad2) {
ResourceId mask_resource_id = this->resource_provider_->CreateResource(
mask_rect.size(), ResourceProvider::TEXTURE_HINT_IMMUTABLE, RGBA_8888,
gfx::ColorSpace());
- {
- SkAutoLockPixels lock(bitmap);
- this->resource_provider_->CopyToResource(
- mask_resource_id, reinterpret_cast<uint8_t*>(bitmap.getPixels()),
- mask_rect.size());
- }
+
+ this->resource_provider_->CopyToResource(
+ mask_resource_id, reinterpret_cast<uint8_t*>(bitmap.getPixels()),
+ mask_rect.size());
// This RenderPassDrawQuad does not include the full |viewport_rect| which is
// the size of the child render pass.
@@ -2806,25 +2802,19 @@ TYPED_TEST(RendererPixelTest, TileDrawQuadNearestNeighbor) {
SkBitmap bitmap;
bitmap.allocN32Pixels(2, 2);
- {
- SkAutoLockPixels lock(bitmap);
- SkCanvas canvas(bitmap);
- draw_point_color(&canvas, 0, 0, SK_ColorGREEN);
- draw_point_color(&canvas, 0, 1, SK_ColorBLUE);
- draw_point_color(&canvas, 1, 0, SK_ColorBLUE);
- draw_point_color(&canvas, 1, 1, SK_ColorGREEN);
- }
+ SkCanvas canvas(bitmap);
+ draw_point_color(&canvas, 0, 0, SK_ColorGREEN);
+ draw_point_color(&canvas, 0, 1, SK_ColorBLUE);
+ draw_point_color(&canvas, 1, 0, SK_ColorBLUE);
+ draw_point_color(&canvas, 1, 1, SK_ColorGREEN);
gfx::Size tile_size(2, 2);
ResourceId resource = this->resource_provider_->CreateResource(
tile_size, ResourceProvider::TEXTURE_HINT_IMMUTABLE, RGBA_8888,
gfx::ColorSpace());
- {
- SkAutoLockPixels lock(bitmap);
- this->resource_provider_->CopyToResource(
- resource, static_cast<uint8_t*>(bitmap.getPixels()), tile_size);
- }
+ this->resource_provider_->CopyToResource(
+ resource, static_cast<uint8_t*>(bitmap.getPixels()), tile_size);
int id = 1;
gfx::Transform transform_to_root;
@@ -2857,25 +2847,19 @@ TYPED_TEST(SoftwareRendererPixelTest, TextureDrawQuadNearestNeighbor) {
SkBitmap bitmap;
bitmap.allocN32Pixels(2, 2);
- {
- SkAutoLockPixels lock(bitmap);
- SkCanvas canvas(bitmap);
- draw_point_color(&canvas, 0, 0, SK_ColorGREEN);
- draw_point_color(&canvas, 0, 1, SK_ColorBLUE);
- draw_point_color(&canvas, 1, 0, SK_ColorBLUE);
- draw_point_color(&canvas, 1, 1, SK_ColorGREEN);
- }
+ SkCanvas canvas(bitmap);
+ draw_point_color(&canvas, 0, 0, SK_ColorGREEN);
+ draw_point_color(&canvas, 0, 1, SK_ColorBLUE);
+ draw_point_color(&canvas, 1, 0, SK_ColorBLUE);
+ draw_point_color(&canvas, 1, 1, SK_ColorGREEN);
gfx::Size tile_size(2, 2);
ResourceId resource = this->resource_provider_->CreateResource(
tile_size, ResourceProvider::TEXTURE_HINT_IMMUTABLE, RGBA_8888,
gfx::ColorSpace());
- {
- SkAutoLockPixels lock(bitmap);
- this->resource_provider_->CopyToResource(
- resource, static_cast<uint8_t*>(bitmap.getPixels()), tile_size);
- }
+ this->resource_provider_->CopyToResource(
+ resource, static_cast<uint8_t*>(bitmap.getPixels()), tile_size);
int id = 1;
gfx::Transform transform_to_root;
@@ -2910,7 +2894,6 @@ TYPED_TEST(SoftwareRendererPixelTest, TextureDrawQuadLinear) {
SkBitmap bitmap;
bitmap.allocN32Pixels(2, 2);
{
- SkAutoLockPixels lock(bitmap);
SkCanvas canvas(bitmap);
draw_point_color(&canvas, 0, 0, SK_ColorGREEN);
draw_point_color(&canvas, 0, 1, SK_ColorBLUE);
@@ -2923,11 +2906,8 @@ TYPED_TEST(SoftwareRendererPixelTest, TextureDrawQuadLinear) {
tile_size, ResourceProvider::TEXTURE_HINT_IMMUTABLE, RGBA_8888,
gfx::ColorSpace());
- {
- SkAutoLockPixels lock(bitmap);
- this->resource_provider_->CopyToResource(
- resource, static_cast<uint8_t*>(bitmap.getPixels()), tile_size);
- }
+ this->resource_provider_->CopyToResource(
+ resource, static_cast<uint8_t*>(bitmap.getPixels()), tile_size);
int id = 1;
gfx::Transform transform_to_root;
@@ -3286,12 +3266,10 @@ TEST_F(GLRendererPixelTest, TextureQuadBatching) {
ResourceId resource = this->resource_provider_->CreateResource(
mask_rect.size(), ResourceProvider::TEXTURE_HINT_IMMUTABLE, RGBA_8888,
gfx::ColorSpace());
- {
- SkAutoLockPixels lock(bitmap);
- this->resource_provider_->CopyToResource(
- resource, reinterpret_cast<uint8_t*>(bitmap.getPixels()),
- mask_rect.size());
- }
+
+ this->resource_provider_->CopyToResource(
+ resource, reinterpret_cast<uint8_t*>(bitmap.getPixels()),
+ mask_rect.size());
// Arbitrary dividing lengths to divide up the resource into 16 quads.
int widths[] = {
diff --git a/chromium/cc/output/renderer_settings.h b/chromium/cc/output/renderer_settings.h
index f6afb55467a..913aa2d3cfb 100644
--- a/chromium/cc/output/renderer_settings.h
+++ b/chromium/cc/output/renderer_settings.h
@@ -25,7 +25,6 @@ class CC_EXPORT RendererSettings {
bool partial_swap_enabled = false;
bool finish_rendering_on_resize = false;
bool should_clear_root_render_pass = true;
- bool disable_display_vsync = false;
bool release_overlay_resources_after_gpu_query = false;
bool gl_composited_texture_quad_border = false;
bool show_overdraw_feedback = false;
@@ -37,6 +36,11 @@ class CC_EXPORT RendererSettings {
bool use_gpu_memory_buffer_resources = false;
ResourceFormat preferred_tile_format;
BufferToTextureTargetMap buffer_to_texture_target_map;
+
+ // Determines whether we disallow non-exact matches when finding resources
+ // in ResourcePool. Only used for layout or pixel tests, as non-deterministic
+ // resource sizes can lead to floating point error and noise in these tests.
+ bool disallow_non_exact_resource_reuse = false;
};
} // namespace cc
diff --git a/chromium/cc/output/software_renderer.cc b/chromium/cc/output/software_renderer.cc
index 75dbff4a6e8..6fc30a038f0 100644
--- a/chromium/cc/output/software_renderer.cc
+++ b/chromium/cc/output/software_renderer.cc
@@ -99,19 +99,10 @@ bool SoftwareRenderer::FlippedFramebuffer() const {
void SoftwareRenderer::EnsureScissorTestEnabled() {
is_scissor_enabled_ = true;
- SetClipRect(scissor_rect_);
}
void SoftwareRenderer::EnsureScissorTestDisabled() {
- // There is no explicit notion of enabling/disabling scissoring in software
- // rendering, but the underlying effect we want is to clear any existing
- // clipRect on the current SkCanvas. This is done by setting clipRect to
- // the viewport's dimensions.
- if (!current_canvas_)
- return;
is_scissor_enabled_ = false;
- SkISize size = current_canvas_->getBaseLayerSize();
- SetClipRect(gfx::Rect(size.width(), size.height()));
}
void SoftwareRenderer::BindFramebufferToOutputSurface() {
@@ -140,7 +131,6 @@ bool SoftwareRenderer::BindFramebufferToTexture(
void SoftwareRenderer::SetScissorTestRect(const gfx::Rect& scissor_rect) {
is_scissor_enabled_ = true;
scissor_rect_ = scissor_rect;
- SetClipRect(scissor_rect);
}
void SoftwareRenderer::SetClipRect(const gfx::Rect& rect) {
@@ -149,16 +139,29 @@ void SoftwareRenderer::SetClipRect(const gfx::Rect& rect) {
// Skia applies the current matrix to clip rects so we reset it temporary.
SkMatrix current_matrix = current_canvas_->getTotalMatrix();
current_canvas_->resetMatrix();
- // TODO(fmalita) stop using kReplace (see crbug.com/673851)
- current_canvas_->clipRect(gfx::RectToSkRect(rect),
- SkClipOp::kReplace_deprecated);
+ // SetClipRect is assumed to be applied temporarily, on an
+ // otherwise-unclipped canvas.
+ DCHECK_EQ(current_canvas_->getDeviceClipBounds().width(),
+ current_canvas_->imageInfo().width());
+ DCHECK_EQ(current_canvas_->getDeviceClipBounds().height(),
+ current_canvas_->imageInfo().height());
+ current_canvas_->clipRect(gfx::RectToSkRect(rect));
current_canvas_->setMatrix(current_matrix);
}
void SoftwareRenderer::ClearCanvas(SkColor color) {
if (!current_canvas_)
return;
- current_canvas_->clear(color);
+
+ if (is_scissor_enabled_) {
+ // The same paint used by SkCanvas::clear, but applied to the scissor rect.
+ SkPaint clear_paint;
+ clear_paint.setColor(color);
+ clear_paint.setBlendMode(SkBlendMode::kSrc);
+ current_canvas_->drawRect(gfx::RectToSkRect(scissor_rect_), clear_paint);
+ } else {
+ current_canvas_->clear(color);
+ }
}
void SoftwareRenderer::ClearFramebuffer() {
@@ -208,11 +211,14 @@ void SoftwareRenderer::DoDrawQuad(const DrawQuad* quad,
const gfx::QuadF* draw_region) {
if (!current_canvas_)
return;
- if (draw_region) {
- current_canvas_->save();
- }
TRACE_EVENT0("cc", "SoftwareRenderer::DoDrawQuad");
+ bool do_save = draw_region || is_scissor_enabled_;
+ SkAutoCanvasRestore canvas_restore(current_canvas_, do_save);
+ if (is_scissor_enabled_) {
+ SetClipRect(scissor_rect_);
+ }
+
gfx::Transform quad_rect_matrix;
QuadRectTransform(&quad_rect_matrix,
quad->shared_quad_state->quad_to_target_transform,
@@ -298,9 +304,6 @@ void SoftwareRenderer::DoDrawQuad(const DrawQuad* quad,
}
current_canvas_->resetMatrix();
- if (draw_region) {
- current_canvas_->restore();
- }
}
void SoftwareRenderer::DrawDebugBorderQuad(const DebugBorderDrawQuad* quad) {
@@ -576,10 +579,11 @@ void SoftwareRenderer::CopyCurrentRenderPassToBitmap(
gfx::Rect window_copy_rect = MoveFromDrawToWindowSpace(copy_rect);
std::unique_ptr<SkBitmap> bitmap(new SkBitmap);
- bitmap->setInfo(SkImageInfo::MakeN32Premul(window_copy_rect.width(),
- window_copy_rect.height()));
- current_canvas_->readPixels(
- bitmap.get(), window_copy_rect.x(), window_copy_rect.y());
+ bitmap->allocPixels(SkImageInfo::MakeN32Premul(window_copy_rect.width(),
+ window_copy_rect.height()));
+ if (!current_canvas_->readPixels(*bitmap, window_copy_rect.x(),
+ window_copy_rect.y()))
+ bitmap->reset();
request->SendBitmapResult(std::move(bitmap));
}
@@ -654,9 +658,11 @@ sk_sp<SkImage> SoftwareRenderer::ApplyImageFilter(
SkBitmap SoftwareRenderer::GetBackdropBitmap(
const gfx::Rect& bounding_rect) const {
SkBitmap bitmap;
- bitmap.setInfo(SkImageInfo::MakeN32Premul(bounding_rect.width(),
- bounding_rect.height()));
- current_canvas_->readPixels(&bitmap, bounding_rect.x(), bounding_rect.y());
+ bitmap.allocPixels(SkImageInfo::MakeN32Premul(bounding_rect.width(),
+ bounding_rect.height()));
+ if (!current_canvas_->readPixels(bitmap, bounding_rect.x(),
+ bounding_rect.y()))
+ bitmap.reset();
return bitmap;
}
diff --git a/chromium/cc/output/software_renderer_unittest.cc b/chromium/cc/output/software_renderer_unittest.cc
index 15da1b622d1..19a68ca6340 100644
--- a/chromium/cc/output/software_renderer_unittest.cc
+++ b/chromium/cc/output/software_renderer_unittest.cc
@@ -27,6 +27,7 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/utils/SkNWayCanvas.h"
#include "ui/gfx/skia_util.h"
namespace cc {
@@ -104,7 +105,7 @@ TEST_F(SoftwareRendererTest, SolidColorQuad) {
gfx::Transform());
SharedQuadState* shared_quad_state =
root_render_pass->CreateAndAppendSharedQuadState();
- shared_quad_state->SetAll(gfx::Transform(), outer_size, outer_rect,
+ shared_quad_state->SetAll(gfx::Transform(), outer_rect, outer_rect,
outer_rect, false, 1.0, SkBlendMode::kSrcOver, 0);
SolidColorDrawQuad* inner_quad =
root_render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
@@ -170,7 +171,7 @@ TEST_F(SoftwareRendererTest, TileQuad) {
gfx::Transform());
SharedQuadState* shared_quad_state =
root_render_pass->CreateAndAppendSharedQuadState();
- shared_quad_state->SetAll(gfx::Transform(), outer_size, outer_rect,
+ shared_quad_state->SetAll(gfx::Transform(), outer_rect, outer_rect,
outer_rect, false, 1.0, SkBlendMode::kSrcOver, 0);
TileDrawQuad* inner_quad =
root_render_pass->CreateAndAppendDrawQuad<TileDrawQuad>();
@@ -230,7 +231,7 @@ TEST_F(SoftwareRendererTest, TileQuadVisibleRect) {
gfx::Transform());
SharedQuadState* shared_quad_state =
root_render_pass->CreateAndAppendSharedQuadState();
- shared_quad_state->SetAll(gfx::Transform(), tile_size, tile_rect, tile_rect,
+ shared_quad_state->SetAll(gfx::Transform(), tile_rect, tile_rect, tile_rect,
false, 1.0, SkBlendMode::kSrcOver, 0);
TileDrawQuad* quad =
root_render_pass->CreateAndAppendDrawQuad<TileDrawQuad>();
@@ -378,26 +379,45 @@ TEST_F(SoftwareRendererTest, RenderPassVisibleRect) {
interior_visible_rect.bottom() - 1));
}
+class ClipTrackingCanvas : public SkNWayCanvas {
+ public:
+ ClipTrackingCanvas(int width, int height) : SkNWayCanvas(width, height) {}
+ void onClipRect(const SkRect& rect,
+ SkClipOp op,
+ ClipEdgeStyle style) override {
+ last_clip_rect_ = rect;
+ SkNWayCanvas::onClipRect(rect, op, style);
+ }
+
+ SkRect last_clip_rect() const { return last_clip_rect_; }
+
+ private:
+ SkRect last_clip_rect_;
+};
+
class PartialSwapSoftwareOutputDevice : public SoftwareOutputDevice {
public:
// SoftwareOutputDevice overrides.
SkCanvas* BeginPaint(const gfx::Rect& damage_rect) override {
damage_rect_at_start_ = damage_rect;
- canvas_ = SoftwareOutputDevice::BeginPaint(damage_rect);
- return canvas_;
+ canvas_.reset(new ClipTrackingCanvas(viewport_pixel_size_.width(),
+ viewport_pixel_size_.height()));
+ canvas_->addCanvas(SoftwareOutputDevice::BeginPaint(damage_rect));
+ return canvas_.get();
}
+
void EndPaint() override {
- clip_rect_at_end_ = gfx::SkIRectToRect(canvas_->getDeviceClipBounds());
+ clip_rect_at_end_ = gfx::SkRectToRectF(canvas_->last_clip_rect());
SoftwareOutputDevice::EndPaint();
}
gfx::Rect damage_rect_at_start() const { return damage_rect_at_start_; }
- gfx::Rect clip_rect_at_end() const { return clip_rect_at_end_; }
+ gfx::RectF clip_rect_at_end() const { return clip_rect_at_end_; }
private:
- SkCanvas* canvas_ = nullptr;
+ std::unique_ptr<ClipTrackingCanvas> canvas_;
gfx::Rect damage_rect_at_start_;
- gfx::Rect clip_rect_at_end_;
+ gfx::RectF clip_rect_at_end_;
};
TEST_F(SoftwareRendererTest, PartialSwap) {
@@ -428,7 +448,7 @@ TEST_F(SoftwareRendererTest, PartialSwap) {
// The damage rect should be reported to the SoftwareOutputDevice.
EXPECT_EQ(gfx::Rect(2, 2, 3, 3), device->damage_rect_at_start());
// The SkCanvas should be clipped to the damage rect.
- EXPECT_EQ(gfx::Rect(2, 2, 3, 3), device->clip_rect_at_end());
+ EXPECT_EQ(gfx::RectF(2, 2, 3, 3), device->clip_rect_at_end());
}
} // namespace
diff --git a/chromium/cc/paint/BUILD.gn b/chromium/cc/paint/BUILD.gn
index c442f045829..7669b28f3a8 100644
--- a/chromium/cc/paint/BUILD.gn
+++ b/chromium/cc/paint/BUILD.gn
@@ -15,6 +15,8 @@ cc_component("paint") {
"compositing_display_item.h",
"discardable_image_map.cc",
"discardable_image_map.h",
+ "discardable_image_store.cc",
+ "discardable_image_store.h",
"display_item.h",
"display_item_list.cc",
"display_item_list.h",
@@ -32,11 +34,19 @@ cc_component("paint") {
"paint_canvas.cc",
"paint_canvas.h",
"paint_export.h",
+ "paint_flags.cc",
"paint_flags.h",
+ "paint_image.cc",
+ "paint_image.h",
+ "paint_op_buffer.cc",
+ "paint_op_buffer.h",
+ "paint_record.cc",
"paint_record.h",
"paint_recorder.cc",
"paint_recorder.h",
"paint_shader.h",
+ "record_paint_canvas.cc",
+ "record_paint_canvas.h",
"skia_paint_canvas.cc",
"skia_paint_canvas.h",
"transform_display_item.cc",
diff --git a/chromium/cc/paint/clip_display_item.h b/chromium/cc/paint/clip_display_item.h
index a969d48dd5b..6a5bf0cf694 100644
--- a/chromium/cc/paint/clip_display_item.h
+++ b/chromium/cc/paint/clip_display_item.h
@@ -26,7 +26,7 @@ class CC_PAINT_EXPORT ClipDisplayItem : public DisplayItem {
size_t ExternalMemoryUsage() const {
return rounded_clip_rects.capacity() * sizeof(rounded_clip_rects[0]);
}
- int ApproximateOpCount() const { return 1; }
+ int OpCount() const { return 1; }
const gfx::Rect clip_rect;
const std::vector<SkRRect> rounded_clip_rects;
@@ -38,7 +38,7 @@ class CC_PAINT_EXPORT EndClipDisplayItem : public DisplayItem {
EndClipDisplayItem();
~EndClipDisplayItem() override;
- int ApproximateOpCount() const { return 0; }
+ int OpCount() const { return 0; }
};
} // namespace cc
diff --git a/chromium/cc/paint/clip_path_display_item.h b/chromium/cc/paint/clip_path_display_item.h
index 54de9992233..960697dc62e 100644
--- a/chromium/cc/paint/clip_path_display_item.h
+++ b/chromium/cc/paint/clip_path_display_item.h
@@ -23,7 +23,7 @@ class CC_PAINT_EXPORT ClipPathDisplayItem : public DisplayItem {
// may well be shared anyway).
return 0;
}
- int ApproximateOpCount() const { return 1; }
+ int OpCount() const { return 1; }
const SkPath clip_path;
const bool antialias;
@@ -34,7 +34,7 @@ class CC_PAINT_EXPORT EndClipPathDisplayItem : public DisplayItem {
EndClipPathDisplayItem();
~EndClipPathDisplayItem() override;
- int ApproximateOpCount() const { return 0; }
+ int OpCount() const { return 0; }
};
} // namespace cc
diff --git a/chromium/cc/paint/compositing_display_item.h b/chromium/cc/paint/compositing_display_item.h
index 266ab4d2ea8..ba14de004b8 100644
--- a/chromium/cc/paint/compositing_display_item.h
+++ b/chromium/cc/paint/compositing_display_item.h
@@ -29,7 +29,7 @@ class CC_PAINT_EXPORT CompositingDisplayItem : public DisplayItem {
// TODO(pdr): Include color_filter's memory here.
return 0;
}
- int ApproximateOpCount() const { return 1; }
+ int OpCount() const { return 1; }
const uint8_t alpha;
const SkBlendMode xfermode;
@@ -44,7 +44,7 @@ class CC_PAINT_EXPORT EndCompositingDisplayItem : public DisplayItem {
EndCompositingDisplayItem();
~EndCompositingDisplayItem() override;
- int ApproximateOpCount() const { return 0; }
+ int OpCount() const { return 0; }
};
} // namespace cc
diff --git a/chromium/cc/paint/discardable_image_map.cc b/chromium/cc/paint/discardable_image_map.cc
index c1a3b57ccb5..4b6c5824089 100644
--- a/chromium/cc/paint/discardable_image_map.cc
+++ b/chromium/cc/paint/discardable_image_map.cc
@@ -9,260 +9,19 @@
#include <algorithm>
#include <limits>
-#include "base/containers/adapters.h"
#include "base/memory/ptr_util.h"
-#include "cc/base/math_util.h"
-#include "cc/paint/display_item_list.h"
-#include "third_party/skia/include/core/SkPath.h"
-#include "third_party/skia/include/utils/SkNWayCanvas.h"
-#include "ui/gfx/geometry/rect_conversions.h"
-#include "ui/gfx/skia_util.h"
+#include "cc/paint/discardable_image_store.h"
namespace cc {
-SkRect MapRect(const SkMatrix& matrix, const SkRect& src) {
- SkRect dst;
- matrix.mapRect(&dst, src);
- return dst;
-}
-
-// Returns a rect clamped to |max_size|. Note that |paint_rect| should intersect
-// or be contained by a rect defined by (0, 0) and |max_size|.
-gfx::Rect SafeClampPaintRectToSize(const SkRect& paint_rect,
- const gfx::Size& max_size) {
- // bounds_rect.x() + bounds_rect.width() (aka bounds_rect.right()) might
- // overflow integer bounds, so do custom intersect, since gfx::Rect::Intersect
- // uses bounds_rect.right().
- gfx::RectF bounds_rect = gfx::SkRectToRectF(paint_rect);
- float x_offset_if_negative = bounds_rect.x() < 0.f ? bounds_rect.x() : 0.f;
- float y_offset_if_negative = bounds_rect.y() < 0.f ? bounds_rect.y() : 0.f;
- bounds_rect.set_x(std::max(0.f, bounds_rect.x()));
- bounds_rect.set_y(std::max(0.f, bounds_rect.y()));
-
- // Verify that the rects intersect or that bound_rect is contained by
- // max_size.
- DCHECK_GE(bounds_rect.width(), -x_offset_if_negative);
- DCHECK_GE(bounds_rect.height(), -y_offset_if_negative);
- DCHECK_GE(max_size.width(), bounds_rect.x());
- DCHECK_GE(max_size.height(), bounds_rect.y());
-
- bounds_rect.set_width(std::min(bounds_rect.width() + x_offset_if_negative,
- max_size.width() - bounds_rect.x()));
- bounds_rect.set_height(std::min(bounds_rect.height() + y_offset_if_negative,
- max_size.height() - bounds_rect.y()));
- return gfx::ToEnclosingRect(bounds_rect);
-}
-
-namespace {
-
-// We're using an NWay canvas with no added canvases, so in effect
-// non-overridden functions are no-ops.
-class DiscardableImagesMetadataCanvas : public SkNWayCanvas {
- public:
- DiscardableImagesMetadataCanvas(
- int width,
- int height,
- std::vector<std::pair<DrawImage, gfx::Rect>>* image_set,
- std::unordered_map<ImageId, gfx::Rect>* image_id_to_rect)
- : SkNWayCanvas(width, height),
- image_set_(image_set),
- image_id_to_rect_(image_id_to_rect),
- canvas_bounds_(SkRect::MakeIWH(width, height)),
- canvas_size_(width, height) {}
-
- protected:
- // we need to "undo" the behavior of SkNWayCanvas, which will try to forward
- // it.
- void onDrawPicture(const SkPicture* picture,
- const SkMatrix* matrix,
- const SkPaint* paint) override {
- SkCanvas::onDrawPicture(picture, matrix, paint);
- }
-
- void onDrawImage(const SkImage* image,
- SkScalar x,
- SkScalar y,
- const SkPaint* paint) override {
- const SkMatrix& ctm = getTotalMatrix();
- AddImage(
- sk_ref_sp(image), SkRect::MakeIWH(image->width(), image->height()),
- MapRect(ctm, SkRect::MakeXYWH(x, y, image->width(), image->height())),
- ctm, paint);
- }
-
- void onDrawImageRect(const SkImage* image,
- const SkRect* src,
- const SkRect& dst,
- const SkPaint* paint,
- SrcRectConstraint) override {
- const SkMatrix& ctm = getTotalMatrix();
- SkRect src_storage;
- if (!src) {
- src_storage = SkRect::MakeIWH(image->width(), image->height());
- src = &src_storage;
- }
- SkMatrix matrix;
- matrix.setRectToRect(*src, dst, SkMatrix::kFill_ScaleToFit);
- matrix.preConcat(ctm);
- AddImage(sk_ref_sp(image), *src, MapRect(ctm, dst), matrix, paint);
- }
-
- void onDrawImageNine(const SkImage* image,
- const SkIRect& center,
- const SkRect& dst,
- const SkPaint* paint) override {
- // No cc embedder issues image nine calls.
- NOTREACHED();
- }
-
- void onDrawRect(const SkRect& r, const SkPaint& paint) override {
- AddPaintImage(r, paint);
- }
-
- void onDrawPath(const SkPath& path, const SkPaint& paint) override {
- AddPaintImage(path.getBounds(), paint);
- }
-
- void onDrawOval(const SkRect& r, const SkPaint& paint) override {
- AddPaintImage(r, paint);
- }
-
- void onDrawArc(const SkRect& r,
- SkScalar start_angle,
- SkScalar sweep_angle,
- bool use_center,
- const SkPaint& paint) override {
- AddPaintImage(r, paint);
- }
-
- void onDrawRRect(const SkRRect& rr, const SkPaint& paint) override {
- AddPaintImage(rr.rect(), paint);
- }
-
- SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override {
- saved_paints_.push_back(rec.fPaint ? *rec.fPaint : SkPaint());
- return SkNWayCanvas::getSaveLayerStrategy(rec);
- }
-
- void willSave() override {
- saved_paints_.push_back(SkPaint());
- return SkNWayCanvas::willSave();
- }
-
- void willRestore() override {
- DCHECK_GT(saved_paints_.size(), 0u);
- saved_paints_.pop_back();
- SkNWayCanvas::willRestore();
- }
-
- private:
- bool ComputePaintBounds(const SkRect& rect,
- const SkPaint* current_paint,
- SkRect* paint_bounds) {
- *paint_bounds = rect;
- if (current_paint) {
- if (!current_paint->canComputeFastBounds())
- return false;
- *paint_bounds =
- current_paint->computeFastBounds(*paint_bounds, paint_bounds);
- }
-
- for (const auto& paint : base::Reversed(saved_paints_)) {
- if (!paint.canComputeFastBounds())
- return false;
- *paint_bounds = paint.computeFastBounds(*paint_bounds, paint_bounds);
- }
-
- return true;
- }
-
- void AddImage(sk_sp<const SkImage> image,
- const SkRect& src_rect,
- const SkRect& rect,
- const SkMatrix& matrix,
- const SkPaint* paint) {
- if (!image->isLazyGenerated())
- return;
-
- SkRect paint_rect;
- bool computed_paint_bounds = ComputePaintBounds(rect, paint, &paint_rect);
- if (!computed_paint_bounds) {
- // TODO(vmpstr): UMA this case.
- paint_rect = canvas_bounds_;
- }
-
- if (!paint_rect.intersects(canvas_bounds_))
- return;
-
- SkFilterQuality filter_quality = kNone_SkFilterQuality;
- if (paint) {
- filter_quality = paint->getFilterQuality();
- }
-
- SkIRect src_irect;
- src_rect.roundOut(&src_irect);
- gfx::Rect image_rect = SafeClampPaintRectToSize(paint_rect, canvas_size_);
-
- // 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).
- image_rect.Inset(-1, -1);
-
- // The true target color space will be assigned when it is known, in
- // GetDiscardableImagesInRect.
- gfx::ColorSpace target_color_space;
-
- (*image_id_to_rect_)[image->uniqueID()].Union(image_rect);
- image_set_->push_back(
- std::make_pair(DrawImage(std::move(image), src_irect, filter_quality,
- matrix, target_color_space),
- image_rect));
- }
-
- // Currently this function only handles extracting images from SkImageShaders
- // embedded in SkPaints. Other embedded image cases, such as SkPictures,
- // are not yet handled.
- void AddPaintImage(const SkRect& rect, const SkPaint& paint) {
- SkShader* shader = paint.getShader();
- if (shader) {
- SkMatrix matrix;
- SkShader::TileMode xy[2];
- SkImage* image = shader->isAImage(&matrix, xy);
- if (image) {
- const SkMatrix& ctm = getTotalMatrix();
- matrix.postConcat(ctm);
- // TODO(ericrk): Handle cases where we only need a sub-rect from the
- // image. crbug.com/671821
- AddImage(sk_ref_sp(image), SkRect::MakeFromIRect(image->bounds()),
- MapRect(ctm, rect), matrix, &paint);
- }
- }
- }
-
- std::vector<std::pair<DrawImage, gfx::Rect>>* image_set_;
- std::unordered_map<ImageId, gfx::Rect>* image_id_to_rect_;
- const SkRect canvas_bounds_;
- const gfx::Size canvas_size_;
- std::vector<SkPaint> saved_paints_;
-};
-
-} // namespace
-
DiscardableImageMap::DiscardableImageMap() {}
DiscardableImageMap::~DiscardableImageMap() {}
-std::unique_ptr<SkCanvas> DiscardableImageMap::BeginGeneratingMetadata(
- const gfx::Size& bounds) {
+std::unique_ptr<DiscardableImageStore>
+DiscardableImageMap::BeginGeneratingMetadata(const gfx::Size& bounds) {
DCHECK(all_images_.empty());
- return base::MakeUnique<DiscardableImagesMetadataCanvas>(
+ return base::MakeUnique<DiscardableImageStore>(
bounds.width(), bounds.height(), &all_images_, &image_id_to_rect_);
}
@@ -278,16 +37,14 @@ void DiscardableImageMap::GetDiscardableImagesInRect(
float contents_scale,
const gfx::ColorSpace& target_color_space,
std::vector<DrawImage>* images) const {
- std::vector<size_t> indices;
- images_rtree_.Search(rect, &indices);
- for (size_t index : indices) {
+ for (size_t index : images_rtree_.Search(rect)) {
images->push_back(all_images_[index]
.first.ApplyScale(contents_scale)
.ApplyTargetColorSpace(target_color_space));
}
}
-gfx::Rect DiscardableImageMap::GetRectForImage(ImageId image_id) const {
+gfx::Rect DiscardableImageMap::GetRectForImage(PaintImage::Id image_id) const {
const auto& it = image_id_to_rect_.find(image_id);
return it == image_id_to_rect_.end() ? gfx::Rect() : it->second;
}
@@ -296,7 +53,7 @@ DiscardableImageMap::ScopedMetadataGenerator::ScopedMetadataGenerator(
DiscardableImageMap* image_map,
const gfx::Size& bounds)
: image_map_(image_map),
- metadata_canvas_(image_map->BeginGeneratingMetadata(bounds)) {}
+ image_store_(image_map->BeginGeneratingMetadata(bounds)) {}
DiscardableImageMap::ScopedMetadataGenerator::~ScopedMetadataGenerator() {
image_map_->EndGeneratingMetadata();
diff --git a/chromium/cc/paint/discardable_image_map.h b/chromium/cc/paint/discardable_image_map.h
index 0e006838834..f705e89355d 100644
--- a/chromium/cc/paint/discardable_image_map.h
+++ b/chromium/cc/paint/discardable_image_map.h
@@ -5,23 +5,23 @@
#ifndef CC_PAINT_DISCARDABLE_IMAGE_MAP_H_
#define CC_PAINT_DISCARDABLE_IMAGE_MAP_H_
-#include <unordered_map>
#include <utility>
#include <vector>
+#include "base/containers/flat_map.h"
#include "cc/base/rtree.h"
#include "cc/paint/draw_image.h"
#include "cc/paint/image_id.h"
#include "cc/paint/paint_export.h"
+#include "cc/paint/paint_flags.h"
+#include "cc/paint/paint_image.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkRefCnt.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
namespace cc {
-
-// Helper function to apply the matrix to the rect and return the result.
-SkRect MapRect(const SkMatrix& matrix, const SkRect& src);
+class DiscardableImageStore;
// This class is used for generating discardable images data (see DrawImage
// for the type of data it stores). It allows the client to query a particular
@@ -34,11 +34,11 @@ class CC_PAINT_EXPORT DiscardableImageMap {
const gfx::Size& bounds);
~ScopedMetadataGenerator();
- SkCanvas* canvas() { return metadata_canvas_.get(); }
+ DiscardableImageStore* image_store() { return image_store_.get(); }
private:
DiscardableImageMap* image_map_;
- std::unique_ptr<SkCanvas> metadata_canvas_;
+ std::unique_ptr<DiscardableImageStore> image_store_;
};
DiscardableImageMap();
@@ -49,17 +49,18 @@ class CC_PAINT_EXPORT DiscardableImageMap {
float contents_scale,
const gfx::ColorSpace& target_color_space,
std::vector<DrawImage>* images) const;
- gfx::Rect GetRectForImage(ImageId image_id) const;
+ gfx::Rect GetRectForImage(PaintImage::Id image_id) const;
private:
friend class ScopedMetadataGenerator;
friend class DiscardableImageMapTest;
- std::unique_ptr<SkCanvas> BeginGeneratingMetadata(const gfx::Size& bounds);
+ std::unique_ptr<DiscardableImageStore> BeginGeneratingMetadata(
+ const gfx::Size& bounds);
void EndGeneratingMetadata();
std::vector<std::pair<DrawImage, gfx::Rect>> all_images_;
- std::unordered_map<ImageId, gfx::Rect> image_id_to_rect_;
+ base::flat_map<PaintImage::Id, gfx::Rect> image_id_to_rect_;
RTree images_rtree_;
};
diff --git a/chromium/cc/paint/discardable_image_map_unittest.cc b/chromium/cc/paint/discardable_image_map_unittest.cc
index eb687ad27df..756a9c35d07 100644
--- a/chromium/cc/paint/discardable_image_map_unittest.cc
+++ b/chromium/cc/paint/discardable_image_map_unittest.cc
@@ -11,6 +11,10 @@
#include "base/memory/ref_counted.h"
#include "base/values.h"
#include "cc/base/region.h"
+#include "cc/paint/clip_display_item.h"
+#include "cc/paint/discardable_image_store.h"
+#include "cc/paint/paint_flags.h"
+#include "cc/paint/paint_recorder.h"
#include "cc/test/fake_content_layer_client.h"
#include "cc/test/fake_recording_source.h"
#include "cc/test/skia_common.h"
@@ -25,16 +29,30 @@
namespace cc {
namespace {
+PaintImage CreateDiscardablePaintImage(const gfx::Size& size) {
+ return PaintImage(PaintImage::GetNextId(), CreateDiscardableImage(size));
+}
+
struct PositionScaleDrawImage {
- PositionScaleDrawImage(sk_sp<const SkImage> image,
+ PositionScaleDrawImage(const PaintImage& image,
const gfx::Rect& image_rect,
const SkSize& scale)
- : image(std::move(image)), image_rect(image_rect), scale(scale) {}
- sk_sp<const SkImage> image;
+ : image(image), image_rect(image_rect), scale(scale) {}
+ PaintImage image;
gfx::Rect image_rect;
SkSize scale;
};
+sk_sp<PaintRecord> CreateRecording(const PaintImage& discardable_image,
+ const gfx::Rect& visible_rect) {
+ PaintRecorder recorder;
+ PaintCanvas* canvas =
+ recorder.beginRecording(visible_rect.width(), visible_rect.height());
+ canvas->drawImage(discardable_image, 0, 0, nullptr);
+ sk_sp<PaintRecord> record = recorder.finishRecordingAsPicture();
+ return record;
+}
+
} // namespace
class DiscardableImageMapTest : public testing::Test {
@@ -49,19 +67,18 @@ class DiscardableImageMapTest : public testing::Test {
image_map.GetDiscardableImagesInRect(rect, 1.f, target_color_space,
&draw_images);
- std::vector<size_t> indices;
- image_map.images_rtree_.Search(rect, &indices);
std::vector<PositionScaleDrawImage> position_draw_images;
- for (size_t index : indices) {
- position_draw_images.push_back(
- PositionScaleDrawImage(image_map.all_images_[index].first.image(),
- image_map.all_images_[index].second,
- image_map.all_images_[index].first.scale()));
+ for (size_t index : image_map.images_rtree_.Search(rect)) {
+ position_draw_images.push_back(PositionScaleDrawImage(
+ image_map.all_images_[index].first.paint_image(),
+ image_map.all_images_[index].second,
+ image_map.all_images_[index].first.scale()));
}
EXPECT_EQ(draw_images.size(), position_draw_images.size());
for (size_t i = 0; i < draw_images.size(); ++i) {
- EXPECT_TRUE(draw_images[i].image() == position_draw_images[i].image);
+ EXPECT_TRUE(draw_images[i].paint_image() ==
+ position_draw_images[i].image);
EXPECT_EQ(draw_images[i].target_color_space(), target_color_space);
}
return position_draw_images;
@@ -95,11 +112,12 @@ TEST_F(DiscardableImageMapTest, GetDiscardableImagesInRectTest) {
// |---|---|---|---|
// | x | | x | |
// |---|---|---|---|
- sk_sp<SkImage> discardable_image[4][4];
+ PaintImage discardable_image[4][4];
for (int y = 0; y < 4; ++y) {
for (int x = 0; x < 4; ++x) {
if ((x + y) & 1) {
- discardable_image[y][x] = CreateDiscardableImage(gfx::Size(500, 500));
+ discardable_image[y][x] =
+ CreateDiscardablePaintImage(gfx::Size(500, 500));
PaintFlags flags;
content_layer_client.add_draw_image(
discardable_image[y][x], gfx::Point(x * 512 + 6, y * 512 + 6),
@@ -111,13 +129,10 @@ TEST_F(DiscardableImageMapTest, GetDiscardableImagesInRectTest) {
scoped_refptr<DisplayItemList> display_list =
content_layer_client.PaintContentsToDisplayList(
ContentLayerClient::PAINTING_BEHAVIOR_NORMAL);
+ display_list->GenerateDiscardableImagesMetadata();
- DiscardableImageMap image_map;
- {
- DiscardableImageMap::ScopedMetadataGenerator generator(&image_map,
- visible_rect.size());
- display_list->Raster(generator.canvas(), nullptr, gfx::Rect(), 1.f);
- }
+ const DiscardableImageMap& image_map =
+ display_list->discardable_image_map_for_testing();
for (int y = 0; y < 4; ++y) {
for (int x = 0; x < 4; ++x) {
@@ -131,7 +146,7 @@ TEST_F(DiscardableImageMapTest, GetDiscardableImagesInRectTest) {
EXPECT_EQ(gfx::Rect(x * 512 + 6, y * 512 + 6, 500, 500),
inset_rects[0]);
EXPECT_EQ(images[0].image_rect,
- image_map.GetRectForImage(images[0].image->uniqueID()));
+ image_map.GetRectForImage(images[0].image.stable_id()));
} else {
EXPECT_EQ(0u, images.size()) << x << " " << y;
}
@@ -147,22 +162,22 @@ TEST_F(DiscardableImageMapTest, GetDiscardableImagesInRectTest) {
EXPECT_TRUE(images[0].image == discardable_image[1][2]);
EXPECT_EQ(gfx::Rect(2 * 512 + 6, 512 + 6, 500, 500), inset_rects[0]);
EXPECT_EQ(images[0].image_rect,
- image_map.GetRectForImage(images[0].image->uniqueID()));
+ image_map.GetRectForImage(images[0].image.stable_id()));
EXPECT_TRUE(images[1].image == discardable_image[2][1]);
EXPECT_EQ(gfx::Rect(512 + 6, 2 * 512 + 6, 500, 500), inset_rects[1]);
EXPECT_EQ(images[1].image_rect,
- image_map.GetRectForImage(images[1].image->uniqueID()));
+ image_map.GetRectForImage(images[1].image.stable_id()));
EXPECT_TRUE(images[2].image == discardable_image[2][3]);
EXPECT_EQ(gfx::Rect(3 * 512 + 6, 2 * 512 + 6, 500, 500), inset_rects[2]);
EXPECT_EQ(images[2].image_rect,
- image_map.GetRectForImage(images[2].image->uniqueID()));
+ image_map.GetRectForImage(images[2].image.stable_id()));
EXPECT_TRUE(images[3].image == discardable_image[3][2]);
EXPECT_EQ(gfx::Rect(2 * 512 + 6, 3 * 512 + 6, 500, 500), inset_rects[3]);
EXPECT_EQ(images[3].image_rect,
- image_map.GetRectForImage(images[3].image->uniqueID()));
+ image_map.GetRectForImage(images[3].image.stable_id()));
}
TEST_F(DiscardableImageMapTest, GetDiscardableImagesInRectNonZeroLayer) {
@@ -182,11 +197,12 @@ TEST_F(DiscardableImageMapTest, GetDiscardableImagesInRectNonZeroLayer) {
// |---|---|---|---|
// | x | | x | |
// |---|---|---|---|
- sk_sp<SkImage> discardable_image[4][4];
+ PaintImage discardable_image[4][4];
for (int y = 0; y < 4; ++y) {
for (int x = 0; x < 4; ++x) {
if ((x + y) & 1) {
- discardable_image[y][x] = CreateDiscardableImage(gfx::Size(500, 500));
+ discardable_image[y][x] =
+ CreateDiscardablePaintImage(gfx::Size(500, 500));
PaintFlags flags;
content_layer_client.add_draw_image(
discardable_image[y][x],
@@ -198,13 +214,10 @@ TEST_F(DiscardableImageMapTest, GetDiscardableImagesInRectNonZeroLayer) {
scoped_refptr<DisplayItemList> display_list =
content_layer_client.PaintContentsToDisplayList(
ContentLayerClient::PAINTING_BEHAVIOR_NORMAL);
+ display_list->GenerateDiscardableImagesMetadata();
- DiscardableImageMap image_map;
- {
- DiscardableImageMap::ScopedMetadataGenerator generator(&image_map,
- layer_size);
- display_list->Raster(generator.canvas(), nullptr, gfx::Rect(), 1.f);
- }
+ const DiscardableImageMap& image_map =
+ display_list->discardable_image_map_for_testing();
for (int y = 0; y < 4; ++y) {
for (int x = 0; x < 4; ++x) {
@@ -218,7 +231,7 @@ TEST_F(DiscardableImageMapTest, GetDiscardableImagesInRectNonZeroLayer) {
EXPECT_EQ(gfx::Rect(1024 + x * 512 + 6, y * 512 + 6, 500, 500),
inset_rects[0]);
EXPECT_EQ(images[0].image_rect,
- image_map.GetRectForImage(images[0].image->uniqueID()));
+ image_map.GetRectForImage(images[0].image.stable_id()));
} else {
EXPECT_EQ(0u, images.size()) << x << " " << y;
}
@@ -234,24 +247,24 @@ TEST_F(DiscardableImageMapTest, GetDiscardableImagesInRectNonZeroLayer) {
EXPECT_TRUE(images[0].image == discardable_image[1][2]);
EXPECT_EQ(gfx::Rect(1024 + 2 * 512 + 6, 512 + 6, 500, 500), inset_rects[0]);
EXPECT_EQ(images[0].image_rect,
- image_map.GetRectForImage(images[0].image->uniqueID()));
+ image_map.GetRectForImage(images[0].image.stable_id()));
EXPECT_TRUE(images[1].image == discardable_image[2][1]);
EXPECT_EQ(gfx::Rect(1024 + 512 + 6, 2 * 512 + 6, 500, 500), inset_rects[1]);
EXPECT_EQ(images[1].image_rect,
- image_map.GetRectForImage(images[1].image->uniqueID()));
+ image_map.GetRectForImage(images[1].image.stable_id()));
EXPECT_TRUE(images[2].image == discardable_image[2][3]);
EXPECT_EQ(gfx::Rect(1024 + 3 * 512 + 6, 2 * 512 + 6, 500, 500),
inset_rects[2]);
EXPECT_EQ(images[2].image_rect,
- image_map.GetRectForImage(images[2].image->uniqueID()));
+ image_map.GetRectForImage(images[2].image.stable_id()));
EXPECT_TRUE(images[3].image == discardable_image[3][2]);
EXPECT_EQ(gfx::Rect(1024 + 2 * 512 + 6, 3 * 512 + 6, 500, 500),
inset_rects[3]);
EXPECT_EQ(images[3].image_rect,
- image_map.GetRectForImage(images[3].image->uniqueID()));
+ image_map.GetRectForImage(images[3].image.stable_id()));
}
// Non intersecting rects
@@ -278,8 +291,8 @@ TEST_F(DiscardableImageMapTest, GetDiscardableImagesInRectNonZeroLayer) {
// Image not present in the list.
{
- sk_sp<SkImage> image = CreateDiscardableImage(gfx::Size(500, 500));
- EXPECT_EQ(gfx::Rect(), image_map.GetRectForImage(image->uniqueID()));
+ PaintImage image = CreateDiscardablePaintImage(gfx::Size(500, 500));
+ EXPECT_EQ(gfx::Rect(), image_map.GetRectForImage(image.stable_id()));
}
}
@@ -298,11 +311,12 @@ TEST_F(DiscardableImageMapTest, GetDiscardableImagesInRectOnePixelQuery) {
// |---|---|---|---|
// | x | | x | |
// |---|---|---|---|
- sk_sp<SkImage> discardable_image[4][4];
+ PaintImage discardable_image[4][4];
for (int y = 0; y < 4; ++y) {
for (int x = 0; x < 4; ++x) {
if ((x + y) & 1) {
- discardable_image[y][x] = CreateDiscardableImage(gfx::Size(500, 500));
+ discardable_image[y][x] =
+ CreateDiscardablePaintImage(gfx::Size(500, 500));
PaintFlags flags;
content_layer_client.add_draw_image(
discardable_image[y][x], gfx::Point(x * 512 + 6, y * 512 + 6),
@@ -314,13 +328,10 @@ TEST_F(DiscardableImageMapTest, GetDiscardableImagesInRectOnePixelQuery) {
scoped_refptr<DisplayItemList> display_list =
content_layer_client.PaintContentsToDisplayList(
ContentLayerClient::PAINTING_BEHAVIOR_NORMAL);
+ display_list->GenerateDiscardableImagesMetadata();
- DiscardableImageMap image_map;
- {
- DiscardableImageMap::ScopedMetadataGenerator generator(&image_map,
- visible_rect.size());
- display_list->Raster(generator.canvas(), nullptr, gfx::Rect(), 1.f);
- }
+ const DiscardableImageMap& image_map =
+ display_list->discardable_image_map_for_testing();
for (int y = 0; y < 4; ++y) {
for (int x = 0; x < 4; ++x) {
@@ -334,7 +345,7 @@ TEST_F(DiscardableImageMapTest, GetDiscardableImagesInRectOnePixelQuery) {
EXPECT_EQ(gfx::Rect(x * 512 + 6, y * 512 + 6, 500, 500),
inset_rects[0]);
EXPECT_EQ(images[0].image_rect,
- image_map.GetRectForImage(images[0].image->uniqueID()));
+ image_map.GetRectForImage(images[0].image.stable_id()));
} else {
EXPECT_EQ(0u, images.size()) << x << " " << y;
}
@@ -347,8 +358,8 @@ TEST_F(DiscardableImageMapTest, GetDiscardableImagesInRectMassiveImage) {
FakeContentLayerClient content_layer_client;
content_layer_client.set_bounds(visible_rect.size());
- sk_sp<SkImage> discardable_image =
- CreateDiscardableImage(gfx::Size(1 << 25, 1 << 25));
+ PaintImage discardable_image =
+ CreateDiscardablePaintImage(gfx::Size(1 << 25, 1 << 25));
PaintFlags flags;
content_layer_client.add_draw_image(discardable_image, gfx::Point(0, 0),
flags);
@@ -356,13 +367,10 @@ TEST_F(DiscardableImageMapTest, GetDiscardableImagesInRectMassiveImage) {
scoped_refptr<DisplayItemList> display_list =
content_layer_client.PaintContentsToDisplayList(
ContentLayerClient::PAINTING_BEHAVIOR_NORMAL);
+ display_list->GenerateDiscardableImagesMetadata();
- DiscardableImageMap image_map;
- {
- DiscardableImageMap::ScopedMetadataGenerator generator(&image_map,
- visible_rect.size());
- display_list->Raster(generator.canvas(), nullptr, gfx::Rect(), 1.f);
- }
+ const DiscardableImageMap& image_map =
+ display_list->discardable_image_map_for_testing();
std::vector<PositionScaleDrawImage> images =
GetDiscardableImagesInRect(image_map, gfx::Rect(0, 0, 1, 1));
std::vector<gfx::Rect> inset_rects = InsetImageRects(images);
@@ -370,7 +378,7 @@ TEST_F(DiscardableImageMapTest, GetDiscardableImagesInRectMassiveImage) {
EXPECT_TRUE(images[0].image == discardable_image);
EXPECT_EQ(gfx::Rect(0, 0, 2048, 2048), inset_rects[0]);
EXPECT_EQ(images[0].image_rect,
- image_map.GetRectForImage(images[0].image->uniqueID()));
+ image_map.GetRectForImage(images[0].image.stable_id()));
}
TEST_F(DiscardableImageMapTest, PaintDestroyedWhileImageIsDrawn) {
@@ -378,19 +386,21 @@ TEST_F(DiscardableImageMapTest, PaintDestroyedWhileImageIsDrawn) {
FakeContentLayerClient content_layer_client;
content_layer_client.set_bounds(visible_rect.size());
- sk_sp<SkImage> discardable_image = CreateDiscardableImage(gfx::Size(10, 10));
+ PaintImage discardable_image = CreateDiscardablePaintImage(gfx::Size(10, 10));
+ sk_sp<PaintRecord> record = CreateRecording(discardable_image, visible_rect);
DiscardableImageMap image_map;
{
DiscardableImageMap::ScopedMetadataGenerator generator(&image_map,
visible_rect.size());
+ DiscardableImageStore* image_store = generator.image_store();
{
std::unique_ptr<SkPaint> paint(new SkPaint());
- generator.canvas()->saveLayer(gfx::RectToSkRect(visible_rect),
- paint.get());
+ image_store->GetNoDrawCanvas()->saveLayer(gfx::RectToSkRect(visible_rect),
+ paint.get());
}
- generator.canvas()->drawImage(discardable_image, 0, 0, nullptr);
- generator.canvas()->restore();
+ image_store->GatherDiscardableImages(record.get());
+ image_store->GetNoDrawCanvas()->restore();
}
std::vector<PositionScaleDrawImage> images =
@@ -404,16 +414,19 @@ TEST_F(DiscardableImageMapTest, NullPaintOnSaveLayer) {
FakeContentLayerClient content_layer_client;
content_layer_client.set_bounds(visible_rect.size());
- sk_sp<SkImage> discardable_image = CreateDiscardableImage(gfx::Size(10, 10));
+ PaintImage discardable_image = CreateDiscardablePaintImage(gfx::Size(10, 10));
+ sk_sp<PaintRecord> record = CreateRecording(discardable_image, visible_rect);
DiscardableImageMap image_map;
{
DiscardableImageMap::ScopedMetadataGenerator generator(&image_map,
visible_rect.size());
+ DiscardableImageStore* image_store = generator.image_store();
SkPaint* null_paint = nullptr;
- generator.canvas()->saveLayer(gfx::RectToSkRect(visible_rect), null_paint);
- generator.canvas()->drawImage(discardable_image, 0, 0, nullptr);
- generator.canvas()->restore();
+ image_store->GetNoDrawCanvas()->saveLayer(gfx::RectToSkRect(visible_rect),
+ null_paint);
+ image_store->GatherDiscardableImages(record.get());
+ image_store->GetNoDrawCanvas()->restore();
}
std::vector<PositionScaleDrawImage> images =
@@ -428,8 +441,8 @@ TEST_F(DiscardableImageMapTest, GetDiscardableImagesInRectMaxImage) {
content_layer_client.set_bounds(visible_rect.size());
int dimension = std::numeric_limits<int>::max();
- sk_sp<SkImage> discardable_image =
- CreateDiscardableImage(gfx::Size(dimension, dimension));
+ PaintImage discardable_image =
+ CreateDiscardablePaintImage(gfx::Size(dimension, dimension));
PaintFlags flags;
content_layer_client.add_draw_image(discardable_image, gfx::Point(42, 42),
flags);
@@ -437,13 +450,10 @@ TEST_F(DiscardableImageMapTest, GetDiscardableImagesInRectMaxImage) {
scoped_refptr<DisplayItemList> display_list =
content_layer_client.PaintContentsToDisplayList(
ContentLayerClient::PAINTING_BEHAVIOR_NORMAL);
+ display_list->GenerateDiscardableImagesMetadata();
- DiscardableImageMap image_map;
- {
- DiscardableImageMap::ScopedMetadataGenerator generator(&image_map,
- visible_rect.size());
- display_list->Raster(generator.canvas(), nullptr, visible_rect, 1.f);
- }
+ const DiscardableImageMap& image_map =
+ display_list->discardable_image_map_for_testing();
std::vector<PositionScaleDrawImage> images =
GetDiscardableImagesInRect(image_map, gfx::Rect(42, 42, 1, 1));
std::vector<gfx::Rect> inset_rects = InsetImageRects(images);
@@ -451,7 +461,7 @@ TEST_F(DiscardableImageMapTest, GetDiscardableImagesInRectMaxImage) {
EXPECT_TRUE(images[0].image == discardable_image);
EXPECT_EQ(gfx::Rect(42, 42, 2006, 2006), inset_rects[0]);
EXPECT_EQ(images[0].image_rect,
- image_map.GetRectForImage(images[0].image->uniqueID()));
+ image_map.GetRectForImage(images[0].image.stable_id()));
}
TEST_F(DiscardableImageMapTest, GetDiscardableImagesInRectMaxImageMaxLayer) {
@@ -466,8 +476,8 @@ TEST_F(DiscardableImageMapTest, GetDiscardableImagesInRectMaxImageMaxLayer) {
FakeContentLayerClient content_layer_client;
content_layer_client.set_bounds(visible_rect.size());
- sk_sp<SkImage> discardable_image =
- CreateDiscardableImage(gfx::Size(dimension, dimension));
+ PaintImage discardable_image =
+ CreateDiscardablePaintImage(gfx::Size(dimension, dimension));
PaintFlags flags;
content_layer_client.add_draw_image(discardable_image, gfx::Point(0, 0),
flags);
@@ -479,13 +489,10 @@ TEST_F(DiscardableImageMapTest, GetDiscardableImagesInRectMaxImageMaxLayer) {
scoped_refptr<DisplayItemList> display_list =
content_layer_client.PaintContentsToDisplayList(
ContentLayerClient::PAINTING_BEHAVIOR_NORMAL);
+ display_list->GenerateDiscardableImagesMetadata();
- DiscardableImageMap image_map;
- {
- DiscardableImageMap::ScopedMetadataGenerator generator(&image_map,
- visible_rect.size());
- display_list->Raster(generator.canvas(), nullptr, visible_rect, 1.f);
- }
+ const DiscardableImageMap& image_map =
+ display_list->discardable_image_map_for_testing();
std::vector<PositionScaleDrawImage> images =
GetDiscardableImagesInRect(image_map, gfx::Rect(0, 0, 1, 1));
std::vector<gfx::Rect> inset_rects = InsetImageRects(images);
@@ -510,7 +517,7 @@ TEST_F(DiscardableImageMapTest, GetDiscardableImagesInRectMaxImageMaxLayer) {
EXPECT_EQ(gfx::Rect(0, 0, dimension, dimension), inset_rects[0]);
EXPECT_EQ(images[0].image_rect,
- image_map.GetRectForImage(discardable_image->uniqueID()));
+ image_map.GetRectForImage(discardable_image.stable_id()));
}
TEST_F(DiscardableImageMapTest, GetDiscardableImagesRectInBounds) {
@@ -518,10 +525,10 @@ TEST_F(DiscardableImageMapTest, GetDiscardableImagesRectInBounds) {
FakeContentLayerClient content_layer_client;
content_layer_client.set_bounds(visible_rect.size());
- sk_sp<SkImage> discardable_image =
- CreateDiscardableImage(gfx::Size(100, 100));
- sk_sp<SkImage> long_discardable_image =
- CreateDiscardableImage(gfx::Size(10000, 100));
+ PaintImage discardable_image =
+ CreateDiscardablePaintImage(gfx::Size(100, 100));
+ PaintImage long_discardable_image =
+ CreateDiscardablePaintImage(gfx::Size(10000, 100));
PaintFlags flags;
content_layer_client.add_draw_image(discardable_image, gfx::Point(-10, -11),
@@ -534,13 +541,10 @@ TEST_F(DiscardableImageMapTest, GetDiscardableImagesRectInBounds) {
scoped_refptr<DisplayItemList> display_list =
content_layer_client.PaintContentsToDisplayList(
ContentLayerClient::PAINTING_BEHAVIOR_NORMAL);
+ display_list->GenerateDiscardableImagesMetadata();
- DiscardableImageMap image_map;
- {
- DiscardableImageMap::ScopedMetadataGenerator generator(&image_map,
- visible_rect.size());
- display_list->Raster(generator.canvas(), nullptr, visible_rect, 1.f);
- }
+ const DiscardableImageMap& image_map =
+ display_list->discardable_image_map_for_testing();
std::vector<PositionScaleDrawImage> images =
GetDiscardableImagesInRect(image_map, gfx::Rect(0, 0, 1, 1));
std::vector<gfx::Rect> inset_rects = InsetImageRects(images);
@@ -562,10 +566,10 @@ TEST_F(DiscardableImageMapTest, GetDiscardableImagesRectInBounds) {
discardable_image_rect.Union(gfx::Rect(950, 951, 50, 49));
discardable_image_rect.Inset(-1, -1, -1, -1);
EXPECT_EQ(discardable_image_rect,
- image_map.GetRectForImage(discardable_image->uniqueID()));
+ image_map.GetRectForImage(discardable_image.stable_id()));
EXPECT_EQ(gfx::Rect(-1, 499, 1002, 102),
- image_map.GetRectForImage(long_discardable_image->uniqueID()));
+ image_map.GetRectForImage(long_discardable_image.stable_id()));
}
TEST_F(DiscardableImageMapTest, GetDiscardableImagesInShader) {
@@ -607,13 +611,10 @@ TEST_F(DiscardableImageMapTest, GetDiscardableImagesInShader) {
scoped_refptr<DisplayItemList> display_list =
content_layer_client.PaintContentsToDisplayList(
ContentLayerClient::PAINTING_BEHAVIOR_NORMAL);
+ display_list->GenerateDiscardableImagesMetadata();
- DiscardableImageMap image_map;
- {
- DiscardableImageMap::ScopedMetadataGenerator generator(&image_map,
- visible_rect.size());
- display_list->Raster(generator.canvas(), nullptr, gfx::Rect(), 1.f);
- }
+ const DiscardableImageMap& image_map =
+ display_list->discardable_image_map_for_testing();
for (int y = 0; y < 4; ++y) {
for (int x = 0; x < 4; ++x) {
@@ -622,7 +623,7 @@ TEST_F(DiscardableImageMapTest, GetDiscardableImagesInShader) {
std::vector<gfx::Rect> inset_rects = InsetImageRects(images);
if ((x + y) & 1) {
EXPECT_EQ(1u, images.size()) << x << " " << y;
- EXPECT_TRUE(images[0].image == discardable_image[y][x])
+ EXPECT_TRUE(images[0].image.sk_image() == discardable_image[y][x])
<< x << " " << y;
EXPECT_EQ(gfx::Rect(x * 512 + 6, y * 512 + 6, 500, 500),
inset_rects[0]);
@@ -639,14 +640,79 @@ TEST_F(DiscardableImageMapTest, GetDiscardableImagesInShader) {
GetDiscardableImagesInRect(image_map, gfx::Rect(512, 512, 2048, 2048));
std::vector<gfx::Rect> inset_rects = InsetImageRects(images);
EXPECT_EQ(4u, images.size());
- EXPECT_TRUE(images[0].image == discardable_image[1][2]);
+ EXPECT_TRUE(images[0].image.sk_image() == discardable_image[1][2]);
EXPECT_EQ(gfx::Rect(2 * 512 + 6, 512 + 6, 500, 500), inset_rects[0]);
- EXPECT_TRUE(images[1].image == discardable_image[2][1]);
+ EXPECT_TRUE(images[1].image.sk_image() == discardable_image[2][1]);
EXPECT_EQ(gfx::Rect(512 + 6, 2 * 512 + 6, 500, 500), inset_rects[1]);
- EXPECT_TRUE(images[2].image == discardable_image[2][3]);
+ EXPECT_TRUE(images[2].image.sk_image() == discardable_image[2][3]);
EXPECT_EQ(gfx::Rect(3 * 512 + 6, 2 * 512 + 6, 500, 500), inset_rects[2]);
- EXPECT_TRUE(images[3].image == discardable_image[3][2]);
+ EXPECT_TRUE(images[3].image.sk_image() == discardable_image[3][2]);
EXPECT_EQ(gfx::Rect(2 * 512 + 6, 3 * 512 + 6, 500, 500), inset_rects[3]);
}
+TEST_F(DiscardableImageMapTest, ClipsImageRects) {
+ gfx::Rect visible_rect(500, 500);
+
+ PaintImage discardable_image =
+ CreateDiscardablePaintImage(gfx::Size(500, 500));
+ sk_sp<PaintRecord> record = CreateRecording(discardable_image, visible_rect);
+
+ scoped_refptr<DisplayItemList> display_list = new DisplayItemList;
+ display_list->CreateAndAppendPairedBeginItem<ClipDisplayItem>(
+ gfx::Rect(250, 250), std::vector<SkRRect>(), false);
+ display_list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
+ gfx::Rect(500, 500), record, SkRect::MakeWH(500, 500));
+ display_list->CreateAndAppendPairedEndItem<EndClipDisplayItem>();
+ display_list->Finalize();
+ display_list->GenerateDiscardableImagesMetadata();
+
+ const DiscardableImageMap& image_map =
+ display_list->discardable_image_map_for_testing();
+ std::vector<PositionScaleDrawImage> images =
+ GetDiscardableImagesInRect(image_map, visible_rect);
+ std::vector<gfx::Rect> inset_rects = InsetImageRects(images);
+ EXPECT_EQ(1u, images.size());
+ EXPECT_TRUE(images[0].image == discardable_image);
+ EXPECT_EQ(gfx::Rect(250, 250), inset_rects[0]);
+}
+
+TEST_F(DiscardableImageMapTest, GathersDiscardableImagesFromNestedOps) {
+ sk_sp<PaintRecord> internal_record = sk_make_sp<PaintRecord>();
+ PaintImage discardable_image =
+ CreateDiscardablePaintImage(gfx::Size(100, 100));
+ internal_record->push<DrawImageOp>(discardable_image, 0.f, 0.f, nullptr);
+
+ sk_sp<PaintRecord> list_record = sk_make_sp<PaintRecord>();
+ PaintImage discardable_image2 =
+ CreateDiscardablePaintImage(gfx::Size(100, 100));
+ list_record->push<DrawImageOp>(discardable_image2, 100.f, 100.f, nullptr);
+ scoped_refptr<DisplayItemList> display_list = new DisplayItemList;
+ display_list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
+ gfx::Rect(100, 100, 100, 100), list_record, SkRect::MakeWH(100, 100));
+ display_list->Finalize();
+
+ PaintOpBuffer buffer;
+ buffer.push<DrawRecordOp>(internal_record);
+ buffer.push<DrawDisplayItemListOp>(display_list);
+ DiscardableImageMap image_map_;
+ {
+ DiscardableImageMap::ScopedMetadataGenerator generator(&image_map_,
+ gfx::Size(200, 200));
+ generator.image_store()->GatherDiscardableImages(&buffer);
+ }
+
+ gfx::ColorSpace target_color_space;
+ std::vector<DrawImage> images;
+ image_map_.GetDiscardableImagesInRect(gfx::Rect(0, 0, 5, 95), 1.f,
+ target_color_space, &images);
+ EXPECT_EQ(1u, images.size());
+ EXPECT_TRUE(discardable_image == images[0].paint_image());
+
+ images.clear();
+ image_map_.GetDiscardableImagesInRect(gfx::Rect(105, 105, 5, 95), 1.f,
+ target_color_space, &images);
+ EXPECT_EQ(1u, images.size());
+ EXPECT_TRUE(discardable_image2 == images[0].paint_image());
+}
+
} // namespace cc
diff --git a/chromium/cc/paint/discardable_image_store.cc b/chromium/cc/paint/discardable_image_store.cc
new file mode 100644
index 00000000000..1545e32aba4
--- /dev/null
+++ b/chromium/cc/paint/discardable_image_store.cc
@@ -0,0 +1,259 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/paint/discardable_image_store.h"
+
+#include "base/containers/adapters.h"
+#include "base/memory/ptr_util.h"
+#include "cc/paint/display_item_list.h"
+#include "third_party/skia/include/utils/SkNoDrawCanvas.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/skia_util.h"
+
+namespace cc {
+namespace {
+
+SkRect MapRect(const SkMatrix& matrix, const SkRect& src) {
+ SkRect dst;
+ matrix.mapRect(&dst, src);
+ return dst;
+}
+
+} // namespace
+
+class DiscardableImageStore::PaintTrackingCanvas : public SkNoDrawCanvas {
+ public:
+ PaintTrackingCanvas(int width, int height) : SkNoDrawCanvas(width, height) {}
+ ~PaintTrackingCanvas() override = default;
+
+ bool ComputePaintBounds(const SkRect& rect,
+ const SkPaint* current_paint,
+ SkRect* paint_bounds) {
+ *paint_bounds = rect;
+ if (current_paint) {
+ if (!current_paint->canComputeFastBounds())
+ return false;
+ *paint_bounds =
+ current_paint->computeFastBounds(*paint_bounds, paint_bounds);
+ }
+
+ for (const auto& paint : base::Reversed(saved_paints_)) {
+ if (!paint.canComputeFastBounds())
+ return false;
+ *paint_bounds = paint.computeFastBounds(*paint_bounds, paint_bounds);
+ }
+
+ return true;
+ }
+
+ protected:
+ SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override {
+ saved_paints_.push_back(rec.fPaint ? *rec.fPaint : SkPaint());
+ return SkNoDrawCanvas::getSaveLayerStrategy(rec);
+ }
+
+ void willSave() override {
+ saved_paints_.push_back(SkPaint());
+ return SkNoDrawCanvas::willSave();
+ }
+
+ void willRestore() override {
+ DCHECK_GT(saved_paints_.size(), 0u);
+ saved_paints_.pop_back();
+ SkNoDrawCanvas::willRestore();
+ }
+
+ private:
+ std::vector<SkPaint> saved_paints_;
+};
+
+DiscardableImageStore::DiscardableImageStore(
+ int width,
+ int height,
+ std::vector<std::pair<DrawImage, gfx::Rect>>* image_set,
+ base::flat_map<PaintImage::Id, gfx::Rect>* image_id_to_rect)
+ : canvas_(base::MakeUnique<PaintTrackingCanvas>(width, height)),
+ image_set_(image_set),
+ image_id_to_rect_(image_id_to_rect) {}
+
+DiscardableImageStore::~DiscardableImageStore() = default;
+
+SkNoDrawCanvas* DiscardableImageStore::GetNoDrawCanvas() {
+ return canvas_.get();
+}
+
+void DiscardableImageStore::GatherDiscardableImages(
+ const PaintOpBuffer* buffer) {
+ if (!buffer->HasDiscardableImages())
+ return;
+
+ SkMatrix original = canvas_->getTotalMatrix();
+ canvas_->save();
+ // TODO(khushalsagar): Optimize out save/restore blocks if there are no images
+ // in the draw ops between them.
+ for (auto* op : PaintOpBuffer::Iterator(buffer)) {
+ if (op->IsDrawOp()) {
+ switch (op->GetType()) {
+ case PaintOpType::DrawArc: {
+ auto* arc_op = static_cast<DrawArcOp*>(op);
+ AddImageFromFlags(arc_op->oval, arc_op->flags);
+ } break;
+ case PaintOpType::DrawCircle: {
+ auto* circle_op = static_cast<DrawCircleOp*>(op);
+ SkRect rect =
+ SkRect::MakeXYWH(circle_op->cx - circle_op->radius,
+ circle_op->cy - circle_op->radius,
+ 2 * circle_op->radius, 2 * circle_op->radius);
+ AddImageFromFlags(rect, circle_op->flags);
+ } break;
+ case PaintOpType::DrawDisplayItemList: {
+ auto* list_op = static_cast<DrawDisplayItemListOp*>(op);
+ list_op->list->GatherDiscardableImages(this);
+ } break;
+ case PaintOpType::DrawImage: {
+ auto* image_op = static_cast<DrawImageOp*>(op);
+ const SkImage* sk_image = image_op->image.sk_image().get();
+ AddImage(image_op->image,
+ SkRect::MakeIWH(sk_image->width(), sk_image->height()),
+ SkRect::MakeXYWH(image_op->left, image_op->top,
+ sk_image->width(), sk_image->height()),
+ nullptr, image_op->flags);
+ } break;
+ case PaintOpType::DrawImageRect: {
+ auto* image_rect_op = static_cast<DrawImageRectOp*>(op);
+ SkMatrix matrix;
+ matrix.setRectToRect(image_rect_op->src, image_rect_op->dst,
+ SkMatrix::kFill_ScaleToFit);
+ AddImage(image_rect_op->image, image_rect_op->src, image_rect_op->dst,
+ &matrix, image_rect_op->flags);
+ } break;
+ case PaintOpType::DrawIRect: {
+ auto* rect_op = static_cast<DrawIRectOp*>(op);
+ AddImageFromFlags(SkRect::Make(rect_op->rect), rect_op->flags);
+ } break;
+ case PaintOpType::DrawOval: {
+ auto* oval_op = static_cast<DrawOvalOp*>(op);
+ AddImageFromFlags(oval_op->oval, oval_op->flags);
+ } break;
+ case PaintOpType::DrawPath: {
+ auto* path_op = static_cast<DrawPathOp*>(op);
+ AddImageFromFlags(path_op->path.getBounds(), path_op->flags);
+ } break;
+ case PaintOpType::DrawRecord: {
+ auto* record_op = static_cast<DrawRecordOp*>(op);
+ GatherDiscardableImages(record_op->record.get());
+ } break;
+ case PaintOpType::DrawRect: {
+ auto* rect_op = static_cast<DrawRectOp*>(op);
+ AddImageFromFlags(rect_op->rect, rect_op->flags);
+ } break;
+ case PaintOpType::DrawRRect: {
+ auto* rect_op = static_cast<DrawRRectOp*>(op);
+ AddImageFromFlags(rect_op->rrect.rect(), rect_op->flags);
+ } break;
+ // TODO(khushalsagar): Check if we should be querying images from any of
+ // the following ops.
+ case PaintOpType::DrawPosText:
+ case PaintOpType::DrawLine:
+ case PaintOpType::DrawDRRect:
+ case PaintOpType::DrawText:
+ case PaintOpType::DrawTextBlob:
+ case PaintOpType::DrawColor:
+ break;
+ default:
+ NOTREACHED();
+ }
+ } else {
+ op->Raster(canvas_.get(), original);
+ }
+ }
+ canvas_->restore();
+}
+
+// Currently this function only handles extracting images from SkImageShaders
+// embedded in SkPaints. Other embedded image cases, such as SkPictures,
+// are not yet handled.
+void DiscardableImageStore::AddImageFromFlags(const SkRect& rect,
+ const PaintFlags& flags) {
+ SkShader* shader = flags.getShader();
+ if (shader) {
+ SkMatrix matrix;
+ SkShader::TileMode xy[2];
+ SkImage* image = shader->isAImage(&matrix, xy);
+ if (image) {
+ // We currently use the wrong id for images that come from shaders. We
+ // don't know what the stable id is, but since the completion and
+ // animation states are both unknown, this value doesn't matter as it
+ // won't be used in checker imaging anyway. Keep this value the same to
+ // avoid id churn.
+ // TODO(vmpstr): Remove this when we can add paint images into shaders
+ // directly.
+ PaintImage paint_image(PaintImage::kUnknownStableId, sk_ref_sp(image),
+ PaintImage::AnimationType::UNKNOWN,
+ PaintImage::CompletionState::UNKNOWN);
+ // TODO(ericrk): Handle cases where we only need a sub-rect from the
+ // image. crbug.com/671821
+ AddImage(std::move(paint_image), SkRect::MakeFromIRect(image->bounds()),
+ rect, &matrix, flags);
+ }
+ }
+}
+
+void DiscardableImageStore::AddImage(PaintImage paint_image,
+ const SkRect& src_rect,
+ const SkRect& rect,
+ const SkMatrix* local_matrix,
+ const PaintFlags& flags) {
+ if (!paint_image.sk_image()->isLazyGenerated())
+ return;
+
+ const SkRect& clip_rect = SkRect::Make(canvas_->getDeviceClipBounds());
+ const SkMatrix& ctm = canvas_->getTotalMatrix();
+
+ SkRect paint_rect = MapRect(ctm, rect);
+ bool computed_paint_bounds =
+ canvas_->ComputePaintBounds(paint_rect, ToSkPaint(&flags), &paint_rect);
+ if (!computed_paint_bounds) {
+ // TODO(vmpstr): UMA this case.
+ paint_rect = clip_rect;
+ }
+
+ // Clamp the image rect by the current clip rect.
+ if (!paint_rect.intersect(clip_rect))
+ return;
+
+ SkFilterQuality filter_quality = flags.getFilterQuality();
+
+ SkIRect src_irect;
+ src_rect.roundOut(&src_irect);
+ gfx::Rect image_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).
+ image_rect.Inset(-1, -1);
+
+ // The true target color space will be assigned when it is known, in
+ // GetDiscardableImagesInRect.
+ gfx::ColorSpace target_color_space;
+
+ SkMatrix matrix = ctm;
+ if (local_matrix)
+ matrix.postConcat(*local_matrix);
+
+ (*image_id_to_rect_)[paint_image.stable_id()].Union(image_rect);
+ image_set_->push_back(
+ std::make_pair(DrawImage(std::move(paint_image), src_irect,
+ filter_quality, matrix, target_color_space),
+ image_rect));
+}
+
+} // namespace cc
diff --git a/chromium/cc/paint/discardable_image_store.h b/chromium/cc/paint/discardable_image_store.h
new file mode 100644
index 00000000000..ea1e828fc5e
--- /dev/null
+++ b/chromium/cc/paint/discardable_image_store.h
@@ -0,0 +1,52 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_PAINT_DISCARDABLE_IMAGE_STORE_H_
+#define CC_PAINT_DISCARDABLE_IMAGE_STORE_H_
+
+#include "base/containers/flat_map.h"
+#include "cc/paint/draw_image.h"
+#include "cc/paint/image_id.h"
+#include "cc/paint/paint_export.h"
+#include "cc/paint/paint_op_buffer.h"
+#include "third_party/skia/include/core/SkMatrix.h"
+#include "third_party/skia/include/core/SkRect.h"
+#include "third_party/skia/include/utils/SkNoDrawCanvas.h"
+
+namespace cc {
+class PaintFlags;
+class PaintImage;
+
+class CC_PAINT_EXPORT DiscardableImageStore {
+ public:
+ DiscardableImageStore(
+ int width,
+ int height,
+ std::vector<std::pair<DrawImage, gfx::Rect>>* image_set,
+ base::flat_map<PaintImage::Id, gfx::Rect>* image_id_to_rect);
+ ~DiscardableImageStore();
+
+ void GatherDiscardableImages(const PaintOpBuffer* buffer);
+ SkNoDrawCanvas* GetNoDrawCanvas();
+
+ private:
+ class PaintTrackingCanvas;
+
+ void AddImageFromFlags(const SkRect& rect, const PaintFlags& flags);
+ void AddImage(PaintImage paint_image,
+ const SkRect& src_rect,
+ const SkRect& rect,
+ const SkMatrix* local_matrix,
+ const PaintFlags& flags);
+
+ // This canvas is used only for tracking transform/clip/filter state from the
+ // non-drawing ops.
+ std::unique_ptr<PaintTrackingCanvas> canvas_;
+ std::vector<std::pair<DrawImage, gfx::Rect>>* image_set_;
+ base::flat_map<PaintImage::Id, gfx::Rect>* image_id_to_rect_;
+};
+
+} // namespace cc
+
+#endif // CC_PAINT_DISCARDABLE_IMAGE_STORE_H_
diff --git a/chromium/cc/paint/display_item_list.cc b/chromium/cc/paint/display_item_list.cc
index 83599482f53..b947403a738 100644
--- a/chromium/cc/paint/display_item_list.cc
+++ b/chromium/cc/paint/display_item_list.cc
@@ -19,6 +19,7 @@
#include "cc/paint/clip_display_item.h"
#include "cc/paint/clip_path_display_item.h"
#include "cc/paint/compositing_display_item.h"
+#include "cc/paint/discardable_image_store.h"
#include "cc/paint/drawing_display_item.h"
#include "cc/paint/filter_display_item.h"
#include "cc/paint/float_clip_display_item.h"
@@ -97,12 +98,13 @@ NOINLINE DISABLE_CFI_PERF void RasterItem(const DisplayItem& base_item,
break;
case DisplayItem::DRAWING: {
const auto& item = static_cast<const DrawingDisplayItem&>(base_item);
- if (canvas->quickReject(item.picture->cullRect()))
- break;
-
- // SkPicture always does a wrapping save/restore on the canvas, so it is
- // not necessary here.
+ // TODO(enne): Maybe the PaintRecord itself could know whether this
+ // was needed? It's not clear whether these save/restore semantics
+ // that SkPicture handles during playback are things that should be
+ // kept around.
+ canvas->save();
item.picture->playback(canvas, callback);
+ canvas->restore();
break;
}
case DisplayItem::FLOAT_CLIP: {
@@ -158,22 +160,31 @@ DisplayItemList::DisplayItemList()
DisplayItemList::~DisplayItemList() = default;
-void DisplayItemList::Raster(SkCanvas* canvas,
- SkPicture::AbortCallback* callback,
- const gfx::Rect& canvas_target_playback_rect,
- float contents_scale) const {
- canvas->save();
- if (!canvas_target_playback_rect.IsEmpty()) {
- // canvas_target_playback_rect is specified in device space. We can't
- // use clipRect because canvas CTM will be applied on it. Use clipRegion
- // instead because it ignores canvas CTM.
- SkRegion device_clip;
- device_clip.setRect(gfx::RectToSkIRect(canvas_target_playback_rect));
- canvas->clipRegion(device_clip);
- }
- canvas->scale(contents_scale, contents_scale);
- Raster(canvas, callback);
- canvas->restore();
+// Atttempts to merge a CompositingDisplayItem and DrawingDisplayItem
+// into a single "draw with alpha". This function returns true if
+// it was successful. If false, then the caller is responsible for
+// drawing these items. This is a DisplayItemList version of the
+// SkRecord optimization SkRecordNoopSaveLayerDrawRestores.
+static bool MergeAndDrawIfPossible(const CompositingDisplayItem& save_item,
+ const DrawingDisplayItem& draw_item,
+ SkCanvas* canvas) {
+ if (save_item.color_filter)
+ return false;
+ if (save_item.xfermode != SkBlendMode::kSrcOver)
+ return false;
+ // TODO(enne): I believe that lcd_text_requires_opaque_layer is not
+ // relevant here and that lcd text is preserved post merge, but I haven't
+ // tested that.
+ const PaintRecord* record = draw_item.picture.get();
+ if (record->size() != 1u)
+ return false;
+
+ const PaintOp* op = record->GetFirstOp();
+ if (!op->IsDrawOp())
+ return false;
+
+ op->RasterWithAlpha(canvas, save_item.alpha);
+ return true;
}
void DisplayItemList::Raster(SkCanvas* canvas,
@@ -182,16 +193,34 @@ void DisplayItemList::Raster(SkCanvas* canvas,
if (!GetCanvasClipBounds(canvas, &canvas_playback_rect))
return;
- std::vector<size_t> indices;
- rtree_.Search(canvas_playback_rect, &indices);
- for (size_t index : indices) {
- RasterItem(items_[index], canvas, callback);
-
+ std::vector<size_t> indices = rtree_.Search(canvas_playback_rect);
+ for (size_t i = 0; i < indices.size(); ++i) {
// We use a callback during solid color analysis on the compositor thread to
// break out early. Since we're handling a sequence of pictures via rtree
// query results ourselves, we have to respect the callback and early out.
if (callback && callback->abort())
break;
+
+ const DisplayItem& item = items_[indices[i]];
+ // Optimize empty begin/end compositing and merge begin/draw/end compositing
+ // where possible.
+ // TODO(enne): remove empty clips here too?
+ // TODO(enne): does this happen recursively? Or is this good enough?
+ if (i < indices.size() - 2 && item.type == DisplayItem::COMPOSITING) {
+ const DisplayItem& second = items_[indices[i + 1]];
+ const DisplayItem& third = items_[indices[i + 2]];
+ if (second.type == DisplayItem::DRAWING &&
+ third.type == DisplayItem::END_COMPOSITING) {
+ if (MergeAndDrawIfPossible(
+ static_cast<const CompositingDisplayItem&>(item),
+ static_cast<const DrawingDisplayItem&>(second), canvas)) {
+ i += 2;
+ continue;
+ }
+ }
+ }
+
+ RasterItem(item, canvas, callback);
}
}
@@ -222,8 +251,8 @@ bool DisplayItemList::IsSuitableForGpuRasterization() const {
return all_items_are_suitable_for_gpu_rasterization_;
}
-int DisplayItemList::ApproximateOpCount() const {
- return approximate_op_count_;
+size_t DisplayItemList::OpCount() const {
+ return op_count_;
}
size_t DisplayItemList::ApproximateMemoryUsage() const {
@@ -282,7 +311,7 @@ size_t DisplayItemList::ApproximateMemoryUsage() const {
}
bool DisplayItemList::ShouldBeAnalyzedForSolidColor() const {
- return ApproximateOpCount() <= kOpCountThatIsOkToAnalyze;
+ return OpCount() <= kOpCountThatIsOkToAnalyze;
}
void DisplayItemList::EmitTraceSnapshot() const {
@@ -395,15 +424,15 @@ DisplayItemList::CreateTracedValue(bool include_items) const {
state->EndArray();
state->BeginArray("cullRect");
- state->AppendInteger(item.picture->cullRect().x());
- state->AppendInteger(item.picture->cullRect().y());
- state->AppendInteger(item.picture->cullRect().width());
- state->AppendInteger(item.picture->cullRect().height());
+ state->AppendInteger(item.bounds.x());
+ state->AppendInteger(item.bounds.y());
+ state->AppendInteger(item.bounds.width());
+ state->AppendInteger(item.bounds.height());
state->EndArray();
std::string b64_picture;
- PictureDebugUtil::SerializeAsBase64(ToSkPicture(item.picture).get(),
- &b64_picture);
+ PictureDebugUtil::SerializeAsBase64(
+ ToSkPicture(item.picture, item.bounds).get(), &b64_picture);
state->SetString("skp64", b64_picture);
state->EndDictionary();
break;
@@ -462,7 +491,7 @@ DisplayItemList::CreateTracedValue(bool include_items) const {
SkCanvas* canvas = recorder.beginRecording(bounds.width(), bounds.height());
canvas->translate(-bounds.x(), -bounds.y());
canvas->clipRect(gfx::RectToSkRect(bounds));
- Raster(canvas, nullptr, gfx::Rect(), 1.f);
+ Raster(canvas);
sk_sp<SkPicture> picture = recorder.finishRecordingAsPicture();
std::string b64_picture;
@@ -476,13 +505,28 @@ DisplayItemList::CreateTracedValue(bool include_items) const {
void DisplayItemList::GenerateDiscardableImagesMetadata() {
// This should be only called once.
DCHECK(image_map_.empty());
+ if (!has_discardable_images_)
+ return;
gfx::Rect bounds = rtree_.GetBounds();
DiscardableImageMap::ScopedMetadataGenerator generator(
&image_map_, gfx::Size(bounds.right(), bounds.bottom()));
- auto* canvas = generator.canvas();
- for (const auto& item : items_)
- RasterItem(item, canvas, nullptr);
+ GatherDiscardableImages(generator.image_store());
+}
+
+void DisplayItemList::GatherDiscardableImages(
+ DiscardableImageStore* image_store) const {
+ // TODO(khushalsagar): Could we avoid this if the data was already stored in
+ // the |image_map_|?
+ SkCanvas* canvas = image_store->GetNoDrawCanvas();
+ for (const auto& item : items_) {
+ if (item.type == DisplayItem::DRAWING) {
+ const auto& drawing_item = static_cast<const DrawingDisplayItem&>(item);
+ image_store->GatherDiscardableImages(drawing_item.picture.get());
+ } else {
+ RasterItem(item, canvas, nullptr);
+ }
+ }
}
void DisplayItemList::GetDiscardableImagesInRect(
@@ -494,7 +538,7 @@ void DisplayItemList::GetDiscardableImagesInRect(
target_color_space, images);
}
-gfx::Rect DisplayItemList::GetRectForImage(ImageId image_id) const {
+gfx::Rect DisplayItemList::GetRectForImage(PaintImage::Id image_id) const {
return image_map_.GetRectForImage(image_id);
}
diff --git a/chromium/cc/paint/display_item_list.h b/chromium/cc/paint/display_item_list.h
index b65707dc6e0..893dc9fbc4f 100644
--- a/chromium/cc/paint/display_item_list.h
+++ b/chromium/cc/paint/display_item_list.h
@@ -18,6 +18,7 @@
#include "cc/base/rtree.h"
#include "cc/paint/discardable_image_map.h"
#include "cc/paint/display_item.h"
+#include "cc/paint/drawing_display_item.h"
#include "cc/paint/image_id.h"
#include "cc/paint/paint_export.h"
#include "third_party/skia/include/core/SkPicture.h"
@@ -41,13 +42,8 @@ class CC_PAINT_EXPORT DisplayItemList
public:
DisplayItemList();
- // TODO(trchen): Deprecated. Apply clip and scale on the canvas instead.
void Raster(SkCanvas* canvas,
- SkPicture::AbortCallback* callback,
- const gfx::Rect& canvas_target_playback_rect,
- float contents_scale) const;
-
- void Raster(SkCanvas* canvas, SkPicture::AbortCallback* callback) const;
+ SkPicture::AbortCallback* callback = nullptr) const;
// Because processing happens in these CreateAndAppend functions, all the set
// up for the item should be done via the args, which is why the return type
@@ -119,7 +115,10 @@ class CC_PAINT_EXPORT DisplayItemList
visual_rects_.push_back(visual_rect);
GrowCurrentBeginItemVisualRect(visual_rect);
- return AllocateAndConstruct<DisplayItemType>(std::forward<Args>(args)...);
+ const auto& item =
+ AllocateAndConstruct<DisplayItemType>(std::forward<Args>(args)...);
+ has_discardable_images_ |= item.picture->HasDiscardableImages();
+ return item;
}
// Called after all items are appended, to process the items and, if
@@ -131,7 +130,7 @@ class CC_PAINT_EXPORT DisplayItemList
}
bool IsSuitableForGpuRasterization() const;
- int ApproximateOpCount() const;
+ size_t OpCount() const;
size_t ApproximateMemoryUsage() const;
bool ShouldBeAnalyzedForSolidColor() const;
@@ -142,7 +141,7 @@ class CC_PAINT_EXPORT DisplayItemList
float contents_scale,
const gfx::ColorSpace& target_color_space,
std::vector<DrawImage>* images);
- gfx::Rect GetRectForImage(ImageId image_id) const;
+ gfx::Rect GetRectForImage(PaintImage::Id image_id) const;
void SetRetainVisualRectsForTesting(bool retain) {
retain_visual_rects_ = retain;
@@ -160,6 +159,13 @@ class CC_PAINT_EXPORT DisplayItemList
return items_.end();
}
+ void GatherDiscardableImages(DiscardableImageStore* image_store) const;
+ const DiscardableImageMap& discardable_image_map_for_testing() const {
+ return image_map_;
+ }
+
+ bool has_discardable_images() const { return has_discardable_images_; }
+
private:
FRIEND_TEST_ALL_PREFIXES(DisplayItemListTest, AsValueWithNoItems);
FRIEND_TEST_ALL_PREFIXES(DisplayItemListTest, AsValueWithItems);
@@ -177,7 +183,7 @@ class CC_PAINT_EXPORT DisplayItemList
const DisplayItemType& AllocateAndConstruct(Args&&... args) {
auto* item = &items_.AllocateAndConstruct<DisplayItemType>(
std::forward<Args>(args)...);
- approximate_op_count_ += item->ApproximateOpCount();
+ op_count_ += item->OpCount();
return *item;
}
@@ -193,11 +199,12 @@ class CC_PAINT_EXPORT DisplayItemList
std::vector<gfx::Rect> visual_rects_;
std::vector<size_t> begin_item_indices_;
- int approximate_op_count_ = 0;
+ size_t op_count_ = 0u;
bool all_items_are_suitable_for_gpu_rasterization_ = true;
// For testing purposes only. Whether to keep visual rects across calls to
// Finalize().
bool retain_visual_rects_ = false;
+ bool has_discardable_images_ = false;
friend class base::RefCountedThreadSafe<DisplayItemList>;
FRIEND_TEST_ALL_PREFIXES(DisplayItemListTest, ApproximateMemoryUsage);
diff --git a/chromium/cc/paint/display_item_list_unittest.cc b/chromium/cc/paint/display_item_list_unittest.cc
index f1b9e759f9b..e4682f3bc56 100644
--- a/chromium/cc/paint/display_item_list_unittest.cc
+++ b/chromium/cc/paint/display_item_list_unittest.cc
@@ -17,16 +17,17 @@
#include "cc/paint/compositing_display_item.h"
#include "cc/paint/drawing_display_item.h"
#include "cc/paint/filter_display_item.h"
-
#include "cc/paint/float_clip_display_item.h"
#include "cc/paint/paint_canvas.h"
#include "cc/paint/paint_flags.h"
#include "cc/paint/paint_record.h"
#include "cc/paint/paint_recorder.h"
+#include "cc/paint/skia_paint_canvas.h"
#include "cc/paint/transform_display_item.h"
#include "cc/test/geometry_test_utils.h"
#include "cc/test/pixel_test_utils.h"
#include "cc/test/skia_common.h"
+#include "cc/test/test_skcanvas.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -80,6 +81,19 @@ sk_sp<const PaintRecord> CreateRectPicture(const gfx::Rect& bounds) {
return recorder.finishRecordingAsPicture();
}
+sk_sp<const PaintRecord> CreateRectPictureWithAlpha(const gfx::Rect& bounds,
+ uint8_t alpha) {
+ PaintRecorder recorder;
+ PaintCanvas* canvas =
+ recorder.beginRecording(bounds.width(), bounds.height());
+ PaintFlags flags;
+ flags.setAlpha(alpha);
+ canvas->drawRect(
+ SkRect::MakeXYWH(bounds.x(), bounds.y(), bounds.width(), bounds.height()),
+ flags);
+ return recorder.finishRecordingAsPicture();
+}
+
void AppendFirstSerializationTestPicture(scoped_refptr<DisplayItemList> list,
const gfx::Size& layer_size) {
gfx::PointF offset(2.f, 3.f);
@@ -88,12 +102,13 @@ void AppendFirstSerializationTestPicture(scoped_refptr<DisplayItemList> list,
PaintFlags red_paint;
red_paint.setColor(SK_ColorRED);
- PaintCanvas* canvas = recorder.beginRecording(SkRect::MakeXYWH(
- offset.x(), offset.y(), layer_size.width(), layer_size.height()));
+ SkRect bounds = SkRect::MakeXYWH(offset.x(), offset.y(), layer_size.width(),
+ layer_size.height());
+ PaintCanvas* canvas = recorder.beginRecording(bounds);
canvas->translate(offset.x(), offset.y());
canvas->drawRect(SkRect::MakeWH(4, 4), red_paint);
list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
- kVisualRect, recorder.finishRecordingAsPicture());
+ kVisualRect, recorder.finishRecordingAsPicture(), bounds);
}
} // namespace
@@ -116,7 +131,8 @@ TEST(DisplayItemListTest, SingleDrawingItem) {
canvas->drawRect(SkRect::MakeLTRB(0.f, 0.f, 60.f, 60.f), red_paint);
canvas->drawRect(SkRect::MakeLTRB(50.f, 50.f, 75.f, 75.f), blue_flags);
list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
- kVisualRect, recorder.finishRecordingAsPicture());
+ kVisualRect, recorder.finishRecordingAsPicture(),
+ gfx::RectFToSkRect(recording_rect));
list->Finalize();
DrawDisplayList(pixels, layer_rect, list);
@@ -156,7 +172,8 @@ TEST(DisplayItemListTest, ClipItem) {
canvas->translate(first_offset.x(), first_offset.y());
canvas->drawRect(SkRect::MakeWH(60, 60), red_paint);
list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
- kVisualRect, recorder.finishRecordingAsPicture());
+ kVisualRect, recorder.finishRecordingAsPicture(),
+ gfx::RectFToSkRect(first_recording_rect));
gfx::Rect clip_rect(60, 60, 10, 10);
list->CreateAndAppendPairedBeginItem<ClipDisplayItem>(
@@ -169,7 +186,8 @@ TEST(DisplayItemListTest, ClipItem) {
canvas->translate(second_offset.x(), second_offset.y());
canvas->drawRect(SkRect::MakeLTRB(50.f, 50.f, 75.f, 75.f), blue_flags);
list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
- kVisualRect, recorder.finishRecordingAsPicture());
+ kVisualRect, recorder.finishRecordingAsPicture(),
+ gfx::RectFToSkRect(second_recording_rect));
list->CreateAndAppendPairedEndItem<EndClipDisplayItem>();
list->Finalize();
@@ -213,7 +231,8 @@ TEST(DisplayItemListTest, TransformItem) {
canvas->translate(first_offset.x(), first_offset.y());
canvas->drawRect(SkRect::MakeWH(60, 60), red_paint);
list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
- kVisualRect, recorder.finishRecordingAsPicture());
+ kVisualRect, recorder.finishRecordingAsPicture(),
+ gfx::RectFToSkRect(first_recording_rect));
gfx::Transform transform;
transform.Rotate(45.0);
@@ -226,7 +245,8 @@ TEST(DisplayItemListTest, TransformItem) {
canvas->translate(second_offset.x(), second_offset.y());
canvas->drawRect(SkRect::MakeLTRB(50.f, 50.f, 75.f, 75.f), blue_flags);
list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
- kVisualRect, recorder.finishRecordingAsPicture());
+ kVisualRect, recorder.finishRecordingAsPicture(),
+ gfx::RectFToSkRect(second_recording_rect));
list->CreateAndAppendPairedEndItem<EndTransformDisplayItem>();
list->Finalize();
@@ -289,14 +309,16 @@ TEST(DisplayItemListTest, FilterItem) {
PaintFlags red_paint;
red_paint.setColor(SK_ColorRED);
- PaintCanvas* canvas = recorder.beginRecording(
- SkRect::MakeXYWH(0, 0, layer_rect.width(), layer_rect.height()));
+ SkRect bounds =
+ SkRect::MakeXYWH(0, 0, layer_rect.width(), layer_rect.height());
+ PaintCanvas* canvas = recorder.beginRecording(bounds);
canvas->drawRect(
SkRect::MakeLTRB(filter_bounds.x(), filter_bounds.y(),
filter_bounds.right(), filter_bounds.bottom()),
red_paint);
list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
- ToNearestRect(filter_bounds), recorder.finishRecordingAsPicture());
+ ToNearestRect(filter_bounds), recorder.finishRecordingAsPicture(),
+ bounds);
}
list->CreateAndAppendPairedEndItem<EndFilterDisplayItem>();
@@ -330,11 +352,12 @@ TEST(DisplayItemListTest, ApproximateMemoryUsage) {
for (int i = 0; i < kNumCommandsInTestSkPicture; i++)
canvas->drawRect(SkRect(), blue_flags);
sk_sp<PaintRecord> record = recorder.finishRecordingAsPicture();
- size_t record_size = record->approximateBytesUsed();
+ size_t record_size = record->bytes_used();
ASSERT_GE(record_size, kNumCommandsInTestSkPicture * sizeof(SkRect));
auto list = make_scoped_refptr(new DisplayItemList);
- list->CreateAndAppendDrawingItem<DrawingDisplayItem>(kVisualRect, record);
+ list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
+ kVisualRect, record, gfx::RectToSkRect(layer_rect));
list->Finalize();
memory_usage = list->ApproximateMemoryUsage();
EXPECT_GE(memory_usage, record_size);
@@ -394,7 +417,8 @@ TEST(DisplayItemListTest, SizeOne) {
auto list = make_scoped_refptr(new DisplayItemList);
gfx::Rect drawing_bounds(5, 6, 1, 1);
list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
- drawing_bounds, CreateRectPicture(drawing_bounds));
+ drawing_bounds, CreateRectPicture(drawing_bounds),
+ gfx::RectToSkRect(drawing_bounds));
EXPECT_EQ(1u, list->size());
}
@@ -414,7 +438,8 @@ TEST(DisplayItemListTest, AppendVisualRectSimple) {
gfx::Rect drawing_bounds(5, 6, 7, 8);
list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
- drawing_bounds, CreateRectPicture(drawing_bounds));
+ drawing_bounds, CreateRectPicture(drawing_bounds),
+ gfx::RectToSkRect(drawing_bounds));
EXPECT_EQ(1u, list->size());
EXPECT_RECT_EQ(drawing_bounds, list->VisualRectForTesting(0));
@@ -466,7 +491,8 @@ TEST(DisplayItemListTest, AppendVisualRectBlockContainingDrawing) {
gfx::Rect drawing_bounds(5, 6, 1, 1);
list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
- drawing_bounds, CreateRectPicture(drawing_bounds));
+ drawing_bounds, CreateRectPicture(drawing_bounds),
+ gfx::RectToSkRect(drawing_bounds));
list->CreateAndAppendPairedEndItem<EndClipDisplayItem>();
@@ -487,7 +513,8 @@ TEST(DisplayItemListTest, AppendVisualRectBlockContainingEscapedDrawing) {
gfx::Rect drawing_bounds(1, 2, 3, 4);
list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
- drawing_bounds, CreateRectPicture(drawing_bounds));
+ drawing_bounds, CreateRectPicture(drawing_bounds),
+ gfx::RectToSkRect(drawing_bounds));
list->CreateAndAppendPairedEndItem<EndClipDisplayItem>();
@@ -506,7 +533,8 @@ TEST(DisplayItemListTest,
gfx::Rect drawing_a_bounds(1, 2, 3, 4);
list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
- drawing_a_bounds, CreateRectPicture(drawing_a_bounds));
+ drawing_a_bounds, CreateRectPicture(drawing_a_bounds),
+ gfx::RectToSkRect(drawing_a_bounds));
gfx::Rect clip_bounds(5, 6, 7, 8);
list->CreateAndAppendPairedBeginItem<ClipDisplayItem>(
@@ -514,7 +542,8 @@ TEST(DisplayItemListTest,
gfx::Rect drawing_b_bounds(13, 14, 1, 1);
list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
- drawing_b_bounds, CreateRectPicture(drawing_b_bounds));
+ drawing_b_bounds, CreateRectPicture(drawing_b_bounds),
+ gfx::RectToSkRect(drawing_b_bounds));
list->CreateAndAppendPairedEndItem<EndClipDisplayItem>();
@@ -536,13 +565,15 @@ TEST(DisplayItemListTest, AppendVisualRectTwoBlocksTwoDrawings) {
gfx::Rect drawing_a_bounds(5, 6, 1, 1);
list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
- drawing_a_bounds, CreateRectPicture(drawing_a_bounds));
+ drawing_a_bounds, CreateRectPicture(drawing_a_bounds),
+ gfx::RectToSkRect(drawing_a_bounds));
list->CreateAndAppendPairedBeginItem<TransformDisplayItem>(gfx::Transform());
gfx::Rect drawing_b_bounds(7, 8, 1, 1);
list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
- drawing_b_bounds, CreateRectPicture(drawing_b_bounds));
+ drawing_b_bounds, CreateRectPicture(drawing_b_bounds),
+ gfx::RectToSkRect(drawing_b_bounds));
list->CreateAndAppendPairedEndItem<EndTransformDisplayItem>();
list->CreateAndAppendPairedEndItem<EndClipDisplayItem>();
@@ -571,13 +602,15 @@ TEST(DisplayItemListTest,
gfx::Rect drawing_a_bounds(5, 6, 1, 1);
list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
- drawing_a_bounds, CreateRectPicture(drawing_a_bounds));
+ drawing_a_bounds, CreateRectPicture(drawing_a_bounds),
+ gfx::RectToSkRect(drawing_a_bounds));
list->CreateAndAppendPairedBeginItem<TransformDisplayItem>(gfx::Transform());
gfx::Rect drawing_b_bounds(1, 2, 3, 4);
list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
- drawing_b_bounds, CreateRectPicture(drawing_b_bounds));
+ drawing_b_bounds, CreateRectPicture(drawing_b_bounds),
+ gfx::RectToSkRect(drawing_b_bounds));
list->CreateAndAppendPairedEndItem<EndTransformDisplayItem>();
list->CreateAndAppendPairedEndItem<EndClipDisplayItem>();
@@ -606,13 +639,15 @@ TEST(DisplayItemListTest,
gfx::Rect drawing_a_bounds(1, 2, 3, 4);
list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
- drawing_a_bounds, CreateRectPicture(drawing_a_bounds));
+ drawing_a_bounds, CreateRectPicture(drawing_a_bounds),
+ gfx::RectToSkRect(drawing_a_bounds));
list->CreateAndAppendPairedBeginItem<TransformDisplayItem>(gfx::Transform());
gfx::Rect drawing_b_bounds(7, 8, 1, 1);
list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
- drawing_b_bounds, CreateRectPicture(drawing_b_bounds));
+ drawing_b_bounds, CreateRectPicture(drawing_b_bounds),
+ gfx::RectToSkRect(drawing_b_bounds));
list->CreateAndAppendPairedEndItem<EndTransformDisplayItem>();
list->CreateAndAppendPairedEndItem<EndClipDisplayItem>();
@@ -641,13 +676,15 @@ TEST(DisplayItemListTest,
gfx::Rect drawing_a_bounds(13, 14, 1, 1);
list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
- drawing_a_bounds, CreateRectPicture(drawing_a_bounds));
+ drawing_a_bounds, CreateRectPicture(drawing_a_bounds),
+ gfx::RectToSkRect(drawing_a_bounds));
list->CreateAndAppendPairedBeginItem<TransformDisplayItem>(gfx::Transform());
gfx::Rect drawing_b_bounds(1, 2, 3, 4);
list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
- drawing_b_bounds, CreateRectPicture(drawing_b_bounds));
+ drawing_b_bounds, CreateRectPicture(drawing_b_bounds),
+ gfx::RectToSkRect(drawing_b_bounds));
list->CreateAndAppendPairedEndItem<EndTransformDisplayItem>();
list->CreateAndAppendPairedEndItem<EndClipDisplayItem>();
@@ -704,4 +741,112 @@ TEST(DisplayItemListTest, AppendVisualRectBlockContainingFilterNoDrawings) {
EXPECT_RECT_EQ(filter_bounds, list->VisualRectForTesting(3));
}
+// Verify that raster time optimizations for compositing item / draw single op /
+// end compositing item can be collapsed together into a single draw op
+// with the opacity from the compositing item folded in.
+TEST(DisplayItemListTest, SaveDrawRestore) {
+ auto list = make_scoped_refptr(new DisplayItemList);
+
+ list->CreateAndAppendPairedBeginItem<CompositingDisplayItem>(
+ 80, SkBlendMode::kSrcOver, nullptr, nullptr, false);
+ list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
+ kVisualRect, CreateRectPictureWithAlpha(kVisualRect, 40),
+ gfx::RectToSkRect(kVisualRect));
+ list->CreateAndAppendPairedEndItem<EndCompositingDisplayItem>();
+ list->Finalize();
+
+ SaveCountingCanvas canvas;
+ list->Raster(&canvas);
+
+ EXPECT_EQ(0, canvas.save_count_);
+ EXPECT_EQ(0, canvas.restore_count_);
+ EXPECT_EQ(gfx::RectToSkRect(kVisualRect), canvas.draw_rect_);
+
+ float expected_alpha = 80 * 40 / 255.f;
+ EXPECT_LE(std::abs(expected_alpha - canvas.paint_.getAlpha()), 1.f);
+}
+
+// Verify that compositing item / end compositing item is a noop.
+// Here we're testing that Skia does an optimization that skips
+// save/restore with nothing in between. If skia stops doing this
+// then we should reimplement this optimization in display list raster.
+TEST(DisplayItemListTest, SaveRestoreNoops) {
+ auto list = make_scoped_refptr(new DisplayItemList);
+
+ list->CreateAndAppendPairedBeginItem<CompositingDisplayItem>(
+ 80, SkBlendMode::kSrcOver, nullptr, nullptr, false);
+ list->CreateAndAppendPairedEndItem<EndCompositingDisplayItem>();
+ list->CreateAndAppendPairedBeginItem<CompositingDisplayItem>(
+ 255, SkBlendMode::kSrcOver, nullptr, nullptr, false);
+ list->CreateAndAppendPairedEndItem<EndCompositingDisplayItem>();
+ list->CreateAndAppendPairedBeginItem<CompositingDisplayItem>(
+ 255, SkBlendMode::kSrc, nullptr, nullptr, false);
+ list->CreateAndAppendPairedEndItem<EndCompositingDisplayItem>();
+ list->Finalize();
+
+ SaveCountingCanvas canvas;
+ list->Raster(&canvas);
+
+ EXPECT_EQ(0, canvas.save_count_);
+ EXPECT_EQ(0, canvas.restore_count_);
+}
+
+// The same as SaveDrawRestore, but with save flags that prevent the
+// optimization.
+TEST(DisplayItemListTest, SaveDrawRestoreFail_BadSaveFlags) {
+ auto list = make_scoped_refptr(new DisplayItemList);
+
+ // Use a blend mode that's not compatible with the SaveDrawRestore
+ // optimization.
+ list->CreateAndAppendPairedBeginItem<CompositingDisplayItem>(
+ 80, SkBlendMode::kSrc, nullptr, nullptr, false);
+ list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
+ kVisualRect, CreateRectPictureWithAlpha(kVisualRect, 40),
+ gfx::RectToSkRect(kVisualRect));
+ list->CreateAndAppendPairedEndItem<EndCompositingDisplayItem>();
+ list->Finalize();
+
+ SaveCountingCanvas canvas;
+ list->Raster(&canvas);
+
+ EXPECT_EQ(1, canvas.save_count_);
+ EXPECT_EQ(1, canvas.restore_count_);
+ EXPECT_EQ(gfx::RectToSkRect(kVisualRect), canvas.draw_rect_);
+ EXPECT_LE(40, canvas.paint_.getAlpha());
+}
+
+// The same as SaveDrawRestore, but with too many ops in the PaintRecord.
+TEST(DisplayItemListTest, SaveDrawRestoreFail_TooManyOps) {
+ sk_sp<const PaintRecord> record;
+ SkRect bounds = SkRect::MakeWH(kVisualRect.width(), kVisualRect.height());
+ {
+ PaintRecorder recorder;
+ PaintCanvas* canvas = recorder.beginRecording(bounds);
+ PaintFlags flags;
+ flags.setAlpha(40);
+ canvas->drawRect(gfx::RectToSkRect(kVisualRect), flags);
+ // Add an extra op here.
+ canvas->drawRect(gfx::RectToSkRect(kVisualRect), flags);
+ record = recorder.finishRecordingAsPicture();
+ }
+ EXPECT_GT(record->size(), 1u);
+
+ auto list = make_scoped_refptr(new DisplayItemList);
+
+ list->CreateAndAppendPairedBeginItem<CompositingDisplayItem>(
+ 80, SkBlendMode::kSrcOver, nullptr, nullptr, false);
+ list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
+ kVisualRect, std::move(record), bounds);
+ list->CreateAndAppendPairedEndItem<EndCompositingDisplayItem>();
+ list->Finalize();
+
+ SaveCountingCanvas canvas;
+ list->Raster(&canvas);
+
+ EXPECT_EQ(1, canvas.save_count_);
+ EXPECT_EQ(1, canvas.restore_count_);
+ EXPECT_EQ(gfx::RectToSkRect(kVisualRect), canvas.draw_rect_);
+ EXPECT_LE(40, canvas.paint_.getAlpha());
+}
+
} // namespace cc
diff --git a/chromium/cc/paint/draw_image.cc b/chromium/cc/paint/draw_image.cc
index 6c0bb644864..6ffb3ae839b 100644
--- a/chromium/cc/paint/draw_image.cc
+++ b/chromium/cc/paint/draw_image.cc
@@ -23,19 +23,18 @@ bool ExtractScale(const SkMatrix& matrix, SkSize* scale) {
} // namespace
DrawImage::DrawImage()
- : image_(nullptr),
- src_rect_(SkIRect::MakeXYWH(0, 0, 0, 0)),
+ : src_rect_(SkIRect::MakeXYWH(0, 0, 0, 0)),
filter_quality_(kNone_SkFilterQuality),
matrix_(SkMatrix::I()),
scale_(SkSize::Make(1.f, 1.f)),
matrix_is_decomposable_(true) {}
-DrawImage::DrawImage(sk_sp<const SkImage> image,
+DrawImage::DrawImage(PaintImage image,
const SkIRect& src_rect,
SkFilterQuality filter_quality,
const SkMatrix& matrix,
const gfx::ColorSpace& target_color_space)
- : image_(std::move(image)),
+ : paint_image_(std::move(image)),
src_rect_(src_rect),
filter_quality_(filter_quality),
matrix_(matrix),
diff --git a/chromium/cc/paint/draw_image.h b/chromium/cc/paint/draw_image.h
index 78513b90d1e..fe84f0606ef 100644
--- a/chromium/cc/paint/draw_image.h
+++ b/chromium/cc/paint/draw_image.h
@@ -6,6 +6,7 @@
#define CC_PAINT_DRAW_IMAGE_H_
#include "cc/paint/paint_export.h"
+#include "cc/paint/paint_image.h"
#include "third_party/skia/include/core/SkFilterQuality.h"
#include "third_party/skia/include/core/SkImage.h"
#include "third_party/skia/include/core/SkMatrix.h"
@@ -21,7 +22,7 @@ namespace cc {
class CC_PAINT_EXPORT DrawImage {
public:
DrawImage();
- DrawImage(sk_sp<const SkImage> image,
+ DrawImage(PaintImage image,
const SkIRect& src_rect,
SkFilterQuality filter_quality,
const SkMatrix& matrix,
@@ -29,7 +30,8 @@ class CC_PAINT_EXPORT DrawImage {
DrawImage(const DrawImage& other);
~DrawImage();
- const sk_sp<const SkImage>& image() const { return image_; }
+ const PaintImage& paint_image() const { return paint_image_; }
+ const sk_sp<SkImage>& image() const { return paint_image_.sk_image(); }
const SkSize& scale() const { return scale_; }
const SkIRect& src_rect() const { return src_rect_; }
SkFilterQuality filter_quality() const { return filter_quality_; }
@@ -42,16 +44,16 @@ class CC_PAINT_EXPORT DrawImage {
DrawImage ApplyScale(float scale) const {
SkMatrix scaled_matrix = matrix_;
scaled_matrix.preScale(scale, scale);
- return DrawImage(image_, src_rect_, filter_quality_, scaled_matrix,
+ return DrawImage(paint_image_, src_rect_, filter_quality_, scaled_matrix,
target_color_space_);
}
DrawImage ApplyTargetColorSpace(const gfx::ColorSpace& target_color_space) {
- return DrawImage(image_, src_rect_, filter_quality_, matrix_,
+ return DrawImage(paint_image_, src_rect_, filter_quality_, matrix_,
target_color_space);
}
private:
- sk_sp<const SkImage> image_;
+ PaintImage paint_image_;
SkIRect src_rect_;
SkFilterQuality filter_quality_;
SkMatrix matrix_;
diff --git a/chromium/cc/paint/drawing_display_item.cc b/chromium/cc/paint/drawing_display_item.cc
index 60b09ee0e27..5fc920bcd18 100644
--- a/chromium/cc/paint/drawing_display_item.cc
+++ b/chromium/cc/paint/drawing_display_item.cc
@@ -8,23 +8,25 @@
namespace cc {
-DrawingDisplayItem::DrawingDisplayItem() : DisplayItem(DRAWING) {}
+DrawingDisplayItem::DrawingDisplayItem()
+ : DisplayItem(DRAWING), bounds(SkRect::MakeEmpty()) {}
-DrawingDisplayItem::DrawingDisplayItem(sk_sp<const PaintRecord> record)
- : DisplayItem(DRAWING), picture(std::move(record)) {}
+DrawingDisplayItem::DrawingDisplayItem(sk_sp<const PaintRecord> record,
+ const SkRect& bounds)
+ : DisplayItem(DRAWING), picture(std::move(record)), bounds(bounds) {}
DrawingDisplayItem::DrawingDisplayItem(const DrawingDisplayItem& item)
- : DisplayItem(DRAWING), picture(item.picture) {}
+ : DisplayItem(DRAWING), picture(item.picture), bounds(item.bounds) {}
DrawingDisplayItem::~DrawingDisplayItem() = default;
size_t DrawingDisplayItem::ExternalMemoryUsage() const {
- return picture->approximateBytesUsed();
+ return picture->bytes_used();
}
DISABLE_CFI_PERF
-int DrawingDisplayItem::ApproximateOpCount() const {
- return picture->approximateOpCount();
+size_t DrawingDisplayItem::OpCount() const {
+ return picture->size();
}
} // namespace cc
diff --git a/chromium/cc/paint/drawing_display_item.h b/chromium/cc/paint/drawing_display_item.h
index 56c7b17aef2..a746a0723f0 100644
--- a/chromium/cc/paint/drawing_display_item.h
+++ b/chromium/cc/paint/drawing_display_item.h
@@ -17,14 +17,16 @@ namespace cc {
class CC_PAINT_EXPORT DrawingDisplayItem : public DisplayItem {
public:
DrawingDisplayItem();
- explicit DrawingDisplayItem(sk_sp<const PaintRecord> record);
+ explicit DrawingDisplayItem(sk_sp<const PaintRecord> record,
+ const SkRect& bounds);
explicit DrawingDisplayItem(const DrawingDisplayItem& item);
~DrawingDisplayItem() override;
size_t ExternalMemoryUsage() const;
- int ApproximateOpCount() const;
+ size_t OpCount() const;
const sk_sp<const PaintRecord> picture;
+ SkRect bounds;
};
} // namespace cc
diff --git a/chromium/cc/paint/filter_display_item.h b/chromium/cc/paint/filter_display_item.h
index c4f18dcbc85..ad40ff977e2 100644
--- a/chromium/cc/paint/filter_display_item.h
+++ b/chromium/cc/paint/filter_display_item.h
@@ -25,7 +25,7 @@ class CC_PAINT_EXPORT FilterDisplayItem : public DisplayItem {
// enough.
return filters.size() * sizeof(filters.at(0));
}
- int ApproximateOpCount() const { return 1; }
+ int OpCount() const { return 1; }
const FilterOperations filters;
const gfx::RectF bounds;
@@ -37,7 +37,7 @@ class CC_PAINT_EXPORT EndFilterDisplayItem : public DisplayItem {
EndFilterDisplayItem();
~EndFilterDisplayItem() override;
- int ApproximateOpCount() const { return 0; }
+ int OpCount() const { return 0; }
};
} // namespace cc
diff --git a/chromium/cc/paint/float_clip_display_item.h b/chromium/cc/paint/float_clip_display_item.h
index 43d751b36ce..b2703c860ca 100644
--- a/chromium/cc/paint/float_clip_display_item.h
+++ b/chromium/cc/paint/float_clip_display_item.h
@@ -19,7 +19,7 @@ class CC_PAINT_EXPORT FloatClipDisplayItem : public DisplayItem {
~FloatClipDisplayItem() override;
size_t ExternalMemoryUsage() const { return 0; }
- int ApproximateOpCount() const { return 1; }
+ int OpCount() const { return 1; }
const gfx::RectF clip_rect;
};
@@ -29,7 +29,7 @@ class CC_PAINT_EXPORT EndFloatClipDisplayItem : public DisplayItem {
EndFloatClipDisplayItem();
~EndFloatClipDisplayItem() override;
- int ApproximateOpCount() const { return 0; }
+ int OpCount() const { return 0; }
};
} // namespace cc
diff --git a/chromium/cc/paint/image_id.h b/chromium/cc/paint/image_id.h
index 0ffaafd782f..015d6616eea 100644
--- a/chromium/cc/paint/image_id.h
+++ b/chromium/cc/paint/image_id.h
@@ -9,11 +9,16 @@
#include <unordered_set>
#include "base/containers/flat_set.h"
+#include "cc/paint/paint_image.h"
namespace cc {
-using ImageId = uint32_t;
-using ImageIdFlatSet = base::flat_set<ImageId>;
+using PaintImageIdFlatSet = base::flat_set<PaintImage::Id>;
+
+// TODO(khushalsagar): These are only used by the hijack canvas since it uses
+// an SkCanvas to replace images. Remove once that moves to PaintOpBuffer.
+using SkImageId = uint32_t;
+using SkImageIdFlatSet = base::flat_set<SkImageId>;
} // namespace cc
diff --git a/chromium/cc/paint/paint_canvas.cc b/chromium/cc/paint/paint_canvas.cc
index 4aab0652b19..a49b2b468fc 100644
--- a/chromium/cc/paint/paint_canvas.cc
+++ b/chromium/cc/paint/paint_canvas.cc
@@ -18,10 +18,6 @@ const char kIsPreviewMetafileKey[] = "CrIsPreviewMetafile";
namespace cc {
-bool ToPixmap(PaintCanvas* canvas, SkPixmap* output) {
- return canvas->ToPixmap(output);
-}
-
#if defined(OS_MACOSX)
void SetIsPreviewMetafile(PaintCanvas* canvas, bool is_preview) {
SkMetaData& meta = canvas->getMetaData();
diff --git a/chromium/cc/paint/paint_canvas.h b/chromium/cc/paint/paint_canvas.h
index daacc301788..b6f4c58016f 100644
--- a/chromium/cc/paint/paint_canvas.h
+++ b/chromium/cc/paint/paint_canvas.h
@@ -10,19 +10,26 @@
#include "base/memory/ref_counted.h"
#include "build/build_config.h"
#include "cc/paint/paint_export.h"
-#include "cc/paint/paint_record.h"
+#include "cc/paint/paint_image.h"
#include "third_party/skia/include/core/SkCanvas.h"
namespace cc {
class DisplayItemList;
class PaintFlags;
+class PaintOpBuffer;
+
+using PaintRecord = PaintOpBuffer;
class CC_PAINT_EXPORT PaintCanvas {
public:
+ PaintCanvas() {}
virtual ~PaintCanvas() {}
virtual SkMetaData& getMetaData() = 0;
+
+ // TODO(enne): this only appears to mostly be used to determine if this is
+ // recording or not, so could be simplified or removed.
virtual SkImageInfo imageInfo() const = 0;
// TODO(enne): It would be nice to get rid of flush() entirely, as it
@@ -33,15 +40,9 @@ class CC_PAINT_EXPORT PaintCanvas {
// both recording and gpu work.
virtual void flush() = 0;
- virtual SkISize getBaseLayerSize() const = 0;
- virtual bool writePixels(const SkImageInfo& info,
- const void* pixels,
- size_t row_bytes,
- int x,
- int y) = 0;
virtual int save() = 0;
virtual int saveLayer(const SkRect* bounds, const PaintFlags* flags) = 0;
- virtual int saveLayerAlpha(const SkRect* bounds, U8CPU alpha) = 0;
+ virtual int saveLayerAlpha(const SkRect* bounds, uint8_t alpha) = 0;
virtual void restore() = 0;
virtual int getSaveCount() const = 0;
@@ -92,6 +93,8 @@ class CC_PAINT_EXPORT PaintCanvas {
virtual bool getDeviceClipBounds(SkIRect* bounds) const = 0;
virtual void drawColor(SkColor color, SkBlendMode mode) = 0;
void drawColor(SkColor color) { drawColor(color, SkBlendMode::kSrcOver); }
+
+ // TODO(enne): This is a synonym for drawColor with kSrc. Remove it.
virtual void clear(SkColor color) = 0;
virtual void drawLine(SkScalar x0,
@@ -120,11 +123,11 @@ class CC_PAINT_EXPORT PaintCanvas {
SkScalar ry,
const PaintFlags& flags) = 0;
virtual void drawPath(const SkPath& path, const PaintFlags& flags) = 0;
- virtual void drawImage(sk_sp<const SkImage> image,
+ virtual void drawImage(const PaintImage& image,
SkScalar left,
SkScalar top,
const PaintFlags* flags) = 0;
- void drawImage(sk_sp<const SkImage> image, SkScalar left, SkScalar top) {
+ void drawImage(const PaintImage& image, SkScalar left, SkScalar top) {
drawImage(image, left, top, nullptr);
}
@@ -133,7 +136,7 @@ class CC_PAINT_EXPORT PaintCanvas {
kFast_SrcRectConstraint = SkCanvas::kFast_SrcRectConstraint,
};
- virtual void drawImageRect(sk_sp<const SkImage> image,
+ virtual void drawImageRect(const PaintImage& image,
const SkRect& src,
const SkRect& dst,
const PaintFlags* flags,
@@ -163,18 +166,14 @@ class CC_PAINT_EXPORT PaintCanvas {
virtual void drawDisplayItemList(
scoped_refptr<DisplayItemList> display_item_list) = 0;
+ // Unlike SkCanvas::drawPicture, this only plays back the PaintRecord and does
+ // not add an additional clip. This is closer to SkPicture::playback.
virtual void drawPicture(sk_sp<const PaintRecord> record) = 0;
virtual bool isClipEmpty() const = 0;
virtual bool isClipRect() const = 0;
virtual const SkMatrix& getTotalMatrix() const = 0;
- // For GraphicsContextCanvas only. Maybe this could be rewritten?
- virtual void temporary_internal_describeTopLayer(SkMatrix* matrix,
- SkIRect* clip_bounds) = 0;
-
- virtual bool ToPixmap(SkPixmap* output) = 0;
-
enum class AnnotationType {
URL,
NAMED_DESTINATION,
@@ -184,14 +183,8 @@ class CC_PAINT_EXPORT PaintCanvas {
const SkRect& rect,
sk_sp<SkData> data) = 0;
- // TODO(enne): maybe this should live on PaintRecord, but that's not
- // possible when PaintRecord is a typedef.
- virtual void PlaybackPaintRecord(sk_sp<const PaintRecord> record) = 0;
-
- protected:
- friend class PaintSurface;
- friend class PaintRecorder;
- friend CC_PAINT_EXPORT bool ToPixmap(PaintCanvas* canvas, SkPixmap* output);
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PaintCanvas);
};
class CC_PAINT_EXPORT PaintCanvasAutoRestore {
@@ -223,14 +216,6 @@ class CC_PAINT_EXPORT PaintCanvasAutoRestore {
int save_count_ = 0;
};
-// TODO(enne): Move all these functions into PaintCanvas. These are only
-// separate now to make the transition to concrete types easier by keeping
-// the base PaintCanvas type equivalent to the SkCanvas interface and
-// all these helper functions potentially operating on both.
-
-// PaintCanvas equivalent of skia::GetWritablePixels.
-CC_PAINT_EXPORT bool ToPixmap(PaintCanvas* canvas, SkPixmap* output);
-
// Following routines are used in print preview workflow to mark the
// preview metafile.
#if defined(OS_MACOSX)
diff --git a/chromium/cc/paint/paint_flags.cc b/chromium/cc/paint/paint_flags.cc
new file mode 100644
index 00000000000..e16a8bb8073
--- /dev/null
+++ b/chromium/cc/paint/paint_flags.cc
@@ -0,0 +1,42 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/paint/paint_flags.h"
+
+namespace cc {
+
+bool PaintFlags::IsSimpleOpacity() const {
+ uint32_t color = getColor();
+ if (SK_ColorTRANSPARENT != SkColorSetA(color, SK_AlphaTRANSPARENT))
+ return false;
+ if (!isSrcOver())
+ return false;
+ if (getLooper())
+ return false;
+ if (getPathEffect())
+ return false;
+ if (getShader())
+ return false;
+ if (getMaskFilter())
+ return false;
+ if (getColorFilter())
+ return false;
+ if (getImageFilter())
+ return false;
+ return true;
+}
+
+bool PaintFlags::SupportsFoldingAlpha() const {
+ if (!isSrcOver())
+ return false;
+ if (getColorFilter())
+ return false;
+ if (getImageFilter())
+ return false;
+ if (getLooper())
+ return false;
+ return true;
+}
+
+} // namespace cc
diff --git a/chromium/cc/paint/paint_flags.h b/chromium/cc/paint/paint_flags.h
index b7e96c68e2e..c884098e555 100644
--- a/chromium/cc/paint/paint_flags.h
+++ b/chromium/cc/paint/paint_flags.h
@@ -7,7 +7,6 @@
#include "base/compiler_specific.h"
#include "cc/paint/paint_export.h"
-#include "cc/paint/paint_shader.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkColorFilter.h"
#include "third_party/skia/include/core/SkDrawLooper.h"
@@ -15,10 +14,13 @@
#include "third_party/skia/include/core/SkMaskFilter.h"
#include "third_party/skia/include/core/SkPaint.h"
#include "third_party/skia/include/core/SkPathEffect.h"
+#include "third_party/skia/include/core/SkShader.h"
#include "third_party/skia/include/core/SkTypeface.h"
namespace cc {
+using PaintShader = SkShader;
+
class CC_PAINT_EXPORT PaintFlags {
public:
enum Style {
@@ -198,6 +200,14 @@ class CC_PAINT_EXPORT PaintFlags {
return paint_.computeFastBounds(orig, storage);
}
+ bool operator==(const PaintFlags& flags) { return flags.paint_ == paint_; }
+ bool operator!=(const PaintFlags& flags) { return flags.paint_ != paint_; }
+
+ // Returns true if this just represents an opacity blend when
+ // used as saveLayer flags.
+ bool IsSimpleOpacity() const;
+ bool SupportsFoldingAlpha() const;
+
private:
friend const SkPaint& ToSkPaint(const PaintFlags& flags);
friend const SkPaint* ToSkPaint(const PaintFlags* flags);
diff --git a/chromium/cc/paint/paint_image.cc b/chromium/cc/paint/paint_image.cc
new file mode 100644
index 00000000000..5575cbdad18
--- /dev/null
+++ b/chromium/cc/paint/paint_image.cc
@@ -0,0 +1,39 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/paint/paint_image.h"
+#include "base/atomic_sequence_num.h"
+
+namespace cc {
+namespace {
+base::StaticAtomicSequenceNumber s_next_id_;
+}
+
+PaintImage::PaintImage() = default;
+PaintImage::PaintImage(Id id,
+ sk_sp<SkImage> sk_image,
+ AnimationType animation_type,
+ CompletionState completion_state)
+ : id_(id),
+ sk_image_(std::move(sk_image)),
+ animation_type_(animation_type),
+ completion_state_(completion_state) {}
+PaintImage::PaintImage(const PaintImage& other) = default;
+PaintImage::PaintImage(PaintImage&& other) = default;
+PaintImage::~PaintImage() = default;
+
+PaintImage& PaintImage::operator=(const PaintImage& other) = default;
+PaintImage& PaintImage::operator=(PaintImage&& other) = default;
+
+bool PaintImage::operator==(const PaintImage& other) const {
+ return id_ == other.id_ && sk_image_ == other.sk_image_ &&
+ animation_type_ == other.animation_type_ &&
+ completion_state_ == other.completion_state_;
+}
+
+PaintImage::Id PaintImage::GetNextId() {
+ return s_next_id_.GetNext();
+}
+
+} // namespace cc
diff --git a/chromium/cc/paint/paint_image.h b/chromium/cc/paint/paint_image.h
new file mode 100644
index 00000000000..489cef27bd2
--- /dev/null
+++ b/chromium/cc/paint/paint_image.h
@@ -0,0 +1,66 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_PAINT_PAINT_IMAGE_H_
+#define CC_PAINT_PAINT_IMAGE_H_
+
+#include "base/logging.h"
+#include "cc/paint/paint_export.h"
+#include "third_party/skia/include/core/SkImage.h"
+
+namespace cc {
+
+// TODO(vmpstr): Add a persistent id to the paint image.
+class CC_PAINT_EXPORT PaintImage {
+ public:
+ using Id = int;
+
+ // An id that can be used for all non-lazy images. Note that if an image is
+ // not lazy, it does not mean that this id must be used; one can still use
+ // GetNextId to generate a stable id for such images.
+ static const Id kNonLazyStableId = -1;
+
+ // This is the id used in places where we are currently not plumbing the
+ // correct image id from blink.
+ // TODO(khushalsagar): Eliminate these cases. See crbug.com/722559.
+ static const Id kUnknownStableId = -2;
+
+ // TODO(vmpstr): Work towards removing "UNKNOWN" value.
+ enum class AnimationType { UNKNOWN, ANIMATED, VIDEO, STATIC };
+
+ // TODO(vmpstr): Work towards removing "UNKNOWN" value.
+ enum class CompletionState { UNKNOWN, DONE, PARTIALLY_DONE };
+
+ static Id GetNextId();
+
+ PaintImage();
+ explicit PaintImage(Id id,
+ sk_sp<SkImage> sk_image,
+ AnimationType animation_type = AnimationType::STATIC,
+ CompletionState completion_state = CompletionState::DONE);
+ PaintImage(const PaintImage& other);
+ PaintImage(PaintImage&& other);
+ ~PaintImage();
+
+ PaintImage& operator=(const PaintImage& other);
+ PaintImage& operator=(PaintImage&& other);
+
+ bool operator==(const PaintImage& other) const;
+ explicit operator bool() const { return sk_image_; }
+
+ Id stable_id() const { return id_; }
+ const sk_sp<SkImage>& sk_image() const { return sk_image_; }
+ AnimationType animation_type() const { return animation_type_; }
+ CompletionState completion_state() const { return completion_state_; }
+
+ private:
+ Id id_ = kUnknownStableId;
+ sk_sp<SkImage> sk_image_;
+ AnimationType animation_type_ = AnimationType::UNKNOWN;
+ CompletionState completion_state_ = CompletionState::UNKNOWN;
+};
+
+} // namespace cc
+
+#endif // CC_PAINT_PAINT_IMAGE_H_
diff --git a/chromium/cc/paint/paint_op_buffer.cc b/chromium/cc/paint/paint_op_buffer.cc
new file mode 100644
index 00000000000..a50c0cf38e2
--- /dev/null
+++ b/chromium/cc/paint/paint_op_buffer.cc
@@ -0,0 +1,797 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/paint/paint_op_buffer.h"
+
+#include "base/containers/stack_container.h"
+#include "cc/paint/display_item_list.h"
+#include "cc/paint/paint_record.h"
+#include "third_party/skia/include/core/SkAnnotation.h"
+
+namespace cc {
+
+#define TYPES(M) \
+ M(AnnotateOp) \
+ M(ClipPathOp) \
+ M(ClipRectOp) \
+ M(ClipRRectOp) \
+ M(ConcatOp) \
+ M(DrawArcOp) \
+ M(DrawCircleOp) \
+ M(DrawColorOp) \
+ M(DrawDisplayItemListOp) \
+ M(DrawDRRectOp) \
+ M(DrawImageOp) \
+ M(DrawImageRectOp) \
+ M(DrawIRectOp) \
+ M(DrawLineOp) \
+ M(DrawOvalOp) \
+ M(DrawPathOp) \
+ M(DrawPosTextOp) \
+ M(DrawRecordOp) \
+ M(DrawRectOp) \
+ M(DrawRRectOp) \
+ M(DrawTextOp) \
+ M(DrawTextBlobOp) \
+ M(NoopOp) \
+ M(RestoreOp) \
+ M(RotateOp) \
+ M(SaveOp) \
+ M(SaveLayerOp) \
+ M(SaveLayerAlphaOp) \
+ M(ScaleOp) \
+ M(SetMatrixOp) \
+ M(TranslateOp)
+
+using RasterFunction = void (*)(const PaintOp* op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm);
+using RasterWithFlagsFunction = void (*)(const PaintOpWithFlags* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm);
+
+NOINLINE static void RasterWithAlphaInternal(RasterFunction raster_fn,
+ const PaintOp* op,
+ SkCanvas* canvas,
+ uint8_t alpha) {
+ // TODO(enne): is it ok to just drop the bounds here?
+ canvas->saveLayerAlpha(nullptr, alpha);
+ SkMatrix unused_matrix;
+ raster_fn(op, canvas, unused_matrix);
+ canvas->restore();
+}
+
+// Helper template to share common code for RasterWithAlpha when paint ops
+// have or don't have PaintFlags.
+template <typename T, bool HasFlags>
+struct Rasterizer {
+ static void RasterWithAlpha(const T* op, SkCanvas* canvas, uint8_t alpha) {
+ static_assert(
+ !T::kHasPaintFlags,
+ "This function should not be used for a PaintOp that has PaintFlags");
+ DCHECK(T::kIsDrawOp);
+ RasterWithAlphaInternal(&T::Raster, op, canvas, alpha);
+ }
+};
+
+NOINLINE static void RasterWithAlphaInternalForFlags(
+ RasterWithFlagsFunction raster_fn,
+ const PaintOpWithFlags* op,
+ SkCanvas* canvas,
+ uint8_t alpha) {
+ SkMatrix unused_matrix;
+ if (alpha == 255) {
+ raster_fn(op, &op->flags, canvas, unused_matrix);
+ } else if (op->flags.SupportsFoldingAlpha()) {
+ PaintFlags flags = op->flags;
+ flags.setAlpha(SkMulDiv255Round(flags.getAlpha(), alpha));
+ raster_fn(op, &flags, canvas, unused_matrix);
+ } else {
+ canvas->saveLayerAlpha(nullptr, alpha);
+ raster_fn(op, &op->flags, canvas, unused_matrix);
+ canvas->restore();
+ }
+}
+
+template <typename T>
+struct Rasterizer<T, true> {
+ static void RasterWithAlpha(const T* op, SkCanvas* canvas, uint8_t alpha) {
+ static_assert(T::kHasPaintFlags,
+ "This function expects the PaintOp to have PaintFlags");
+ DCHECK(T::kIsDrawOp);
+ RasterWithAlphaInternalForFlags(&T::RasterWithFlags, op, canvas, alpha);
+ }
+};
+
+template <>
+struct Rasterizer<DrawRecordOp, false> {
+ static void RasterWithAlpha(const DrawRecordOp* op,
+ SkCanvas* canvas,
+ uint8_t alpha) {
+ // This "looking into records" optimization is done here instead of
+ // in the PaintOpBuffer::Raster function as DisplayItemList calls
+ // into RasterWithAlpha directly.
+ if (op->record->size() == 1u) {
+ PaintOp* single_op = op->record->GetFirstOp();
+ // RasterWithAlpha only supported for draw ops.
+ if (single_op->IsDrawOp()) {
+ single_op->RasterWithAlpha(canvas, alpha);
+ return;
+ }
+ }
+
+ canvas->saveLayerAlpha(nullptr, alpha);
+ SkMatrix unused_matrix;
+ DrawRecordOp::Raster(op, canvas, unused_matrix);
+ canvas->restore();
+ }
+};
+
+// TODO(enne): partially specialize RasterWithAlpha for draw color?
+
+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
+
+using RasterFunction = void (*)(const PaintOp* op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm);
+#define M(T) &T::Raster,
+static const RasterFunction g_raster_functions[kNumOpTypes] = {TYPES(M)};
+#undef M
+
+using RasterAlphaFunction = void (*)(const PaintOp* op,
+ SkCanvas* canvas,
+ uint8_t alpha);
+#define M(T) \
+ T::kIsDrawOp ? \
+ [](const PaintOp* op, SkCanvas* canvas, uint8_t alpha) { \
+ Rasterizer<T, T::kHasPaintFlags>::RasterWithAlpha( \
+ static_cast<const T*>(op), canvas, alpha); \
+ } : static_cast<RasterAlphaFunction>(nullptr),
+static const RasterAlphaFunction g_raster_alpha_functions[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) \
+ 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
+
+#undef TYPES
+
+SkRect PaintOp::kUnsetRect = {SK_ScalarInfinity, 0, 0, 0};
+
+void AnnotateOp::Raster(const PaintOp* base_op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* op = static_cast<const AnnotateOp*>(base_op);
+ 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 PaintOp* base_op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* op = static_cast<const ClipPathOp*>(base_op);
+ canvas->clipPath(op->path, op->op, op->antialias);
+}
+
+void ClipRectOp::Raster(const PaintOp* base_op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* op = static_cast<const ClipRectOp*>(base_op);
+ canvas->clipRect(op->rect, op->op, op->antialias);
+}
+
+void ClipRRectOp::Raster(const PaintOp* base_op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* op = static_cast<const ClipRRectOp*>(base_op);
+ canvas->clipRRect(op->rrect, op->op, op->antialias);
+}
+
+void ConcatOp::Raster(const PaintOp* base_op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* op = static_cast<const ConcatOp*>(base_op);
+ canvas->concat(op->matrix);
+}
+
+void DrawArcOp::RasterWithFlags(const PaintOpWithFlags* base_op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* op = static_cast<const DrawArcOp*>(base_op);
+ canvas->drawArc(op->oval, op->start_angle, op->sweep_angle, op->use_center,
+ ToSkPaint(*flags));
+}
+
+void DrawCircleOp::RasterWithFlags(const PaintOpWithFlags* base_op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* op = static_cast<const DrawCircleOp*>(base_op);
+ canvas->drawCircle(op->cx, op->cy, op->radius, ToSkPaint(*flags));
+}
+
+void DrawColorOp::Raster(const PaintOp* base_op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* op = static_cast<const DrawColorOp*>(base_op);
+ canvas->drawColor(op->color, op->mode);
+}
+
+void DrawDisplayItemListOp::Raster(const PaintOp* base_op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* op = static_cast<const DrawDisplayItemListOp*>(base_op);
+ op->list->Raster(canvas);
+}
+
+void DrawDRRectOp::RasterWithFlags(const PaintOpWithFlags* base_op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* op = static_cast<const DrawDRRectOp*>(base_op);
+ canvas->drawDRRect(op->outer, op->inner, ToSkPaint(*flags));
+}
+
+void DrawImageOp::RasterWithFlags(const PaintOpWithFlags* base_op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* op = static_cast<const DrawImageOp*>(base_op);
+ canvas->drawImage(op->image.sk_image().get(), op->left, op->top,
+ ToSkPaint(flags));
+}
+
+void DrawImageRectOp::RasterWithFlags(const PaintOpWithFlags* base_op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* op = static_cast<const DrawImageRectOp*>(base_op);
+ // TODO(enne): Probably PaintCanvas should just use the skia enum directly.
+ SkCanvas::SrcRectConstraint skconstraint =
+ static_cast<SkCanvas::SrcRectConstraint>(op->constraint);
+ canvas->drawImageRect(op->image.sk_image().get(), op->src, op->dst,
+ ToSkPaint(flags), skconstraint);
+}
+
+void DrawIRectOp::RasterWithFlags(const PaintOpWithFlags* base_op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* op = static_cast<const DrawIRectOp*>(base_op);
+ canvas->drawIRect(op->rect, ToSkPaint(*flags));
+}
+
+void DrawLineOp::RasterWithFlags(const PaintOpWithFlags* base_op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* op = static_cast<const DrawLineOp*>(base_op);
+ canvas->drawLine(op->x0, op->y0, op->x1, op->y1, ToSkPaint(*flags));
+}
+
+void DrawOvalOp::RasterWithFlags(const PaintOpWithFlags* base_op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* op = static_cast<const DrawOvalOp*>(base_op);
+ canvas->drawOval(op->oval, ToSkPaint(*flags));
+}
+
+void DrawPathOp::RasterWithFlags(const PaintOpWithFlags* base_op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* op = static_cast<const DrawPathOp*>(base_op);
+ canvas->drawPath(op->path, ToSkPaint(*flags));
+}
+
+void DrawPosTextOp::RasterWithFlags(const PaintOpWithFlags* base_op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* op = static_cast<const DrawPosTextOp*>(base_op);
+ canvas->drawPosText(op->GetData(), op->bytes, op->GetArray(),
+ ToSkPaint(*flags));
+}
+
+void DrawRecordOp::Raster(const PaintOp* base_op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ // Don't use drawPicture here, as it adds an implicit clip.
+ auto* op = static_cast<const DrawRecordOp*>(base_op);
+ op->record->playback(canvas);
+}
+
+void DrawRectOp::RasterWithFlags(const PaintOpWithFlags* base_op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* op = static_cast<const DrawRectOp*>(base_op);
+ canvas->drawRect(op->rect, ToSkPaint(*flags));
+}
+
+void DrawRRectOp::RasterWithFlags(const PaintOpWithFlags* base_op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* op = static_cast<const DrawRRectOp*>(base_op);
+ canvas->drawRRect(op->rrect, ToSkPaint(*flags));
+}
+
+void DrawTextOp::RasterWithFlags(const PaintOpWithFlags* base_op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* op = static_cast<const DrawTextOp*>(base_op);
+ canvas->drawText(op->GetData(), op->bytes, op->x, op->y, ToSkPaint(*flags));
+}
+
+void DrawTextBlobOp::RasterWithFlags(const PaintOpWithFlags* base_op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* op = static_cast<const DrawTextBlobOp*>(base_op);
+ canvas->drawTextBlob(op->blob.get(), op->x, op->y, ToSkPaint(*flags));
+}
+
+void RestoreOp::Raster(const PaintOp* base_op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ canvas->restore();
+}
+
+void RotateOp::Raster(const PaintOp* base_op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* op = static_cast<const RotateOp*>(base_op);
+ canvas->rotate(op->degrees);
+}
+
+void SaveOp::Raster(const PaintOp* base_op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ canvas->save();
+}
+
+void SaveLayerOp::RasterWithFlags(const PaintOpWithFlags* base_op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* op = static_cast<const SaveLayerOp*>(base_op);
+ // See PaintOp::kUnsetRect
+ bool unset = op->bounds.left() == SK_ScalarInfinity;
+
+ canvas->saveLayer(unset ? nullptr : &op->bounds, ToSkPaint(flags));
+}
+
+void SaveLayerAlphaOp::Raster(const PaintOp* base_op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* op = static_cast<const SaveLayerAlphaOp*>(base_op);
+ // See PaintOp::kUnsetRect
+ bool unset = op->bounds.left() == SK_ScalarInfinity;
+ canvas->saveLayerAlpha(unset ? nullptr : &op->bounds, op->alpha);
+}
+
+void ScaleOp::Raster(const PaintOp* base_op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* op = static_cast<const ScaleOp*>(base_op);
+ canvas->scale(op->sx, op->sy);
+}
+
+void SetMatrixOp::Raster(const PaintOp* base_op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* op = static_cast<const SetMatrixOp*>(base_op);
+ canvas->setMatrix(SkMatrix::Concat(original_ctm, op->matrix));
+}
+
+void TranslateOp::Raster(const PaintOp* base_op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* op = static_cast<const TranslateOp*>(base_op);
+ canvas->translate(op->dx, op->dy);
+}
+
+bool PaintOp::IsDrawOp() const {
+ return g_is_draw_op[type];
+}
+
+void PaintOp::Raster(SkCanvas* canvas, const SkMatrix& original_ctm) const {
+ g_raster_functions[type](this, canvas, original_ctm);
+}
+
+void PaintOp::RasterWithAlpha(SkCanvas* canvas, uint8_t alpha) const {
+ g_raster_alpha_functions[type](this, canvas, alpha);
+}
+
+int ClipPathOp::CountSlowPaths() const {
+ return antialias && !path.isConvex() ? 1 : 0;
+}
+
+int DrawLineOp::CountSlowPaths() const {
+ if (const SkPathEffect* effect = flags.getPathEffect()) {
+ 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->numSlowPaths();
+}
+
+AnnotateOp::AnnotateOp(PaintCanvas::AnnotationType annotation_type,
+ const SkRect& rect,
+ sk_sp<SkData> data)
+ : annotation_type(annotation_type), rect(rect), data(std::move(data)) {}
+
+AnnotateOp::~AnnotateOp() = default;
+
+DrawDisplayItemListOp::DrawDisplayItemListOp(
+ scoped_refptr<DisplayItemList> list)
+ : list(list) {}
+
+size_t DrawDisplayItemListOp::AdditionalBytesUsed() const {
+ return list->ApproximateMemoryUsage();
+}
+
+bool DrawDisplayItemListOp::HasDiscardableImages() const {
+ return list->has_discardable_images();
+}
+
+DrawDisplayItemListOp::DrawDisplayItemListOp(const DrawDisplayItemListOp& op) =
+ default;
+
+DrawDisplayItemListOp& DrawDisplayItemListOp::operator=(
+ const DrawDisplayItemListOp& op) = default;
+
+DrawDisplayItemListOp::~DrawDisplayItemListOp() = default;
+
+DrawImageOp::DrawImageOp(const PaintImage& image,
+ SkScalar left,
+ SkScalar top,
+ const PaintFlags* flags)
+ : PaintOpWithFlags(flags ? *flags : PaintFlags()),
+ image(image),
+ left(left),
+ top(top) {}
+
+bool DrawImageOp::HasDiscardableImages() const {
+ // TODO(khushalsagar): Callers should not be able to change the lazy generated
+ // state for a PaintImage.
+ return image.sk_image()->isLazyGenerated();
+}
+
+DrawImageOp::~DrawImageOp() = default;
+
+DrawImageRectOp::DrawImageRectOp(const PaintImage& image,
+ const SkRect& src,
+ const SkRect& dst,
+ const PaintFlags* flags,
+ PaintCanvas::SrcRectConstraint constraint)
+ : PaintOpWithFlags(flags ? *flags : PaintFlags()),
+ image(image),
+ src(src),
+ dst(dst),
+ constraint(constraint) {}
+
+bool DrawImageRectOp::HasDiscardableImages() const {
+ return image.sk_image()->isLazyGenerated();
+}
+
+DrawImageRectOp::~DrawImageRectOp() = default;
+
+DrawPosTextOp::DrawPosTextOp(size_t bytes,
+ size_t count,
+ const PaintFlags& flags)
+ : PaintOpWithArray(flags, bytes, count) {}
+
+DrawPosTextOp::~DrawPosTextOp() = default;
+
+DrawRecordOp::DrawRecordOp(sk_sp<const PaintRecord> record)
+ : record(std::move(record)) {}
+
+DrawRecordOp::~DrawRecordOp() = default;
+
+size_t DrawRecordOp::AdditionalBytesUsed() const {
+ return record->bytes_used();
+}
+
+bool DrawRecordOp::HasDiscardableImages() const {
+ return record->HasDiscardableImages();
+}
+
+DrawTextBlobOp::DrawTextBlobOp(sk_sp<SkTextBlob> blob,
+ SkScalar x,
+ SkScalar y,
+ const PaintFlags& flags)
+ : PaintOpWithFlags(flags), blob(std::move(blob)), x(x), y(y) {}
+
+DrawTextBlobOp::~DrawTextBlobOp() = default;
+
+PaintOpBuffer::PaintOpBuffer() = default;
+
+PaintOpBuffer::~PaintOpBuffer() {
+ Reset();
+}
+
+void PaintOpBuffer::Reset() {
+ for (auto* op : Iterator(this)) {
+ auto func = g_destructor_functions[op->type];
+ if (func)
+ func(op);
+ }
+
+ // Leave data_ allocated, reserved_ unchanged.
+ used_ = 0;
+ op_count_ = 0;
+ num_slow_paths_ = 0;
+}
+
+static const PaintOp* NextOp(const std::vector<size_t>& range_starts,
+ const std::vector<size_t>& range_indices,
+ base::StackVector<const PaintOp*, 3>* stack_ptr,
+ PaintOpBuffer::Iterator* iter,
+ size_t* range_index) {
+ auto& stack = *stack_ptr;
+ if (stack->size()) {
+ const PaintOp* op = stack->front();
+ // Shift paintops forward
+ stack->erase(stack->begin());
+ return op;
+ }
+ if (!*iter)
+ return nullptr;
+
+ const size_t active_range = range_indices[*range_index];
+ DCHECK_GE(iter->op_idx(), range_starts[active_range]);
+
+ // This grabs the PaintOp from the current iterator position, and advances it
+ // to the next position immediately. We'll see we reached the end of the
+ // buffer on the next call to this method.
+ const PaintOp* op = **iter;
+ ++*iter;
+
+ if (active_range + 1 == range_starts.size()) {
+ // In the last possible range, so let the iter go right to the end of the
+ // buffer.
+ return op;
+ }
+
+ const size_t range_end = range_starts[active_range + 1];
+ DCHECK_LE(iter->op_idx(), range_end);
+ if (iter->op_idx() < range_end) {
+ // Still inside the range, so let the iter be.
+ return op;
+ }
+
+ if (*range_index + 1 == range_indices.size()) {
+ // We're now past the last range that we want to iterate.
+ *iter = iter->end();
+ return op;
+ }
+
+ // Move to the next range.
+ ++(*range_index);
+ size_t next_range_start = range_starts[range_indices[*range_index]];
+ while (iter->op_idx() < next_range_start)
+ ++(*iter);
+ return op;
+}
+
+void PaintOpBuffer::playback(SkCanvas* canvas,
+ SkPicture::AbortCallback* callback) const {
+ static auto* zero = new std::vector<size_t>({0});
+ // Treats the entire PaintOpBuffer as a single range.
+ PlaybackRanges(*zero, *zero, canvas, callback);
+}
+
+void PaintOpBuffer::PlaybackRanges(const std::vector<size_t>& range_starts,
+ const std::vector<size_t>& range_indices,
+ SkCanvas* canvas,
+ SkPicture::AbortCallback* callback) const {
+ if (!op_count_)
+ return;
+ if (callback && callback->abort())
+ return;
+
+#if DCHECK_IS_ON()
+ DCHECK(!range_starts.empty()); // Don't call this then.
+ DCHECK(!range_indices.empty()); // Don't call this then.
+ DCHECK_EQ(0u, range_starts[0]);
+ for (size_t i = 1; i < range_starts.size(); ++i) {
+ DCHECK_GT(range_starts[i], range_starts[i - 1]);
+ DCHECK_LT(range_starts[i], op_count_);
+ }
+ DCHECK_LT(range_indices[0], range_starts.size());
+ for (size_t i = 1; i < range_indices.size(); ++i) {
+ DCHECK_GT(range_indices[i], range_indices[i - 1]);
+ DCHECK_LT(range_indices[i], range_starts.size());
+ }
+#endif
+
+ // TODO(enne): a PaintRecord that contains a SetMatrix assumes that the
+ // SetMatrix is local to that PaintRecord itself. Said differently, if you
+ // translate(x, y), then draw a paint record with a SetMatrix(identity),
+ // the translation should be preserved instead of clobbering the top level
+ // transform. This could probably be done more efficiently.
+ SkMatrix original = canvas->getTotalMatrix();
+
+ // FIFO queue of paint ops that have been peeked at.
+ base::StackVector<const PaintOp*, 3> stack;
+
+ // The current offset into range_indices. range_indices[range_index] is the
+ // current offset into range_starts.
+ size_t range_index = 0;
+
+ Iterator iter(this);
+ while (iter.op_idx() < range_starts[range_indices[range_index]])
+ ++iter;
+ while (const PaintOp* op =
+ NextOp(range_starts, range_indices, &stack, &iter, &range_index)) {
+ // Optimize out save/restores or save/draw/restore that can be a single
+ // draw. See also: similar code in SkRecordOpts and cc's DisplayItemList.
+ // TODO(enne): consider making this recursive?
+ if (op->GetType() == PaintOpType::SaveLayerAlpha) {
+ const PaintOp* second =
+ NextOp(range_starts, range_indices, &stack, &iter, &range_index);
+ const PaintOp* third = nullptr;
+ if (second) {
+ if (second->GetType() == PaintOpType::Restore) {
+ continue;
+ }
+ if (second->IsDrawOp()) {
+ third =
+ NextOp(range_starts, range_indices, &stack, &iter, &range_index);
+ if (third && third->GetType() == PaintOpType::Restore) {
+ const SaveLayerAlphaOp* save_op =
+ static_cast<const SaveLayerAlphaOp*>(op);
+ second->RasterWithAlpha(canvas, save_op->alpha);
+ continue;
+ }
+ }
+
+ // Store deferred ops for later.
+ stack->push_back(second);
+ if (third)
+ stack->push_back(third);
+ }
+ }
+ // TODO(enne): skip SaveLayer followed by restore with nothing in
+ // between, however SaveLayer with image filters on it (or maybe
+ // other PaintFlags options) are not a noop. Figure out what these
+ // are so we can skip them correctly.
+
+ op->Raster(canvas, original);
+ if (callback && callback->abort())
+ return;
+ }
+}
+
+void 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)));
+ memcpy(new_data.get(), data_.get(), used_);
+ data_ = std::move(new_data);
+ reserved_ = new_size;
+}
+
+std::pair<void*, size_t> PaintOpBuffer::AllocatePaintOp(size_t sizeof_op,
+ size_t bytes) {
+ if (!op_count_) {
+ if (bytes) {
+ // Internal first_op buffer doesn't have room for extra data.
+ // If the op wants extra bytes, then we'll just store a Noop
+ // in the first_op and proceed from there. This seems unlikely
+ // to be a common case.
+ push<NoopOp>();
+ } else {
+ op_count_++;
+ return std::make_pair(first_op_.void_data(), 0);
+ }
+ }
+
+ // We've filled |first_op_| by now so we need to allocate space in |data_|.
+ DCHECK(op_count_);
+
+ // Compute a skip such that all ops in the buffer are aligned to the
+ // maximum required alignment of all ops.
+ size_t skip = MathUtil::UncheckedRoundUp(sizeof_op + bytes, PaintOpAlign);
+ DCHECK_LT(skip, static_cast<size_t>(1) << 24);
+ if (used_ + skip > reserved_) {
+ // Start reserved_ at kInitialBufferSize and then double.
+ // ShrinkToFit can make this smaller afterwards.
+ size_t new_size = reserved_ ? reserved_ : kInitialBufferSize;
+ while (used_ + skip > new_size)
+ new_size *= 2;
+ ReallocBuffer(new_size);
+ }
+ DCHECK_LE(used_ + skip, reserved_);
+
+ void* op = data_.get() + used_;
+ used_ += skip;
+ op_count_++;
+ return std::make_pair(op, skip);
+}
+
+void PaintOpBuffer::ShrinkToFit() {
+ if (!used_ || used_ == reserved_)
+ return;
+ ReallocBuffer(used_);
+}
+
+} // namespace cc
diff --git a/chromium/cc/paint/paint_op_buffer.h b/chromium/cc/paint/paint_op_buffer.h
new file mode 100644
index 00000000000..bcc0c809964
--- /dev/null
+++ b/chromium/cc/paint/paint_op_buffer.h
@@ -0,0 +1,978 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_PAINT_PAINT_OP_BUFFER_H_
+#define CC_PAINT_PAINT_OP_BUFFER_H_
+
+#include <stdint.h>
+
+#include "base/logging.h"
+#include "base/memory/aligned_memory.h"
+#include "cc/base/math_util.h"
+#include "cc/paint/paint_canvas.h"
+#include "cc/paint/paint_export.h"
+#include "cc/paint/paint_flags.h"
+#include "third_party/skia/include/core/SkPicture.h"
+#include "third_party/skia/include/core/SkRect.h"
+#include "third_party/skia/include/core/SkTextBlob.h"
+
+// PaintOpBuffer is a reimplementation of SkLiteDL.
+// See: third_party/skia/src/core/SkLiteDL.h.
+
+namespace cc {
+class DisplayItemList;
+
+class CC_PAINT_EXPORT ThreadsafeMatrix : public SkMatrix {
+ public:
+ explicit ThreadsafeMatrix(const SkMatrix& matrix) : SkMatrix(matrix) {
+ (void)getType();
+ }
+};
+
+class CC_PAINT_EXPORT ThreadsafePath : public SkPath {
+ public:
+ explicit ThreadsafePath(const SkPath& path) : SkPath(path) {
+ updateBoundsCache();
+ }
+};
+
+enum class PaintOpType : uint8_t {
+ Annotate,
+ ClipPath,
+ ClipRect,
+ ClipRRect,
+ Concat,
+ DrawArc,
+ DrawCircle,
+ DrawColor,
+ DrawDisplayItemList,
+ DrawDRRect,
+ DrawImage,
+ DrawImageRect,
+ DrawIRect,
+ DrawLine,
+ DrawOval,
+ DrawPath,
+ DrawPosText,
+ DrawRecord,
+ DrawRect,
+ DrawRRect,
+ DrawText,
+ DrawTextBlob,
+ Noop,
+ Restore,
+ Rotate,
+ Save,
+ SaveLayer,
+ SaveLayerAlpha,
+ Scale,
+ SetMatrix,
+ Translate,
+ LastPaintOpType = Translate,
+};
+
+struct CC_PAINT_EXPORT PaintOp {
+ uint32_t type : 8;
+ uint32_t skip : 24;
+
+ 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 SkMatrix& original_ctm) const;
+ bool IsDrawOp() const;
+
+ // Only valid for draw ops.
+ void RasterWithAlpha(SkCanvas* canvas, uint8_t alpha) const;
+
+ int CountSlowPaths() const { return 0; }
+ int CountSlowPathsFromFlags() const { return 0; }
+
+ 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; }
+
+ static constexpr bool kIsDrawOp = false;
+ static constexpr bool kHasPaintFlags = false;
+ static SkRect kUnsetRect;
+};
+
+struct CC_PAINT_EXPORT PaintOpWithFlags : PaintOp {
+ static constexpr bool kHasPaintFlags = true;
+
+ explicit PaintOpWithFlags(const PaintFlags& flags) : flags(flags) {}
+
+ int CountSlowPathsFromFlags() const { return flags.getPathEffect() ? 1 : 0; }
+ bool HasDiscardableImagesFromFlags() const {
+ if (!IsDrawOp())
+ return false;
+
+ SkShader* shader = flags.getShader();
+ SkImage* image = shader ? shader->isAImage(nullptr, nullptr) : nullptr;
+ return image && image->isLazyGenerated();
+ }
+
+ // Subclasses should provide a static RasterWithFlags() method which is called
+ // from the Raster() method. The RasterWithFlags() should use the PaintFlags
+ // 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;
+};
+
+struct CC_PAINT_EXPORT PaintOpWithData : PaintOpWithFlags {
+ // Having data is just a helper for ops that have a varying amount of data and
+ // want a way to store that inline. This is for ops that pass in a
+ // void* and a length. The void* data is assumed to not have any alignment
+ // requirements.
+ PaintOpWithData(const PaintFlags& flags, size_t bytes)
+ : PaintOpWithFlags(flags), bytes(bytes) {}
+
+ // Get data out by calling paint_op_data. This can't be part of the class
+ // because it needs to know the size of the derived type.
+ size_t bytes;
+
+ protected:
+ // For some derived object T, return the internally stored data.
+ // This needs the fully derived type to know how much to offset
+ // from the start of the top to the data.
+ template <typename T>
+ const void* GetDataForThis(const T* op) const {
+ static_assert(std::is_convertible<T, PaintOpWithData>::value,
+ "T is not a PaintOpWithData");
+ // Arbitrary data for a PaintOp is stored after the PaintOp itself
+ // in the PaintOpBuffer. Therefore, to access this data, it's
+ // pointer math to increment past the size of T. Accessing the
+ // next op in the buffer is ((char*)op) + op->skip, with the data
+ // fitting between.
+ return op + 1;
+ }
+
+ template <typename T>
+ void* GetDataForThis(T* op) {
+ return const_cast<void*>(
+ const_cast<const PaintOpWithData*>(this)->GetDataForThis(
+ const_cast<const T*>(op)));
+ }
+};
+
+struct CC_PAINT_EXPORT PaintOpWithArrayBase : PaintOpWithFlags {
+ explicit PaintOpWithArrayBase(const PaintFlags& flags)
+ : PaintOpWithFlags(flags) {}
+};
+
+template <typename M>
+struct CC_PAINT_EXPORT PaintOpWithArray : PaintOpWithArrayBase {
+ // Paint op that has a M[count] and a char[bytes].
+ // Array data is stored first so that it can be aligned with T's alignment
+ // with the arbitrary unaligned char data after it.
+ // Memory layout here is: | op | M[count] | char[bytes] | padding | next op |
+ // Next op is located at (char*)(op) + op->skip.
+ PaintOpWithArray(const PaintFlags& flags, size_t bytes, size_t count)
+ : PaintOpWithArrayBase(flags), bytes(bytes), count(count) {}
+
+ size_t bytes;
+ size_t count;
+
+ protected:
+ template <typename T>
+ const void* GetDataForThis(const T* op) const {
+ static_assert(std::is_convertible<T, PaintOpWithArrayBase>::value,
+ "T is not a PaintOpWithData");
+ const char* start_array =
+ reinterpret_cast<const char*>(GetArrayForThis(op));
+ return start_array + sizeof(M) * count;
+ }
+
+ template <typename T>
+ void* GetDataForThis(T* op) {
+ return const_cast<void*>(
+ const_cast<const PaintOpWithArray*>(this)->GetDataForThis(
+ const_cast<T*>(op)));
+ }
+
+ template <typename T>
+ const M* GetArrayForThis(const T* op) const {
+ static_assert(std::is_convertible<T, PaintOpWithArrayBase>::value,
+ "T is not a PaintOpWithData");
+ // As an optimization to not have to store an additional offset,
+ // assert that T has the same or more alignment requirements than M. Thus,
+ // if T is aligned, and M's alignment needs are a multiple of T's size, then
+ // M will also be aligned when placed immediately after T.
+ static_assert(
+ sizeof(T) % ALIGNOF(M) == 0,
+ "T must be padded such that an array of M is aligned after it");
+ static_assert(
+ ALIGNOF(T) >= ALIGNOF(M),
+ "T must have not have less alignment requirements than the array data");
+ return reinterpret_cast<const M*>(op + 1);
+ }
+
+ template <typename T>
+ M* GetArrayForThis(T* op) {
+ return const_cast<M*>(
+ const_cast<const PaintOpWithArray*>(this)->GetArrayForThis(
+ const_cast<T*>(op)));
+ }
+};
+
+struct CC_PAINT_EXPORT AnnotateOp final : PaintOp {
+ enum class AnnotationType {
+ URL,
+ LinkToDestination,
+ NamedDestination,
+ };
+
+ static constexpr PaintOpType kType = PaintOpType::Annotate;
+ AnnotateOp(PaintCanvas::AnnotationType annotation_type,
+ const SkRect& rect,
+ sk_sp<SkData> data);
+ ~AnnotateOp();
+ static void Raster(const PaintOp* op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm);
+
+ PaintCanvas::AnnotationType annotation_type;
+ SkRect rect;
+ sk_sp<SkData> data;
+};
+
+struct CC_PAINT_EXPORT ClipPathOp final : PaintOp {
+ static constexpr PaintOpType kType = PaintOpType::ClipPath;
+ ClipPathOp(SkPath path, SkClipOp op, bool antialias)
+ : path(path), op(op), antialias(antialias) {}
+ static void Raster(const PaintOp* op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm);
+ int CountSlowPaths() const;
+
+ ThreadsafePath path;
+ SkClipOp op;
+ bool antialias;
+};
+
+struct CC_PAINT_EXPORT ClipRectOp final : PaintOp {
+ static constexpr PaintOpType kType = PaintOpType::ClipRect;
+ ClipRectOp(const SkRect& rect, SkClipOp op, bool antialias)
+ : rect(rect), op(op), antialias(antialias) {}
+ static void Raster(const PaintOp* op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm);
+
+ SkRect rect;
+ SkClipOp op;
+ bool antialias;
+};
+
+struct CC_PAINT_EXPORT ClipRRectOp final : PaintOp {
+ static constexpr PaintOpType kType = PaintOpType::ClipRRect;
+ ClipRRectOp(const SkRRect& rrect, SkClipOp op, bool antialias)
+ : rrect(rrect), op(op), antialias(antialias) {}
+ static void Raster(const PaintOp* op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm);
+
+ SkRRect rrect;
+ SkClipOp op;
+ bool antialias;
+};
+
+struct CC_PAINT_EXPORT ConcatOp final : PaintOp {
+ static constexpr PaintOpType kType = PaintOpType::Concat;
+ explicit ConcatOp(const SkMatrix& matrix) : matrix(matrix) {}
+ static void Raster(const PaintOp* op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm);
+
+ ThreadsafeMatrix matrix;
+};
+
+struct CC_PAINT_EXPORT DrawArcOp final : PaintOpWithFlags {
+ static constexpr PaintOpType kType = PaintOpType::DrawArc;
+ static constexpr bool kIsDrawOp = true;
+ DrawArcOp(const SkRect& oval,
+ SkScalar start_angle,
+ SkScalar sweep_angle,
+ bool use_center,
+ const PaintFlags& flags)
+ : PaintOpWithFlags(flags),
+ oval(oval),
+ start_angle(start_angle),
+ sweep_angle(sweep_angle),
+ use_center(use_center) {}
+ static void Raster(const PaintOp* op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* flags_op = static_cast<const PaintOpWithFlags*>(op);
+ RasterWithFlags(flags_op, &flags_op->flags, canvas, original_ctm);
+ }
+ static void RasterWithFlags(const PaintOpWithFlags* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm);
+
+ SkRect oval;
+ SkScalar start_angle;
+ SkScalar sweep_angle;
+ bool use_center;
+};
+
+struct CC_PAINT_EXPORT DrawCircleOp final : PaintOpWithFlags {
+ static constexpr PaintOpType kType = PaintOpType::DrawCircle;
+ static constexpr bool kIsDrawOp = true;
+ DrawCircleOp(SkScalar cx,
+ SkScalar cy,
+ SkScalar radius,
+ const PaintFlags& flags)
+ : PaintOpWithFlags(flags), cx(cx), cy(cy), radius(radius) {}
+ static void Raster(const PaintOp* op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* flags_op = static_cast<const PaintOpWithFlags*>(op);
+ RasterWithFlags(flags_op, &flags_op->flags, canvas, original_ctm);
+ }
+ static void RasterWithFlags(const PaintOpWithFlags* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm);
+
+ SkScalar cx;
+ SkScalar cy;
+ SkScalar radius;
+};
+
+struct CC_PAINT_EXPORT DrawColorOp final : PaintOp {
+ static constexpr PaintOpType kType = PaintOpType::DrawColor;
+ static constexpr bool kIsDrawOp = true;
+ DrawColorOp(SkColor color, SkBlendMode mode) : color(color), mode(mode) {}
+ static void Raster(const PaintOp* op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm);
+
+ SkColor color;
+ SkBlendMode mode;
+};
+
+struct CC_PAINT_EXPORT DrawDisplayItemListOp final : PaintOp {
+ static constexpr PaintOpType kType = PaintOpType::DrawDisplayItemList;
+ static constexpr bool kIsDrawOp = true;
+ explicit DrawDisplayItemListOp(scoped_refptr<DisplayItemList> list);
+ // Windows wants to generate these when types are exported, so
+ // provide them here explicitly so that DisplayItemList doesn't have
+ // to be defined in this header.
+ DrawDisplayItemListOp(const DrawDisplayItemListOp& op);
+ DrawDisplayItemListOp& operator=(const DrawDisplayItemListOp& op);
+ ~DrawDisplayItemListOp();
+ static void Raster(const PaintOp* op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm);
+ size_t AdditionalBytesUsed() const;
+ bool HasDiscardableImages() const;
+ // TODO(enne): DisplayItemList should know number of slow paths.
+
+ scoped_refptr<DisplayItemList> list;
+};
+
+struct CC_PAINT_EXPORT DrawDRRectOp final : PaintOpWithFlags {
+ static constexpr PaintOpType kType = PaintOpType::DrawDRRect;
+ static constexpr bool kIsDrawOp = true;
+ DrawDRRectOp(const SkRRect& outer,
+ const SkRRect& inner,
+ const PaintFlags& flags)
+ : PaintOpWithFlags(flags), outer(outer), inner(inner) {}
+ static void Raster(const PaintOp* op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* flags_op = static_cast<const PaintOpWithFlags*>(op);
+ RasterWithFlags(flags_op, &flags_op->flags, canvas, original_ctm);
+ }
+ static void RasterWithFlags(const PaintOpWithFlags* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm);
+
+ SkRRect outer;
+ SkRRect inner;
+};
+
+struct CC_PAINT_EXPORT DrawImageOp final : PaintOpWithFlags {
+ static constexpr PaintOpType kType = PaintOpType::DrawImage;
+ static constexpr bool kIsDrawOp = true;
+ DrawImageOp(const PaintImage& image,
+ SkScalar left,
+ SkScalar top,
+ const PaintFlags* flags);
+ ~DrawImageOp();
+ static void Raster(const PaintOp* op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* flags_op = static_cast<const PaintOpWithFlags*>(op);
+ RasterWithFlags(flags_op, &flags_op->flags, canvas, original_ctm);
+ }
+ static void RasterWithFlags(const PaintOpWithFlags* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm);
+ bool HasDiscardableImages() const;
+
+ PaintImage image;
+ SkScalar left;
+ SkScalar top;
+};
+
+struct CC_PAINT_EXPORT DrawImageRectOp final : PaintOpWithFlags {
+ static constexpr PaintOpType kType = PaintOpType::DrawImageRect;
+ static constexpr bool kIsDrawOp = true;
+ DrawImageRectOp(const PaintImage& image,
+ const SkRect& src,
+ const SkRect& dst,
+ const PaintFlags* flags,
+ PaintCanvas::SrcRectConstraint constraint);
+ ~DrawImageRectOp();
+ static void Raster(const PaintOp* op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* flags_op = static_cast<const PaintOpWithFlags*>(op);
+ RasterWithFlags(flags_op, &flags_op->flags, canvas, original_ctm);
+ }
+ static void RasterWithFlags(const PaintOpWithFlags* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm);
+ bool HasDiscardableImages() const;
+
+ PaintImage image;
+ SkRect src;
+ SkRect dst;
+ PaintCanvas::SrcRectConstraint constraint;
+};
+
+struct CC_PAINT_EXPORT DrawIRectOp final : PaintOpWithFlags {
+ static constexpr PaintOpType kType = PaintOpType::DrawIRect;
+ static constexpr bool kIsDrawOp = true;
+ DrawIRectOp(const SkIRect& rect, const PaintFlags& flags)
+ : PaintOpWithFlags(flags), rect(rect) {}
+ static void Raster(const PaintOp* op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* flags_op = static_cast<const PaintOpWithFlags*>(op);
+ RasterWithFlags(flags_op, &flags_op->flags, canvas, original_ctm);
+ }
+ static void RasterWithFlags(const PaintOpWithFlags* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm);
+
+ SkIRect rect;
+};
+
+struct CC_PAINT_EXPORT DrawLineOp final : PaintOpWithFlags {
+ static constexpr PaintOpType kType = PaintOpType::DrawLine;
+ static constexpr bool kIsDrawOp = true;
+ DrawLineOp(SkScalar x0,
+ SkScalar y0,
+ SkScalar x1,
+ SkScalar y1,
+ const PaintFlags& flags)
+ : PaintOpWithFlags(flags), x0(x0), y0(y0), x1(x1), y1(y1) {}
+ static void Raster(const PaintOp* op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* flags_op = static_cast<const PaintOpWithFlags*>(op);
+ RasterWithFlags(flags_op, &flags_op->flags, canvas, original_ctm);
+ }
+ static void RasterWithFlags(const PaintOpWithFlags* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm);
+
+ int CountSlowPaths() const;
+
+ SkScalar x0;
+ SkScalar y0;
+ SkScalar x1;
+ SkScalar y1;
+};
+
+struct CC_PAINT_EXPORT DrawOvalOp final : PaintOpWithFlags {
+ static constexpr PaintOpType kType = PaintOpType::DrawOval;
+ static constexpr bool kIsDrawOp = true;
+ DrawOvalOp(const SkRect& oval, const PaintFlags& flags)
+ : PaintOpWithFlags(flags), oval(oval) {}
+ static void Raster(const PaintOp* op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* flags_op = static_cast<const PaintOpWithFlags*>(op);
+ RasterWithFlags(flags_op, &flags_op->flags, canvas, original_ctm);
+ }
+ static void RasterWithFlags(const PaintOpWithFlags* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm);
+
+ SkRect oval;
+};
+
+struct CC_PAINT_EXPORT DrawPathOp final : PaintOpWithFlags {
+ static constexpr PaintOpType kType = PaintOpType::DrawPath;
+ static constexpr bool kIsDrawOp = true;
+ DrawPathOp(const SkPath& path, const PaintFlags& flags)
+ : PaintOpWithFlags(flags), path(path) {}
+ static void Raster(const PaintOp* op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* flags_op = static_cast<const PaintOpWithFlags*>(op);
+ RasterWithFlags(flags_op, &flags_op->flags, canvas, original_ctm);
+ }
+ static void RasterWithFlags(const PaintOpWithFlags* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm);
+ int CountSlowPaths() const;
+
+ ThreadsafePath path;
+};
+
+struct CC_PAINT_EXPORT DrawPosTextOp final : PaintOpWithArray<SkPoint> {
+ static constexpr PaintOpType kType = PaintOpType::DrawPosText;
+ static constexpr bool kIsDrawOp = true;
+ DrawPosTextOp(size_t bytes, size_t count, const PaintFlags& flags);
+ ~DrawPosTextOp();
+ static void Raster(const PaintOp* op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* flags_op = static_cast<const PaintOpWithFlags*>(op);
+ RasterWithFlags(flags_op, &flags_op->flags, canvas, original_ctm);
+ }
+ static void RasterWithFlags(const PaintOpWithFlags* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm);
+
+ const void* GetData() const { return GetDataForThis(this); }
+ void* GetData() { return GetDataForThis(this); }
+ const SkPoint* GetArray() const { return GetArrayForThis(this); }
+ SkPoint* GetArray() { return GetArrayForThis(this); }
+};
+
+struct CC_PAINT_EXPORT DrawRecordOp final : PaintOp {
+ static constexpr PaintOpType kType = PaintOpType::DrawRecord;
+ static constexpr bool kIsDrawOp = true;
+ explicit DrawRecordOp(sk_sp<const PaintRecord> record);
+ ~DrawRecordOp();
+ static void Raster(const PaintOp* op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm);
+ size_t AdditionalBytesUsed() const;
+ bool HasDiscardableImages() const;
+ int CountSlowPaths() const;
+
+ sk_sp<const PaintRecord> record;
+};
+
+struct CC_PAINT_EXPORT DrawRectOp final : PaintOpWithFlags {
+ static constexpr PaintOpType kType = PaintOpType::DrawRect;
+ static constexpr bool kIsDrawOp = true;
+ DrawRectOp(const SkRect& rect, const PaintFlags& flags)
+ : PaintOpWithFlags(flags), rect(rect) {}
+ static void Raster(const PaintOp* op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* flags_op = static_cast<const PaintOpWithFlags*>(op);
+ RasterWithFlags(flags_op, &flags_op->flags, canvas, original_ctm);
+ }
+ static void RasterWithFlags(const PaintOpWithFlags* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm);
+
+ SkRect rect;
+};
+
+struct CC_PAINT_EXPORT DrawRRectOp final : PaintOpWithFlags {
+ static constexpr PaintOpType kType = PaintOpType::DrawRRect;
+ static constexpr bool kIsDrawOp = true;
+ DrawRRectOp(const SkRRect& rrect, const PaintFlags& flags)
+ : PaintOpWithFlags(flags), rrect(rrect) {}
+ static void Raster(const PaintOp* op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* flags_op = static_cast<const PaintOpWithFlags*>(op);
+ RasterWithFlags(flags_op, &flags_op->flags, canvas, original_ctm);
+ }
+ static void RasterWithFlags(const PaintOpWithFlags* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm);
+
+ SkRRect rrect;
+};
+
+struct CC_PAINT_EXPORT DrawTextOp final : PaintOpWithData {
+ static constexpr PaintOpType kType = PaintOpType::DrawText;
+ static constexpr bool kIsDrawOp = true;
+ DrawTextOp(size_t bytes, SkScalar x, SkScalar y, const PaintFlags& flags)
+ : PaintOpWithData(flags, bytes), x(x), y(y) {}
+ static void Raster(const PaintOp* op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* flags_op = static_cast<const PaintOpWithFlags*>(op);
+ RasterWithFlags(flags_op, &flags_op->flags, canvas, original_ctm);
+ }
+ static void RasterWithFlags(const PaintOpWithFlags* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm);
+
+ void* GetData() { return GetDataForThis(this); }
+ const void* GetData() const { return GetDataForThis(this); }
+
+ SkScalar x;
+ SkScalar y;
+};
+
+struct CC_PAINT_EXPORT DrawTextBlobOp final : PaintOpWithFlags {
+ static constexpr PaintOpType kType = PaintOpType::DrawTextBlob;
+ static constexpr bool kIsDrawOp = true;
+ DrawTextBlobOp(sk_sp<SkTextBlob> blob,
+ SkScalar x,
+ SkScalar y,
+ const PaintFlags& flags);
+ ~DrawTextBlobOp();
+ static void Raster(const PaintOp* op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* flags_op = static_cast<const PaintOpWithFlags*>(op);
+ RasterWithFlags(flags_op, &flags_op->flags, canvas, original_ctm);
+ }
+ static void RasterWithFlags(const PaintOpWithFlags* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm);
+
+ sk_sp<SkTextBlob> blob;
+ SkScalar x;
+ SkScalar y;
+};
+
+struct CC_PAINT_EXPORT NoopOp final : PaintOp {
+ static constexpr PaintOpType kType = PaintOpType::Noop;
+ static void Raster(const PaintOp* op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {}
+};
+
+struct CC_PAINT_EXPORT RestoreOp final : PaintOp {
+ static constexpr PaintOpType kType = PaintOpType::Restore;
+ static void Raster(const PaintOp* op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm);
+};
+
+struct CC_PAINT_EXPORT RotateOp final : PaintOp {
+ static constexpr PaintOpType kType = PaintOpType::Rotate;
+ explicit RotateOp(SkScalar degrees) : degrees(degrees) {}
+ static void Raster(const PaintOp* op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm);
+
+ SkScalar degrees;
+};
+
+struct CC_PAINT_EXPORT SaveOp final : PaintOp {
+ static constexpr PaintOpType kType = PaintOpType::Save;
+ static void Raster(const PaintOp* op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm);
+};
+
+struct CC_PAINT_EXPORT SaveLayerOp final : PaintOpWithFlags {
+ static constexpr PaintOpType kType = PaintOpType::SaveLayer;
+ SaveLayerOp(const SkRect* bounds, const PaintFlags* flags)
+ : PaintOpWithFlags(flags ? *flags : PaintFlags()),
+ bounds(bounds ? *bounds : kUnsetRect) {}
+ static void Raster(const PaintOp* op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm) {
+ auto* flags_op = static_cast<const PaintOpWithFlags*>(op);
+ RasterWithFlags(flags_op, &flags_op->flags, canvas, original_ctm);
+ }
+ static void RasterWithFlags(const PaintOpWithFlags* op,
+ const PaintFlags* flags,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm);
+
+ SkRect bounds;
+};
+
+struct CC_PAINT_EXPORT SaveLayerAlphaOp final : PaintOp {
+ static constexpr PaintOpType kType = PaintOpType::SaveLayerAlpha;
+ SaveLayerAlphaOp(const SkRect* bounds, uint8_t alpha)
+ : bounds(bounds ? *bounds : kUnsetRect), alpha(alpha) {}
+ static void Raster(const PaintOp* op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm);
+
+ SkRect bounds;
+ uint8_t alpha;
+};
+
+struct CC_PAINT_EXPORT ScaleOp final : PaintOp {
+ static constexpr PaintOpType kType = PaintOpType::Scale;
+ ScaleOp(SkScalar sx, SkScalar sy) : sx(sx), sy(sy) {}
+ static void Raster(const PaintOp* op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm);
+
+ SkScalar sx;
+ SkScalar sy;
+};
+
+struct CC_PAINT_EXPORT SetMatrixOp final : PaintOp {
+ static constexpr PaintOpType kType = PaintOpType::SetMatrix;
+ explicit SetMatrixOp(const SkMatrix& matrix) : 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 PaintOp* op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm);
+
+ ThreadsafeMatrix matrix;
+};
+
+struct CC_PAINT_EXPORT TranslateOp final : PaintOp {
+ static constexpr PaintOpType kType = PaintOpType::Translate;
+ TranslateOp(SkScalar dx, SkScalar dy) : dx(dx), dy(dy) {}
+ static void Raster(const PaintOp* op,
+ SkCanvas* canvas,
+ const SkMatrix& original_ctm);
+
+ SkScalar dx;
+ SkScalar dy;
+};
+
+using LargestPaintOp = DrawDRRectOp;
+
+class CC_PAINT_EXPORT PaintOpBuffer : public SkRefCnt {
+ public:
+ enum { kInitialBufferSize = 4096 };
+ // It's not necessarily the case that the op with the maximum alignment
+ // requirements is also the biggest op, but for now that's true.
+ static constexpr size_t PaintOpAlign = ALIGNOF(DrawDRRectOp);
+
+ PaintOpBuffer();
+ ~PaintOpBuffer() override;
+
+ void Reset();
+
+ void playback(SkCanvas* canvas,
+ SkPicture::AbortCallback* callback = nullptr) const;
+ // This can be used to play back a subset of the PaintOpBuffer.
+ // The |range_starts| array is an increasing set of positions in the
+ // PaintOpBuffer that break the buffer up into arbitrary consecutive chunks
+ // that together cover the entire buffer. The first value in |range_starts|
+ // must be 0. Each value after defines the end of the previous range
+ // (exclusive) and the beginning of the next range (inclusive). The last value
+ // in the array defines the last range which includes all ops to the end of
+ // the buffer. For example, given a PaintOpBuffer with the following ops:
+ // { A, B, C, D, E, F, G, H, I }
+ // And a |range_starts| with the following values:
+ // { 0, 4, 5 }
+ // This defines the following ranges in PaintOpBuffer:
+ // { A, B, C, D }, { E }, { F, G, H, I }.
+ // The |range_indices| is an increasing set of indices into the |range_starts|
+ // array. This defines the set of ranges that will be played back.
+ // Given the above example, if range_indices contains:
+ // { 1, 2 }
+ // Then the 1th and 2th (starting from base 0) ranges as defined in
+ // |range_starts| would be played back, which would be:
+ // { E, F, G, H, I }.
+ void PlaybackRanges(const std::vector<size_t>& range_starts,
+ const std::vector<size_t>& range_indices,
+ SkCanvas* canvas,
+ SkPicture::AbortCallback* callback = nullptr) const;
+
+ // Returns the size of the paint op buffer. That is, the number of ops
+ // contained in it.
+ size_t size() const { return op_count_; }
+ // Returns the number of bytes used by the paint op buffer.
+ size_t bytes_used() const {
+ return sizeof(*this) + reserved_ + subrecord_bytes_used_;
+ }
+ int numSlowPaths() const { return num_slow_paths_; }
+ bool HasDiscardableImages() const { return has_discardable_images_; }
+
+ // Resize the PaintOpBuffer to exactly fit the current amount of used space.
+ void ShrinkToFit();
+
+ PaintOp* GetFirstOp() const {
+ return const_cast<PaintOp*>(first_op_.data_as<PaintOp>());
+ }
+
+ template <typename T, typename... Args>
+ void push(Args&&... args) {
+ static_assert(std::is_convertible<T, PaintOp>::value, "T not a PaintOp.");
+ static_assert(!std::is_convertible<T, PaintOpWithData>::value,
+ "Type needs to use push_with_data");
+ push_internal<T>(0, std::forward<Args>(args)...);
+ }
+
+ template <typename T, typename... Args>
+ void push_with_data(const void* data, size_t bytes, Args&&... args) {
+ static_assert(std::is_convertible<T, PaintOpWithData>::value,
+ "T is not a PaintOpWithData");
+ static_assert(!std::is_convertible<T, PaintOpWithArrayBase>::value,
+ "Type needs to use push_with_array");
+ DCHECK_GE(bytes, 0u);
+ T* op = push_internal<T>(bytes, bytes, std::forward<Args>(args)...);
+ memcpy(op->GetData(), data, bytes);
+
+#if DCHECK_IS_ON()
+ // Double check the data fits between op and next op and doesn't clobber.
+ char* op_start = reinterpret_cast<char*>(op);
+ char* op_end = op_start + sizeof(T);
+ char* next_op = op_start + op->skip;
+ char* data_start = reinterpret_cast<char*>(op->GetData());
+ char* data_end = data_start + bytes;
+ DCHECK_GE(data_start, op_end);
+ DCHECK_LT(data_start, next_op);
+ DCHECK_LE(data_end, next_op);
+#endif
+ }
+
+ template <typename T, typename M, typename... Args>
+ void push_with_array(const void* data,
+ size_t bytes,
+ const M* array,
+ size_t count,
+ Args&&... args) {
+ static_assert(std::is_convertible<T, PaintOpWithArray<M>>::value,
+ "T is not a PaintOpWithArray");
+ DCHECK_GE(bytes, 0u);
+ DCHECK_GE(count, 0u);
+ size_t array_size = sizeof(M) * count;
+ size_t total_size = bytes + array_size;
+ T* op =
+ push_internal<T>(total_size, bytes, count, std::forward<Args>(args)...);
+ memcpy(op->GetData(), data, bytes);
+ memcpy(op->GetArray(), array, array_size);
+
+#if DCHECK_IS_ON()
+ // Double check data and array don't clobber op, next op, or each other
+ char* op_start = reinterpret_cast<char*>(op);
+ char* op_end = op_start + sizeof(T);
+ char* array_start = reinterpret_cast<char*>(op->GetArray());
+ char* array_end = array_start + array_size;
+ char* data_start = reinterpret_cast<char*>(op->GetData());
+ char* data_end = data_start + bytes;
+ char* next_op = op_start + op->skip;
+ DCHECK_GE(array_start, op_end);
+ DCHECK_LE(array_start, data_start);
+ DCHECK_GE(data_start, array_end);
+ DCHECK_LE(data_end, next_op);
+#endif
+ }
+
+ class Iterator {
+ public:
+ explicit Iterator(const PaintOpBuffer* buffer)
+ : buffer_(buffer), ptr_(buffer_->data_.get()) {}
+
+ PaintOp* operator->() const {
+ return op_idx_ ? reinterpret_cast<PaintOp*>(ptr_) : buffer_->GetFirstOp();
+ }
+ PaintOp* operator*() const { return operator->(); }
+ Iterator begin() { return Iterator(buffer_, buffer_->data_.get(), 0); }
+ Iterator end() {
+ return Iterator(buffer_, buffer_->data_.get() + buffer_->used_,
+ buffer_->size());
+ }
+ bool operator!=(const Iterator& other) {
+ // Not valid to compare iterators on different buffers.
+ DCHECK_EQ(other.buffer_, buffer_);
+ return other.op_idx_ != op_idx_;
+ }
+ Iterator& operator++() {
+ if (!op_idx_++)
+ return *this;
+ PaintOp* op = **this;
+ uint32_t type = op->type;
+ CHECK_LE(type, static_cast<uint32_t>(PaintOpType::LastPaintOpType));
+ ptr_ += op->skip;
+ return *this;
+ }
+ operator bool() const { return op_idx_ < buffer_->size(); }
+ size_t op_idx() const { return op_idx_; }
+
+ private:
+ Iterator(const PaintOpBuffer* buffer, char* ptr, size_t op_idx)
+ : buffer_(buffer), ptr_(ptr), op_idx_(op_idx) {}
+
+ const PaintOpBuffer* buffer_ = nullptr;
+ char* ptr_ = nullptr;
+ size_t op_idx_ = 0;
+ };
+
+ private:
+ void ReallocBuffer(size_t new_size);
+ // Returns the allocated op and the number of bytes to skip in |data_| to get
+ // to the next op.
+ std::pair<void*, size_t> AllocatePaintOp(size_t sizeof_op, size_t bytes);
+
+ template <typename T, typename... Args>
+ T* push_internal(size_t bytes, Args&&... args) {
+ static_assert(ALIGNOF(T) <= PaintOpAlign, "");
+
+ auto pair = AllocatePaintOp(sizeof(T), bytes);
+ T* op = reinterpret_cast<T*>(pair.first);
+ size_t skip = pair.second;
+
+ new (op) T{std::forward<Args>(args)...};
+ op->type = static_cast<uint32_t>(T::kType);
+ op->skip = skip;
+ AnalyzeAddedOp(op);
+ return op;
+ }
+
+ template <typename T>
+ void AnalyzeAddedOp(const T* op) {
+ num_slow_paths_ += op->CountSlowPathsFromFlags();
+ num_slow_paths_ += op->CountSlowPaths();
+
+ has_discardable_images_ |= op->HasDiscardableImages();
+ has_discardable_images_ |= op->HasDiscardableImagesFromFlags();
+
+ subrecord_bytes_used_ += op->AdditionalBytesUsed();
+ }
+
+ // As a performance optimization because n=1 is an extremely common case just
+ // store the first op in the PaintOpBuffer itself to avoid an extra alloc.
+ base::AlignedMemory<sizeof(LargestPaintOp), PaintOpAlign> first_op_;
+ std::unique_ptr<char, base::AlignedFreeDeleter> data_;
+ size_t used_ = 0;
+ size_t reserved_ = 0;
+ size_t op_count_ = 0;
+
+ // Record paths for veto-to-msaa for gpu raster.
+ int num_slow_paths_ = 0;
+ // Record additional bytes used by referenced sub-records and display lists.
+ size_t subrecord_bytes_used_ = 0;
+ bool has_discardable_images_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(PaintOpBuffer);
+};
+
+} // namespace cc
+
+#endif // CC_PAINT_PAINT_OP_BUFFER_H_
diff --git a/chromium/cc/paint/paint_op_buffer_unittest.cc b/chromium/cc/paint/paint_op_buffer_unittest.cc
new file mode 100644
index 00000000000..5751c2fa1e0
--- /dev/null
+++ b/chromium/cc/paint/paint_op_buffer_unittest.cc
@@ -0,0 +1,901 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/paint/paint_op_buffer.h"
+#include "cc/paint/display_item_list.h"
+#include "cc/test/skia_common.h"
+#include "cc/test/test_skcanvas.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/effects/SkDashPathEffect.h"
+
+using testing::_;
+using testing::Property;
+using testing::Mock;
+
+namespace {
+
+template <typename T>
+void CheckRefCnt(const T& obj, int32_t count) {
+// Skia doesn't define getRefCnt in all builds.
+#ifdef SK_DEBUG
+ EXPECT_EQ(obj->getRefCnt(), count);
+#endif
+}
+
+} // namespace
+
+namespace cc {
+
+TEST(PaintOpBufferTest, Empty) {
+ PaintOpBuffer buffer;
+ EXPECT_EQ(buffer.size(), 0u);
+ EXPECT_EQ(buffer.bytes_used(), sizeof(PaintOpBuffer));
+ EXPECT_EQ(PaintOpBuffer::Iterator(&buffer), false);
+
+ buffer.Reset();
+ EXPECT_EQ(buffer.size(), 0u);
+ EXPECT_EQ(buffer.bytes_used(), sizeof(PaintOpBuffer));
+ EXPECT_EQ(PaintOpBuffer::Iterator(&buffer), false);
+}
+
+TEST(PaintOpBufferTest, SimpleAppend) {
+ SkRect rect = SkRect::MakeXYWH(2, 3, 4, 5);
+ PaintFlags flags;
+ flags.setColor(SK_ColorMAGENTA);
+ flags.setAlpha(100);
+ SkColor draw_color = SK_ColorRED;
+ SkBlendMode blend = SkBlendMode::kSrc;
+
+ PaintOpBuffer buffer;
+ buffer.push<SaveLayerOp>(&rect, &flags);
+ buffer.push<SaveOp>();
+ buffer.push<DrawColorOp>(draw_color, blend);
+ buffer.push<RestoreOp>();
+
+ EXPECT_EQ(buffer.size(), 4u);
+
+ PaintOpBuffer::Iterator iter(&buffer);
+ ASSERT_EQ(iter->GetType(), PaintOpType::SaveLayer);
+ SaveLayerOp* save_op = static_cast<SaveLayerOp*>(*iter);
+ EXPECT_EQ(save_op->bounds, rect);
+ EXPECT_TRUE(save_op->flags == flags);
+ ++iter;
+
+ ASSERT_EQ(iter->GetType(), PaintOpType::Save);
+ ++iter;
+
+ ASSERT_EQ(iter->GetType(), PaintOpType::DrawColor);
+ DrawColorOp* op = static_cast<DrawColorOp*>(*iter);
+ EXPECT_EQ(op->color, draw_color);
+ EXPECT_EQ(op->mode, blend);
+ ++iter;
+
+ ASSERT_EQ(iter->GetType(), PaintOpType::Restore);
+ ++iter;
+
+ EXPECT_FALSE(iter);
+}
+
+// PaintOpBuffer has a special case for first ops stored locally, so
+// make sure that appending different kind of ops as a first op works
+// properly, as well as resetting and reusing the first local op.
+TEST(PaintOpBufferTest, FirstOpWithAndWithoutData) {
+ PaintOpBuffer buffer;
+ char text[] = "asdf";
+
+ // Use a color filter and its ref count to verify that the destructor
+ // is called on ops after reset.
+ PaintFlags flags;
+ sk_sp<SkColorFilter> filter =
+ SkColorFilter::MakeModeFilter(SK_ColorMAGENTA, SkBlendMode::kSrcOver);
+ flags.setColorFilter(filter);
+ CheckRefCnt(filter, 2);
+
+ buffer.push_with_data<DrawTextOp>(text, arraysize(text), 0.f, 0.f, flags);
+ CheckRefCnt(filter, 3);
+
+ // Verify that when the first op has data, which may not fit in the
+ // PaintRecord internal buffer, that it adds a noop as the first op
+ // and then appends the "op with data" into the heap buffer.
+ ASSERT_EQ(buffer.size(), 2u);
+ EXPECT_EQ(buffer.GetFirstOp()->GetType(), PaintOpType::Noop);
+
+ // Verify iteration behavior and brief smoke test of op state.
+ {
+ PaintOpBuffer::Iterator iter(&buffer);
+ PaintOp* noop = *iter;
+ EXPECT_EQ(buffer.GetFirstOp(), noop);
+ ++iter;
+
+ PaintOp* op = *iter;
+ ASSERT_EQ(op->GetType(), PaintOpType::DrawText);
+ DrawTextOp* draw_text_op = static_cast<DrawTextOp*>(op);
+ EXPECT_EQ(draw_text_op->bytes, arraysize(text));
+
+ const void* data = draw_text_op->GetData();
+ EXPECT_EQ(memcmp(data, text, arraysize(text)), 0);
+
+ ++iter;
+ EXPECT_FALSE(iter);
+ }
+
+ // Reset, verify state, and append an op that will fit in the first slot.
+ buffer.Reset();
+ CheckRefCnt(filter, 2);
+
+ ASSERT_EQ(buffer.size(), 0u);
+ EXPECT_EQ(PaintOpBuffer::Iterator(&buffer), false);
+
+ SkRect rect = SkRect::MakeXYWH(1, 2, 3, 4);
+ buffer.push<DrawRectOp>(rect, flags);
+ CheckRefCnt(filter, 3);
+
+ ASSERT_EQ(buffer.size(), 1u);
+ EXPECT_EQ(buffer.GetFirstOp()->GetType(), PaintOpType::DrawRect);
+
+ PaintOpBuffer::Iterator iter(&buffer);
+ ASSERT_EQ(iter->GetType(), PaintOpType::DrawRect);
+ DrawRectOp* draw_rect_op = static_cast<DrawRectOp*>(*iter);
+ EXPECT_EQ(draw_rect_op->rect, rect);
+
+ ++iter;
+ EXPECT_FALSE(iter);
+
+ buffer.Reset();
+ ASSERT_EQ(buffer.size(), 0u);
+ CheckRefCnt(filter, 2);
+}
+
+// Verify that PaintOps with data are stored properly.
+TEST(PaintOpBufferTest, PaintOpData) {
+ PaintOpBuffer buffer;
+
+ buffer.push<SaveOp>();
+ PaintFlags flags;
+ char text1[] = "asdfasdf";
+ buffer.push_with_data<DrawTextOp>(text1, arraysize(text1), 0.f, 0.f, flags);
+
+ char text2[] = "qwerty";
+ buffer.push_with_data<DrawTextOp>(text2, arraysize(text2), 0.f, 0.f, flags);
+
+ ASSERT_EQ(buffer.size(), 3u);
+
+ // Verify iteration behavior and brief smoke test of op state.
+ PaintOpBuffer::Iterator iter(&buffer);
+ PaintOp* save_op = *iter;
+ EXPECT_EQ(save_op->GetType(), PaintOpType::Save);
+ ++iter;
+
+ PaintOp* op1 = *iter;
+ ASSERT_EQ(op1->GetType(), PaintOpType::DrawText);
+ DrawTextOp* draw_text_op1 = static_cast<DrawTextOp*>(op1);
+ EXPECT_EQ(draw_text_op1->bytes, arraysize(text1));
+ const void* data1 = draw_text_op1->GetData();
+ EXPECT_EQ(memcmp(data1, text1, arraysize(text1)), 0);
+ ++iter;
+
+ PaintOp* op2 = *iter;
+ ASSERT_EQ(op2->GetType(), PaintOpType::DrawText);
+ DrawTextOp* draw_text_op2 = static_cast<DrawTextOp*>(op2);
+ EXPECT_EQ(draw_text_op2->bytes, arraysize(text2));
+ const void* data2 = draw_text_op2->GetData();
+ EXPECT_EQ(memcmp(data2, text2, arraysize(text2)), 0);
+ ++iter;
+
+ EXPECT_FALSE(iter);
+}
+
+// Verify that PaintOps with arrays are stored properly.
+TEST(PaintOpBufferTest, PaintOpArray) {
+ PaintOpBuffer buffer;
+ buffer.push<SaveOp>();
+
+ // arbitrary data
+ std::string texts[] = {"xyz", "abcdefg", "thingerdoo"};
+ SkPoint point1[] = {SkPoint::Make(1, 2), SkPoint::Make(2, 3),
+ SkPoint::Make(3, 4)};
+ SkPoint point2[] = {SkPoint::Make(8, -12)};
+ SkPoint point3[] = {SkPoint::Make(0, 0), SkPoint::Make(5, 6),
+ SkPoint::Make(-1, -1), SkPoint::Make(9, 9),
+ SkPoint::Make(50, 50), SkPoint::Make(100, 100)};
+ SkPoint* points[] = {point1, point2, point3};
+ size_t counts[] = {arraysize(point1), arraysize(point2), arraysize(point3)};
+
+ for (size_t i = 0; i < arraysize(texts); ++i) {
+ PaintFlags flags;
+ flags.setAlpha(i);
+ buffer.push_with_array<DrawPosTextOp>(texts[i].c_str(), texts[i].length(),
+ points[i], counts[i], flags);
+ }
+
+ PaintOpBuffer::Iterator iter(&buffer);
+ PaintOp* save_op = *iter;
+ EXPECT_EQ(save_op->GetType(), PaintOpType::Save);
+ ++iter;
+
+ for (size_t i = 0; i < arraysize(texts); ++i) {
+ ASSERT_EQ(iter->GetType(), PaintOpType::DrawPosText);
+ DrawPosTextOp* op = static_cast<DrawPosTextOp*>(*iter);
+
+ EXPECT_EQ(op->flags.getAlpha(), i);
+
+ EXPECT_EQ(op->bytes, texts[i].length());
+ const void* data = op->GetData();
+ EXPECT_EQ(memcmp(data, texts[i].c_str(), op->bytes), 0);
+
+ EXPECT_EQ(op->count, counts[i]);
+ const SkPoint* op_points = op->GetArray();
+ for (size_t k = 0; k < op->count; ++k)
+ EXPECT_EQ(op_points[k], points[i][k]);
+
+ ++iter;
+ }
+
+ EXPECT_FALSE(iter);
+}
+
+// Verify that a SaveLayerAlpha / Draw / Restore can be optimized to just
+// a draw with opacity.
+TEST(PaintOpBufferTest, SaveDrawRestore) {
+ PaintOpBuffer buffer;
+
+ uint8_t alpha = 100;
+ buffer.push<SaveLayerAlphaOp>(nullptr, alpha);
+
+ PaintFlags draw_flags;
+ draw_flags.setColor(SK_ColorMAGENTA);
+ draw_flags.setAlpha(50);
+ EXPECT_TRUE(draw_flags.SupportsFoldingAlpha());
+ SkRect rect = SkRect::MakeXYWH(1, 2, 3, 4);
+ buffer.push<DrawRectOp>(rect, draw_flags);
+ buffer.push<RestoreOp>();
+
+ SaveCountingCanvas canvas;
+ buffer.playback(&canvas);
+
+ EXPECT_EQ(0, canvas.save_count_);
+ EXPECT_EQ(0, canvas.restore_count_);
+ EXPECT_EQ(rect, canvas.draw_rect_);
+
+ // Expect the alpha from the draw and the save layer to be folded together.
+ // Since alpha is stored in a uint8_t and gets rounded, so use tolerance.
+ float expected_alpha = alpha * 50 / 255.f;
+ EXPECT_LE(std::abs(expected_alpha - canvas.paint_.getAlpha()), 1.f);
+}
+
+// The same as SaveDrawRestore, but test that the optimization doesn't apply
+// when the drawing op's flags are not compatible with being folded into the
+// save layer with opacity.
+TEST(PaintOpBufferTest, SaveDrawRestoreFail_BadFlags) {
+ PaintOpBuffer buffer;
+
+ uint8_t alpha = 100;
+ buffer.push<SaveLayerAlphaOp>(nullptr, alpha);
+
+ PaintFlags draw_flags;
+ draw_flags.setColor(SK_ColorMAGENTA);
+ draw_flags.setAlpha(50);
+ draw_flags.setBlendMode(SkBlendMode::kSrc);
+ EXPECT_FALSE(draw_flags.SupportsFoldingAlpha());
+ SkRect rect = SkRect::MakeXYWH(1, 2, 3, 4);
+ buffer.push<DrawRectOp>(rect, draw_flags);
+ buffer.push<RestoreOp>();
+
+ SaveCountingCanvas canvas;
+ buffer.playback(&canvas);
+
+ EXPECT_EQ(1, canvas.save_count_);
+ EXPECT_EQ(1, canvas.restore_count_);
+ EXPECT_EQ(rect, canvas.draw_rect_);
+ EXPECT_EQ(draw_flags.getAlpha(), canvas.paint_.getAlpha());
+}
+
+// The same as SaveDrawRestore, but test that the optimization doesn't apply
+// when there are more than one ops between the save and restore.
+TEST(PaintOpBufferTest, SaveDrawRestoreFail_TooManyOps) {
+ PaintOpBuffer buffer;
+
+ uint8_t alpha = 100;
+ buffer.push<SaveLayerAlphaOp>(nullptr, alpha);
+
+ PaintFlags draw_flags;
+ draw_flags.setColor(SK_ColorMAGENTA);
+ draw_flags.setAlpha(50);
+ draw_flags.setBlendMode(SkBlendMode::kSrcOver);
+ EXPECT_TRUE(draw_flags.SupportsFoldingAlpha());
+ SkRect rect = SkRect::MakeXYWH(1, 2, 3, 4);
+ buffer.push<DrawRectOp>(rect, draw_flags);
+ buffer.push<NoopOp>();
+ buffer.push<RestoreOp>();
+
+ SaveCountingCanvas canvas;
+ buffer.playback(&canvas);
+
+ EXPECT_EQ(1, canvas.save_count_);
+ EXPECT_EQ(1, canvas.restore_count_);
+ EXPECT_EQ(rect, canvas.draw_rect_);
+ EXPECT_EQ(draw_flags.getAlpha(), canvas.paint_.getAlpha());
+}
+
+// Verify that the save draw restore code works with a single op
+// that's not a draw op, and the optimization does not kick in.
+TEST(PaintOpBufferTest, SaveDrawRestore_SingleOpNotADrawOp) {
+ PaintOpBuffer buffer;
+
+ uint8_t alpha = 100;
+ buffer.push<SaveLayerAlphaOp>(nullptr, alpha);
+
+ buffer.push<NoopOp>();
+ buffer.push<RestoreOp>();
+
+ SaveCountingCanvas canvas;
+ buffer.playback(&canvas);
+
+ EXPECT_EQ(1, canvas.save_count_);
+ EXPECT_EQ(1, canvas.restore_count_);
+}
+
+// Test that the save/draw/restore optimization applies if the single op
+// is a DrawRecord that itself has a single draw op.
+TEST(PaintOpBufferTest, SaveDrawRestore_SingleOpRecordWithSingleOp) {
+ sk_sp<PaintRecord> record = sk_make_sp<PaintRecord>();
+
+ PaintFlags draw_flags;
+ draw_flags.setColor(SK_ColorMAGENTA);
+ draw_flags.setAlpha(50);
+ EXPECT_TRUE(draw_flags.SupportsFoldingAlpha());
+ SkRect rect = SkRect::MakeXYWH(1, 2, 3, 4);
+ record->push<DrawRectOp>(rect, draw_flags);
+ EXPECT_EQ(record->size(), 1u);
+
+ PaintOpBuffer buffer;
+
+ uint8_t alpha = 100;
+ buffer.push<SaveLayerAlphaOp>(nullptr, alpha);
+ buffer.push<DrawRecordOp>(std::move(record));
+ buffer.push<RestoreOp>();
+
+ SaveCountingCanvas canvas;
+ buffer.playback(&canvas);
+
+ EXPECT_EQ(0, canvas.save_count_);
+ EXPECT_EQ(0, canvas.restore_count_);
+ EXPECT_EQ(rect, canvas.draw_rect_);
+
+ float expected_alpha = alpha * 50 / 255.f;
+ EXPECT_LE(std::abs(expected_alpha - canvas.paint_.getAlpha()), 1.f);
+}
+
+// The same as the above SingleOpRecord test, but the single op is not
+// a draw op. So, there's no way to fold in the save layer optimization.
+// Verify that the optimization doesn't apply and that this doesn't crash.
+// See: http://crbug.com/712093.
+TEST(PaintOpBufferTest, SaveDrawRestore_SingleOpRecordWithSingleNonDrawOp) {
+ sk_sp<PaintRecord> record = sk_make_sp<PaintRecord>();
+ record->push<NoopOp>();
+ EXPECT_EQ(record->size(), 1u);
+ EXPECT_FALSE(record->GetFirstOp()->IsDrawOp());
+
+ PaintOpBuffer buffer;
+
+ uint8_t alpha = 100;
+ buffer.push<SaveLayerAlphaOp>(nullptr, alpha);
+ buffer.push<DrawRecordOp>(std::move(record));
+ buffer.push<RestoreOp>();
+
+ SaveCountingCanvas canvas;
+ buffer.playback(&canvas);
+
+ EXPECT_EQ(1, canvas.save_count_);
+ EXPECT_EQ(1, canvas.restore_count_);
+}
+
+TEST(PaintOpBufferTest, DiscardableImagesTracking_EmptyBuffer) {
+ PaintOpBuffer buffer;
+ EXPECT_FALSE(buffer.HasDiscardableImages());
+}
+
+TEST(PaintOpBufferTest, DiscardableImagesTracking_NoImageOp) {
+ PaintOpBuffer buffer;
+ PaintFlags flags;
+ buffer.push<DrawRectOp>(SkRect::MakeWH(100, 100), flags);
+ EXPECT_FALSE(buffer.HasDiscardableImages());
+}
+
+TEST(PaintOpBufferTest, DiscardableImagesTracking_DrawImage) {
+ PaintOpBuffer buffer;
+ PaintImage image = PaintImage(PaintImage::GetNextId(),
+ CreateDiscardableImage(gfx::Size(100, 100)));
+ buffer.push<DrawImageOp>(image, SkIntToScalar(0), SkIntToScalar(0), nullptr);
+ EXPECT_TRUE(buffer.HasDiscardableImages());
+}
+
+TEST(PaintOpBufferTest, DiscardableImagesTracking_DrawImageRect) {
+ PaintOpBuffer buffer;
+ PaintImage image = PaintImage(PaintImage::GetNextId(),
+ CreateDiscardableImage(gfx::Size(100, 100)));
+ buffer.push<DrawImageRectOp>(
+ image, SkRect::MakeWH(100, 100), SkRect::MakeWH(100, 100), nullptr,
+ PaintCanvas::SrcRectConstraint::kFast_SrcRectConstraint);
+ EXPECT_TRUE(buffer.HasDiscardableImages());
+}
+
+TEST(PaintOpBufferTest, DiscardableImagesTracking_NestedDrawOp) {
+ sk_sp<PaintRecord> record = sk_make_sp<PaintRecord>();
+ PaintImage image = PaintImage(PaintImage::GetNextId(),
+ CreateDiscardableImage(gfx::Size(100, 100)));
+ record->push<DrawImageOp>(image, SkIntToScalar(0), SkIntToScalar(0), nullptr);
+
+ PaintOpBuffer buffer;
+ buffer.push<DrawRecordOp>(record);
+ EXPECT_TRUE(buffer.HasDiscardableImages());
+
+ scoped_refptr<DisplayItemList> list = new DisplayItemList;
+ list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
+ gfx::Rect(100, 100), record, SkRect::MakeWH(100, 100));
+ list->Finalize();
+ PaintOpBuffer new_buffer;
+ new_buffer.push<DrawDisplayItemListOp>(list);
+ EXPECT_TRUE(new_buffer.HasDiscardableImages());
+}
+
+TEST(PaintOpBufferTest, DiscardableImagesTracking_OpWithFlags) {
+ PaintOpBuffer buffer;
+ PaintFlags flags;
+ sk_sp<SkImage> image = CreateDiscardableImage(gfx::Size(100, 100));
+ flags.setShader(
+ image->makeShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode));
+ buffer.push<DrawRectOp>(SkRect::MakeWH(100, 100), flags);
+ EXPECT_TRUE(buffer.HasDiscardableImages());
+}
+
+TEST(PaintOpBufferTest, SlowPaths) {
+ auto buffer = sk_make_sp<PaintOpBuffer>();
+ EXPECT_EQ(buffer->numSlowPaths(), 0);
+
+ // Op without slow paths
+ PaintFlags noop_flags;
+ SkRect rect = SkRect::MakeXYWH(2, 3, 4, 5);
+ buffer->push<SaveLayerOp>(&rect, &noop_flags);
+
+ // Line op with a slow path
+ PaintFlags line_effect_slow;
+ line_effect_slow.setStrokeWidth(1.f);
+ line_effect_slow.setStyle(PaintFlags::kStroke_Style);
+ line_effect_slow.setStrokeCap(PaintFlags::kRound_Cap);
+ SkScalar intervals[] = {1.f, 1.f};
+ line_effect_slow.setPathEffect(SkDashPathEffect::Make(intervals, 2, 0));
+
+ buffer->push<DrawLineOp>(1.f, 2.f, 3.f, 4.f, line_effect_slow);
+ EXPECT_EQ(buffer->numSlowPaths(), 1);
+
+ // Line effect special case that Skia handles specially.
+ PaintFlags line_effect = line_effect_slow;
+ line_effect.setStrokeCap(PaintFlags::kButt_Cap);
+ buffer->push<DrawLineOp>(1.f, 2.f, 3.f, 4.f, line_effect);
+ EXPECT_EQ(buffer->numSlowPaths(), 1);
+
+ // Antialiased convex path is not slow.
+ SkPath path;
+ path.addCircle(2, 2, 5);
+ EXPECT_TRUE(path.isConvex());
+ buffer->push<ClipPathOp>(path, SkClipOp::kIntersect, true);
+ EXPECT_EQ(buffer->numSlowPaths(), 1);
+
+ // Concave paths are slow only when antialiased.
+ SkPath concave = path;
+ concave.addCircle(3, 4, 2);
+ EXPECT_FALSE(concave.isConvex());
+ buffer->push<ClipPathOp>(concave, SkClipOp::kIntersect, true);
+ EXPECT_EQ(buffer->numSlowPaths(), 2);
+ buffer->push<ClipPathOp>(concave, SkClipOp::kIntersect, false);
+ EXPECT_EQ(buffer->numSlowPaths(), 2);
+
+ // Drawing a record with slow paths into another adds the same
+ // number of slow paths as the record.
+ auto buffer2 = sk_make_sp<PaintOpBuffer>();
+ EXPECT_EQ(buffer2->numSlowPaths(), 0);
+ buffer2->push<DrawRecordOp>(buffer);
+ EXPECT_EQ(buffer->numSlowPaths(), buffer2->numSlowPaths());
+}
+
+TEST(PaintOpBufferTest, ContiguousRanges) {
+ PaintOpBuffer buffer;
+ MockCanvas canvas;
+
+ buffer.push<DrawColorOp>(0u, SkBlendMode::kClear);
+ buffer.push<DrawColorOp>(1u, SkBlendMode::kClear);
+ buffer.push<DrawColorOp>(2u, SkBlendMode::kClear);
+ buffer.push<DrawColorOp>(3u, SkBlendMode::kClear);
+ buffer.push<DrawColorOp>(4u, SkBlendMode::kClear);
+
+ // Ranges are {0, 1}, {2}, {3, 4}.
+ std::vector<size_t> ranges = {0, 2, 3};
+
+ // Plays all 3 ranges.
+ testing::Sequence s;
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(0u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(1u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(2u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(3u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(4u)).InSequence(s);
+ buffer.PlaybackRanges(ranges, {0, 1, 2}, &canvas);
+}
+
+TEST(PaintOpBufferTest, NonContiguousRanges) {
+ PaintOpBuffer buffer;
+ MockCanvas canvas;
+
+ buffer.push<DrawColorOp>(0u, SkBlendMode::kClear);
+ buffer.push<DrawColorOp>(1u, SkBlendMode::kClear);
+ buffer.push<DrawColorOp>(2u, SkBlendMode::kClear);
+ buffer.push<DrawColorOp>(3u, SkBlendMode::kClear);
+ buffer.push<DrawColorOp>(4u, SkBlendMode::kClear);
+
+ // Ranges are {0, 1}, {2}, {3, 4}.
+ std::vector<size_t> ranges = {0, 2, 3};
+
+ // Plays first and third ranges.
+ testing::Sequence s;
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(0u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(1u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(3u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(4u)).InSequence(s);
+ buffer.PlaybackRanges(ranges, {0, 2}, &canvas);
+}
+
+TEST(PaintOpBufferTest, FirstRange) {
+ PaintOpBuffer buffer;
+ MockCanvas canvas;
+
+ buffer.push<DrawColorOp>(0u, SkBlendMode::kClear);
+ buffer.push<DrawColorOp>(1u, SkBlendMode::kClear);
+ buffer.push<DrawColorOp>(2u, SkBlendMode::kClear);
+ buffer.push<DrawColorOp>(3u, SkBlendMode::kClear);
+ buffer.push<DrawColorOp>(4u, SkBlendMode::kClear);
+
+ // Ranges are {0, 1}, {2}, {3, 4}.
+ std::vector<size_t> ranges = {0, 2, 3};
+
+ // Plays first range.
+ testing::Sequence s;
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(0u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(1u)).InSequence(s);
+ buffer.PlaybackRanges(ranges, {0}, &canvas);
+}
+
+TEST(PaintOpBufferTest, MiddleRange) {
+ PaintOpBuffer buffer;
+ MockCanvas canvas;
+
+ buffer.push<DrawColorOp>(0u, SkBlendMode::kClear);
+ buffer.push<DrawColorOp>(1u, SkBlendMode::kClear);
+ buffer.push<DrawColorOp>(2u, SkBlendMode::kClear);
+ buffer.push<DrawColorOp>(3u, SkBlendMode::kClear);
+ buffer.push<DrawColorOp>(4u, SkBlendMode::kClear);
+
+ // Ranges are {0, 1}, {2}, {3, 4}.
+ std::vector<size_t> ranges = {0, 2, 3};
+
+ // Plays second range.
+ testing::Sequence s;
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(2u)).InSequence(s);
+ buffer.PlaybackRanges(ranges, {1}, &canvas);
+}
+
+TEST(PaintOpBufferTest, LastRange) {
+ PaintOpBuffer buffer;
+ MockCanvas canvas;
+
+ buffer.push<DrawColorOp>(0u, SkBlendMode::kClear);
+ buffer.push<DrawColorOp>(1u, SkBlendMode::kClear);
+ buffer.push<DrawColorOp>(2u, SkBlendMode::kClear);
+ buffer.push<DrawColorOp>(3u, SkBlendMode::kClear);
+ buffer.push<DrawColorOp>(4u, SkBlendMode::kClear);
+
+ // Ranges are {0, 1}, {2}, {3, 4}.
+ std::vector<size_t> ranges = {0, 2, 3};
+
+ // Plays third range.
+ testing::Sequence s;
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(3u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(4u)).InSequence(s);
+ buffer.PlaybackRanges(ranges, {2}, &canvas);
+}
+
+TEST(PaintOpBufferTest, ContiguousRangeWithSaveLayerAlphaRestore) {
+ PaintOpBuffer buffer;
+ MockCanvas canvas;
+
+ buffer.push<DrawColorOp>(0u, SkBlendMode::kClear);
+ buffer.push<DrawColorOp>(1u, SkBlendMode::kClear);
+ uint8_t alpha = 100;
+ buffer.push<SaveLayerAlphaOp>(nullptr, alpha);
+ buffer.push<RestoreOp>();
+ buffer.push<DrawColorOp>(2u, SkBlendMode::kClear);
+ buffer.push<DrawColorOp>(3u, SkBlendMode::kClear);
+ buffer.push<DrawColorOp>(4u, SkBlendMode::kClear);
+
+ {
+ // Ranges are {0, 1, save, restore}, {2}, {3, 4}.
+ std::vector<size_t> ranges = {0, 4, 5};
+
+ testing::Sequence s;
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(0u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(1u)).InSequence(s);
+ // The empty SaveLayerAlpha/Restore is dropped.
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(2u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(3u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(4u)).InSequence(s);
+ buffer.PlaybackRanges(ranges, {0, 1, 2}, &canvas);
+ }
+ Mock::VerifyAndClearExpectations(&canvas);
+
+ {
+ // Ranges are {0, 1}, {save, restore}, {2}, {3, 4}.
+ std::vector<size_t> ranges = {0, 2, 4, 5};
+
+ testing::Sequence s;
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(0u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(1u)).InSequence(s);
+ // The empty SaveLayerAlpha/Restore is dropped.
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(2u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(3u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(4u)).InSequence(s);
+ buffer.PlaybackRanges(ranges, {0, 1, 2, 3}, &canvas);
+ }
+ Mock::VerifyAndClearExpectations(&canvas);
+
+ {
+ // Ranges are {0, 1}, {save, restore, 2}, {3, 4}.
+ std::vector<size_t> ranges = {0, 2, 5};
+
+ testing::Sequence s;
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(0u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(1u)).InSequence(s);
+ // The empty SaveLayerAlpha/Restore is dropped.
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(2u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(3u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(4u)).InSequence(s);
+ buffer.PlaybackRanges(ranges, {0, 1, 2}, &canvas);
+ }
+ Mock::VerifyAndClearExpectations(&canvas);
+
+ {
+ // Ranges are {0, 1, save}, {restore, 2}, {3, 4}.
+ std::vector<size_t> ranges = {0, 3, 5};
+
+ testing::Sequence s;
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(0u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(1u)).InSequence(s);
+ // The empty SaveLayerAlpha/Restore is dropped.
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(2u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(3u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(4u)).InSequence(s);
+ buffer.PlaybackRanges(ranges, {0, 1, 2}, &canvas);
+ }
+}
+
+TEST(PaintOpBufferTest, NonContiguousRangeWithSaveLayerAlphaRestore) {
+ PaintOpBuffer buffer;
+ MockCanvas canvas;
+
+ buffer.push<DrawColorOp>(0u, SkBlendMode::kClear);
+ buffer.push<DrawColorOp>(1u, SkBlendMode::kClear);
+ uint8_t alpha = 100;
+ buffer.push<SaveLayerAlphaOp>(nullptr, alpha);
+ buffer.push<DrawColorOp>(2u, SkBlendMode::kClear);
+ buffer.push<DrawColorOp>(3u, SkBlendMode::kClear);
+ buffer.push<RestoreOp>();
+ buffer.push<DrawColorOp>(4u, SkBlendMode::kClear);
+
+ // Ranges are {0, 1, save}, {2, 3}, {restore, 4}.
+ std::vector<size_t> ranges = {0, 3, 5};
+
+ // Plays back all ranges.
+ {
+ testing::Sequence s;
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(0u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(1u)).InSequence(s);
+ // The SaveLayerAlpha/Restore is not dropped if we draw the middle
+ // range, as we need them to represent the two draws inside the layer
+ // correctly.
+ EXPECT_CALL(canvas, OnSaveLayer()).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(2u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(3u)).InSequence(s);
+ EXPECT_CALL(canvas, willRestore()).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(4u)).InSequence(s);
+ buffer.PlaybackRanges(ranges, {0, 1, 2}, &canvas);
+ }
+ Mock::VerifyAndClearExpectations(&canvas);
+
+ // Skips the middle range.
+ {
+ testing::Sequence s;
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(0u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(1u)).InSequence(s);
+ // The now-empty SaveLayerAlpha/Restore is dropped
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(4u)).InSequence(s);
+ buffer.PlaybackRanges(ranges, {0, 2}, &canvas);
+ }
+
+ // Repeat with ranges that contain just the save and restore, as
+ // {0, 1}, {save}, {2, 3}, {restore}, {4}.
+ ranges = {0, 2, 3, 5, 6};
+
+ // Plays back all ranges.
+ {
+ testing::Sequence s;
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(0u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(1u)).InSequence(s);
+ // The SaveLayerAlpha/Restore is not dropped if we draw the middle
+ // range, as we need them to represent the two draws inside the layer
+ // correctly.
+ EXPECT_CALL(canvas, OnSaveLayer()).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(2u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(3u)).InSequence(s);
+ EXPECT_CALL(canvas, willRestore()).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(4u)).InSequence(s);
+ buffer.PlaybackRanges(ranges, {0, 1, 2, 3, 4}, &canvas);
+ }
+ Mock::VerifyAndClearExpectations(&canvas);
+
+ // Skips the middle range.
+ {
+ testing::Sequence s;
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(0u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(1u)).InSequence(s);
+ // The now-empty SaveLayerAlpha/Restore is dropped
+ EXPECT_CALL(canvas, OnDrawPaintWithColor(4u)).InSequence(s);
+ buffer.PlaybackRanges(ranges, {0, 1, 3, 4}, &canvas);
+ }
+}
+
+TEST(PaintOpBufferTest, ContiguousRangeWithSaveLayerAlphaDrawRestore) {
+ PaintOpBuffer buffer;
+ MockCanvas canvas;
+
+ auto add_draw_rect = [](PaintOpBuffer* buffer, SkColor c) {
+ PaintFlags flags;
+ flags.setColor(c);
+ buffer->push<DrawRectOp>(SkRect::MakeWH(1, 1), flags);
+ };
+
+ add_draw_rect(&buffer, 0u);
+ add_draw_rect(&buffer, 1u);
+ uint8_t alpha = 100;
+ buffer.push<SaveLayerAlphaOp>(nullptr, alpha);
+ add_draw_rect(&buffer, 2u);
+ buffer.push<RestoreOp>();
+ add_draw_rect(&buffer, 3u);
+ add_draw_rect(&buffer, 4u);
+
+ {
+ // Ranges are {0, 1, save, 2, restore}, {3, 4}.
+ std::vector<size_t> ranges = {0, 5};
+
+ testing::Sequence s;
+ EXPECT_CALL(canvas, OnDrawRectWithColor(0u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawRectWithColor(1u)).InSequence(s);
+ // The empty SaveLayerAlpha/Restore is duropped, the containing
+ // operation can be drawn with alpha.
+ EXPECT_CALL(canvas, OnDrawRectWithColor(2u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawRectWithColor(3u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawRectWithColor(4u)).InSequence(s);
+ buffer.PlaybackRanges(ranges, {0, 1}, &canvas);
+ }
+ Mock::VerifyAndClearExpectations(&canvas);
+
+ {
+ // Ranges are {0, 1, save, 2}, {restore}, {3, 4}.
+ std::vector<size_t> ranges = {0, 4, 5};
+
+ testing::Sequence s;
+ EXPECT_CALL(canvas, OnDrawRectWithColor(0u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawRectWithColor(1u)).InSequence(s);
+ // The empty SaveLayerAlpha/Restore is dropped, the containing
+ // operation can be drawn with alpha.
+ EXPECT_CALL(canvas, OnDrawRectWithColor(2u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawRectWithColor(3u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawRectWithColor(4u)).InSequence(s);
+ buffer.PlaybackRanges(ranges, {0, 1, 2}, &canvas);
+ }
+ Mock::VerifyAndClearExpectations(&canvas);
+
+ {
+ // Ranges are {0, 1, save}, {2, restore}, {3, 4}.
+ std::vector<size_t> ranges = {0, 3, 5};
+
+ testing::Sequence s;
+ EXPECT_CALL(canvas, OnDrawRectWithColor(0u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawRectWithColor(1u)).InSequence(s);
+ // The empty SaveLayerAlpha/Restore is dropped, the containing
+ // operation can be drawn with alpha.
+ EXPECT_CALL(canvas, OnDrawRectWithColor(2u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawRectWithColor(3u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawRectWithColor(4u)).InSequence(s);
+ buffer.PlaybackRanges(ranges, {0, 1, 2}, &canvas);
+ }
+ Mock::VerifyAndClearExpectations(&canvas);
+
+ {
+ // Ranges are {0, 1, save}, {2}, {restore}, {3, 4}.
+ std::vector<size_t> ranges = {0, 3, 4, 5};
+
+ testing::Sequence s;
+ EXPECT_CALL(canvas, OnDrawRectWithColor(0u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawRectWithColor(1u)).InSequence(s);
+ // The empty SaveLayerAlpha/Restore is dropped, the containing
+ // operation can be drawn with alpha.
+ EXPECT_CALL(canvas, OnDrawRectWithColor(2u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawRectWithColor(3u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawRectWithColor(4u)).InSequence(s);
+ buffer.PlaybackRanges(ranges, {0, 1, 2, 3}, &canvas);
+ }
+ Mock::VerifyAndClearExpectations(&canvas);
+}
+
+TEST(PaintOpBufferTest, NonContiguousRangeWithSaveLayerAlphaDrawRestore) {
+ PaintOpBuffer buffer;
+ MockCanvas canvas;
+
+ auto add_draw_rect = [](PaintOpBuffer* buffer, SkColor c) {
+ PaintFlags flags;
+ flags.setColor(c);
+ buffer->push<DrawRectOp>(SkRect::MakeWH(1, 1), flags);
+ };
+
+ add_draw_rect(&buffer, 0u);
+ add_draw_rect(&buffer, 1u);
+ uint8_t alpha = 100;
+ buffer.push<SaveLayerAlphaOp>(nullptr, alpha);
+ add_draw_rect(&buffer, 2u);
+ add_draw_rect(&buffer, 3u);
+ add_draw_rect(&buffer, 4u);
+ buffer.push<RestoreOp>();
+
+ // Ranges are {0, 1, save}, {2, 3}, {4, restore}.
+ std::vector<size_t> ranges = {0, 3, 5};
+
+ // If the middle range is played, then the SaveLayerAlpha/Restore
+ // can't be dropped.
+ {
+ testing::Sequence s;
+ EXPECT_CALL(canvas, OnDrawRectWithColor(0u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawRectWithColor(1u)).InSequence(s);
+ EXPECT_CALL(canvas, OnSaveLayer()).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawRectWithColor(2u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawRectWithColor(3u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawRectWithColor(4u)).InSequence(s);
+ EXPECT_CALL(canvas, willRestore()).InSequence(s);
+ buffer.PlaybackRanges(ranges, {0, 1, 2}, &canvas);
+ }
+ Mock::VerifyAndClearExpectations(&canvas);
+
+ // If the middle range is not played, then the SaveLayerAlpha/Restore
+ // can be dropped.
+ {
+ testing::Sequence s;
+ EXPECT_CALL(canvas, OnDrawRectWithColor(0u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawRectWithColor(1u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawRectWithColor(4u)).InSequence(s);
+ buffer.PlaybackRanges(ranges, {0, 2}, &canvas);
+ }
+ Mock::VerifyAndClearExpectations(&canvas);
+
+ // Ranges are {0, 1, save, 2}, {3, 4}, {restore}.
+ ranges = {0, 4, 6};
+
+ // If the middle range is not played, then the SaveLayerAlpha/Restore
+ // can be dropped.
+ {
+ testing::Sequence s;
+ EXPECT_CALL(canvas, OnDrawRectWithColor(0u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawRectWithColor(1u)).InSequence(s);
+ EXPECT_CALL(canvas, OnDrawRectWithColor(2u)).InSequence(s);
+ buffer.PlaybackRanges(ranges, {0, 2}, &canvas);
+ }
+}
+
+} // namespace cc
diff --git a/chromium/cc/paint/paint_record.cc b/chromium/cc/paint/paint_record.cc
new file mode 100644
index 00000000000..24830068913
--- /dev/null
+++ b/chromium/cc/paint/paint_record.cc
@@ -0,0 +1,27 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/paint/paint_record.h"
+
+#include "cc/paint/paint_op_buffer.h"
+#include "third_party/skia/include/core/SkPictureRecorder.h"
+
+namespace cc {
+
+sk_sp<SkPicture> ToSkPicture(sk_sp<PaintRecord> record, const SkRect& bounds) {
+ SkPictureRecorder recorder;
+ SkCanvas* canvas = recorder.beginRecording(bounds);
+ record->playback(canvas);
+ return recorder.finishRecordingAsPicture();
+}
+
+sk_sp<const SkPicture> ToSkPicture(sk_sp<const PaintRecord> record,
+ const SkRect& bounds) {
+ SkPictureRecorder recorder;
+ SkCanvas* canvas = recorder.beginRecording(bounds);
+ record->playback(canvas);
+ return recorder.finishRecordingAsPicture();
+}
+
+} // namespace cc
diff --git a/chromium/cc/paint/paint_record.h b/chromium/cc/paint/paint_record.h
index 8506606b59f..1509bac0529 100644
--- a/chromium/cc/paint/paint_record.h
+++ b/chromium/cc/paint/paint_record.h
@@ -5,19 +5,24 @@
#ifndef CC_PAINT_PAINT_RECORD_H_
#define CC_PAINT_PAINT_RECORD_H_
+#include "cc/paint/paint_export.h"
+#include "cc/paint/paint_op_buffer.h"
#include "third_party/skia/include/core/SkPicture.h"
namespace cc {
-using PaintRecord = SkPicture;
+// TODO(enne): Don't want to rename the world for this. Using these as the
+// same types for now prevents an extra allocation. Probably PaintRecord
+// will become an interface in the future.
+using PaintRecord = PaintOpBuffer;
-inline sk_sp<SkPicture> ToSkPicture(sk_sp<PaintRecord> record) {
- return record;
-}
+// TODO(enne): Remove these if possible, they are really expensive.
+CC_PAINT_EXPORT sk_sp<SkPicture> ToSkPicture(sk_sp<PaintRecord> record,
+ const SkRect& bounds);
-inline sk_sp<const SkPicture> ToSkPicture(sk_sp<const PaintRecord> record) {
- return record;
-}
+CC_PAINT_EXPORT sk_sp<const SkPicture> ToSkPicture(
+ sk_sp<const PaintRecord> record,
+ const SkRect& bounds);
} // namespace cc
diff --git a/chromium/cc/paint/paint_recorder.cc b/chromium/cc/paint/paint_recorder.cc
index 672f0712725..20f5cacd2d6 100644
--- a/chromium/cc/paint/paint_recorder.cc
+++ b/chromium/cc/paint/paint_recorder.cc
@@ -4,9 +4,36 @@
#include "cc/paint/paint_recorder.h"
+#include "cc/paint/paint_op_buffer.h"
+
namespace cc {
PaintRecorder::PaintRecorder() = default;
+
PaintRecorder::~PaintRecorder() = default;
+PaintCanvas* PaintRecorder::beginRecording(const SkRect& bounds) {
+ buffer_ = sk_make_sp<PaintOpBuffer>();
+ canvas_.emplace(buffer_.get(), bounds);
+ return getRecordingCanvas();
+}
+
+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();
+
+ buffer_->ShrinkToFit();
+ return std::move(buffer_);
+}
+
} // namespace cc
diff --git a/chromium/cc/paint/paint_recorder.h b/chromium/cc/paint/paint_recorder.h
index 2bbea83b981..7f582b85191 100644
--- a/chromium/cc/paint/paint_recorder.h
+++ b/chromium/cc/paint/paint_recorder.h
@@ -9,47 +9,36 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/optional.h"
-#include "cc/paint/paint_canvas.h"
#include "cc/paint/paint_record.h"
-#include "cc/paint/skia_paint_canvas.h"
-#include "third_party/skia/include/core/SkPictureRecorder.h"
+#include "cc/paint/record_paint_canvas.h"
namespace cc {
+class PaintOpBuffer;
+
class CC_PAINT_EXPORT PaintRecorder {
public:
PaintRecorder();
~PaintRecorder();
- ALWAYS_INLINE PaintCanvas* beginRecording(const SkRect& bounds) {
- uint32_t record_flags = 0;
- canvas_.emplace(recorder_.beginRecording(bounds, nullptr, record_flags));
- return getRecordingCanvas();
- }
+ PaintCanvas* beginRecording(const SkRect& bounds);
- ALWAYS_INLINE PaintCanvas* beginRecording(SkScalar width, SkScalar height) {
- uint32_t record_flags = 0;
- canvas_.emplace(
- recorder_.beginRecording(width, height, nullptr, record_flags));
- return getRecordingCanvas();
+ // 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));
}
// Only valid between between and finish recording.
- ALWAYS_INLINE PaintCanvas* getRecordingCanvas() {
+ ALWAYS_INLINE RecordPaintCanvas* getRecordingCanvas() {
return canvas_.has_value() ? &canvas_.value() : nullptr;
}
- ALWAYS_INLINE sk_sp<PaintRecord> finishRecordingAsPicture() {
- sk_sp<SkPicture> picture = recorder_.finishRecordingAsPicture();
- // Some users (e.g. printing) use the existence of the recording canvas
- // to know if recording is finished, so reset it here.
- canvas_.reset();
- return sk_ref_sp(static_cast<PaintRecord*>(picture.get()));
- }
+ sk_sp<PaintRecord> finishRecordingAsPicture();
private:
- SkPictureRecorder recorder_;
- base::Optional<SkiaPaintCanvas> canvas_;
+ sk_sp<PaintOpBuffer> buffer_;
+ base::Optional<RecordPaintCanvas> canvas_;
DISALLOW_COPY_AND_ASSIGN(PaintRecorder);
};
diff --git a/chromium/cc/paint/paint_shader.h b/chromium/cc/paint/paint_shader.h
index 6afdaa650de..019174443bb 100644
--- a/chromium/cc/paint/paint_shader.h
+++ b/chromium/cc/paint/paint_shader.h
@@ -24,12 +24,12 @@ inline sk_sp<PaintShader> MakePaintShaderImage(sk_sp<const SkImage> image,
}
inline sk_sp<PaintShader> MakePaintShaderRecord(sk_sp<PaintRecord> record,
+ const SkRect& tile,
SkShader::TileMode tx,
SkShader::TileMode ty,
- const SkMatrix* local_matrix,
- const SkRect* tile) {
- return SkShader::MakePictureShader(ToSkPicture(record), tx, ty, local_matrix,
- tile);
+ const SkMatrix* local_matrix) {
+ return SkShader::MakePictureShader(ToSkPicture(record, tile), tx, ty,
+ local_matrix, nullptr);
}
} // namespace cc
diff --git a/chromium/cc/paint/record_paint_canvas.cc b/chromium/cc/paint/record_paint_canvas.cc
new file mode 100644
index 00000000000..a635474a372
--- /dev/null
+++ b/chromium/cc/paint/record_paint_canvas.cc
@@ -0,0 +1,372 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/paint/record_paint_canvas.h"
+
+#include "base/memory/ptr_util.h"
+#include "cc/paint/display_item_list.h"
+#include "cc/paint/paint_op_buffer.h"
+#include "cc/paint/paint_record.h"
+#include "cc/paint/paint_recorder.h"
+#include "third_party/skia/include/core/SkAnnotation.h"
+#include "third_party/skia/include/core/SkMetaData.h"
+#include "third_party/skia/include/utils/SkNWayCanvas.h"
+
+namespace cc {
+
+RecordPaintCanvas::RecordPaintCanvas(PaintOpBuffer* buffer,
+ const SkRect& bounds)
+ : buffer_(buffer), recording_bounds_(bounds) {
+ DCHECK(buffer_);
+}
+
+RecordPaintCanvas::~RecordPaintCanvas() = default;
+
+SkMetaData& RecordPaintCanvas::getMetaData() {
+ // This could just be SkMetaData owned by RecordPaintCanvas, but since
+ // SkCanvas already has one, we might as well use it directly.
+ return GetCanvas()->getMetaData();
+}
+
+SkImageInfo RecordPaintCanvas::imageInfo() const {
+ return GetCanvas()->imageInfo();
+}
+
+void RecordPaintCanvas::flush() {
+ // This is a noop when recording.
+}
+
+int RecordPaintCanvas::save() {
+ buffer_->push<SaveOp>();
+ return GetCanvas()->save();
+}
+
+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.
+ buffer_->push<SaveLayerOp>(bounds, flags);
+ const SkPaint& paint = ToSkPaint(*flags);
+ return GetCanvas()->saveLayer(bounds, &paint);
+ }
+ buffer_->push<SaveLayerOp>(bounds, flags);
+ return GetCanvas()->saveLayer(bounds, nullptr);
+}
+
+int RecordPaintCanvas::saveLayerAlpha(const SkRect* bounds, uint8_t alpha) {
+ buffer_->push<SaveLayerAlphaOp>(bounds, alpha);
+ return GetCanvas()->saveLayerAlpha(bounds, alpha);
+}
+
+void RecordPaintCanvas::restore() {
+ buffer_->push<RestoreOp>();
+ GetCanvas()->restore();
+}
+
+int RecordPaintCanvas::getSaveCount() const {
+ return GetCanvas()->getSaveCount();
+}
+
+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;
+ DCHECK_GE(diff, 0);
+ for (int i = 0; i < diff; ++i)
+ restore();
+}
+
+void RecordPaintCanvas::translate(SkScalar dx, SkScalar dy) {
+ buffer_->push<TranslateOp>(dx, dy);
+ GetCanvas()->translate(dx, dy);
+}
+
+void RecordPaintCanvas::scale(SkScalar sx, SkScalar sy) {
+ buffer_->push<ScaleOp>(sx, sy);
+ GetCanvas()->scale(sx, sy);
+}
+
+void RecordPaintCanvas::rotate(SkScalar degrees) {
+ buffer_->push<RotateOp>(degrees);
+ GetCanvas()->rotate(degrees);
+}
+
+void RecordPaintCanvas::concat(const SkMatrix& matrix) {
+ buffer_->push<ConcatOp>(matrix);
+ GetCanvas()->concat(matrix);
+}
+
+void RecordPaintCanvas::setMatrix(const SkMatrix& matrix) {
+ buffer_->push<SetMatrixOp>(matrix);
+ GetCanvas()->setMatrix(matrix);
+}
+
+void RecordPaintCanvas::clipRect(const SkRect& rect,
+ SkClipOp op,
+ bool antialias) {
+ buffer_->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;
+ }
+ buffer_->push<ClipRRectOp>(rrect, op, antialias);
+ GetCanvas()->clipRRect(rrect, op, antialias);
+}
+
+void RecordPaintCanvas::clipPath(const SkPath& path,
+ SkClipOp op,
+ bool antialias) {
+ if (!path.isInverseFillType() &&
+ GetCanvas()->getTotalMatrix().rectStaysRect()) {
+ // TODO(enne): do these cases happen? should the caller know that this isn't
+ // a path?
+ SkRect rect;
+ if (path.isRect(&rect)) {
+ clipRect(rect, op, antialias);
+ return;
+ }
+ SkRRect rrect;
+ if (path.isOval(&rect)) {
+ rrect.setOval(rect);
+ clipRRect(rrect, op, antialias);
+ return;
+ }
+ if (path.isRRect(&rrect)) {
+ clipRRect(rrect, op, antialias);
+ return;
+ }
+ }
+
+ buffer_->push<ClipPathOp>(path, op, antialias);
+ GetCanvas()->clipPath(path, op, antialias);
+ return;
+}
+
+bool RecordPaintCanvas::quickReject(const SkRect& rect) const {
+ return GetCanvas()->quickReject(rect);
+}
+
+bool RecordPaintCanvas::quickReject(const SkPath& path) const {
+ return GetCanvas()->quickReject(path);
+}
+
+SkRect RecordPaintCanvas::getLocalClipBounds() const {
+ return GetCanvas()->getLocalClipBounds();
+}
+
+bool RecordPaintCanvas::getLocalClipBounds(SkRect* bounds) const {
+ return GetCanvas()->getLocalClipBounds(bounds);
+}
+
+SkIRect RecordPaintCanvas::getDeviceClipBounds() const {
+ return GetCanvas()->getDeviceClipBounds();
+}
+
+bool RecordPaintCanvas::getDeviceClipBounds(SkIRect* bounds) const {
+ return GetCanvas()->getDeviceClipBounds(bounds);
+}
+
+void RecordPaintCanvas::drawColor(SkColor color, SkBlendMode mode) {
+ buffer_->push<DrawColorOp>(color, mode);
+}
+
+void RecordPaintCanvas::clear(SkColor color) {
+ buffer_->push<DrawColorOp>(color, SkBlendMode::kSrc);
+}
+
+void RecordPaintCanvas::drawLine(SkScalar x0,
+ SkScalar y0,
+ SkScalar x1,
+ SkScalar y1,
+ const PaintFlags& flags) {
+ buffer_->push<DrawLineOp>(x0, y0, x1, y1, flags);
+}
+
+void RecordPaintCanvas::drawRect(const SkRect& rect, const PaintFlags& flags) {
+ buffer_->push<DrawRectOp>(rect, flags);
+}
+
+void RecordPaintCanvas::drawIRect(const SkIRect& rect,
+ const PaintFlags& flags) {
+ buffer_->push<DrawIRectOp>(rect, flags);
+}
+
+void RecordPaintCanvas::drawOval(const SkRect& oval, const PaintFlags& flags) {
+ buffer_->push<DrawOvalOp>(oval, flags);
+}
+
+void RecordPaintCanvas::drawRRect(const SkRRect& rrect,
+ const PaintFlags& flags) {
+ buffer_->push<DrawRRectOp>(rrect, flags);
+}
+
+void RecordPaintCanvas::drawDRRect(const SkRRect& outer,
+ const SkRRect& inner,
+ const PaintFlags& flags) {
+ if (outer.isEmpty())
+ return;
+ if (inner.isEmpty()) {
+ drawRRect(outer, flags);
+ return;
+ }
+ buffer_->push<DrawDRRectOp>(outer, inner, flags);
+}
+
+void RecordPaintCanvas::drawCircle(SkScalar cx,
+ SkScalar cy,
+ SkScalar radius,
+ const PaintFlags& flags) {
+ buffer_->push<DrawCircleOp>(cx, cy, radius, flags);
+}
+
+void RecordPaintCanvas::drawArc(const SkRect& oval,
+ SkScalar start_angle,
+ SkScalar sweep_angle,
+ bool use_center,
+ const PaintFlags& flags) {
+ buffer_->push<DrawArcOp>(oval, start_angle, sweep_angle, use_center, flags);
+}
+
+void RecordPaintCanvas::drawRoundRect(const SkRect& rect,
+ SkScalar rx,
+ SkScalar ry,
+ const PaintFlags& flags) {
+ // TODO(enne): move this into base class?
+ if (rx > 0 && ry > 0) {
+ SkRRect rrect;
+ rrect.setRectXY(rect, rx, ry);
+ drawRRect(rrect, flags);
+ } else {
+ drawRect(rect, flags);
+ }
+}
+
+void RecordPaintCanvas::drawPath(const SkPath& path, const PaintFlags& flags) {
+ buffer_->push<DrawPathOp>(path, flags);
+}
+
+void RecordPaintCanvas::drawImage(const PaintImage& image,
+ SkScalar left,
+ SkScalar top,
+ const PaintFlags* flags) {
+ buffer_->push<DrawImageOp>(image, left, top, flags);
+}
+
+void RecordPaintCanvas::drawImageRect(const PaintImage& image,
+ const SkRect& src,
+ const SkRect& dst,
+ const PaintFlags* flags,
+ SrcRectConstraint constraint) {
+ buffer_->push<DrawImageRectOp>(image, src, dst, flags, constraint);
+}
+
+void RecordPaintCanvas::drawBitmap(const SkBitmap& bitmap,
+ SkScalar left,
+ SkScalar top,
+ const PaintFlags* flags) {
+ // TODO(enne): Move into base class?
+ if (bitmap.drawsNothing())
+ return;
+ drawImage(
+ PaintImage(PaintImage::kNonLazyStableId, SkImage::MakeFromBitmap(bitmap),
+ PaintImage::AnimationType::UNKNOWN,
+ PaintImage::CompletionState::UNKNOWN),
+ left, top, flags);
+}
+
+void RecordPaintCanvas::drawText(const void* text,
+ size_t byte_length,
+ SkScalar x,
+ SkScalar y,
+ const PaintFlags& flags) {
+ buffer_->push_with_data<DrawTextOp>(text, byte_length, x, y, flags);
+}
+
+void RecordPaintCanvas::drawPosText(const void* text,
+ size_t byte_length,
+ const SkPoint pos[],
+ const PaintFlags& flags) {
+ size_t count = ToSkPaint(flags).countText(text, byte_length);
+ buffer_->push_with_array<DrawPosTextOp>(text, byte_length, pos, count, flags);
+}
+
+void RecordPaintCanvas::drawTextBlob(sk_sp<SkTextBlob> blob,
+ SkScalar x,
+ SkScalar y,
+ const PaintFlags& flags) {
+ buffer_->push<DrawTextBlobOp>(blob, x, y, flags);
+}
+
+void RecordPaintCanvas::drawDisplayItemList(
+ scoped_refptr<DisplayItemList> list) {
+ buffer_->push<DrawDisplayItemListOp>(list);
+}
+
+void RecordPaintCanvas::drawPicture(sk_sp<const PaintRecord> record) {
+ // TODO(enne): If this is small, maybe flatten it?
+ buffer_->push<DrawRecordOp>(record);
+}
+
+bool RecordPaintCanvas::isClipEmpty() const {
+ return GetCanvas()->isClipEmpty();
+}
+
+bool RecordPaintCanvas::isClipRect() const {
+ return GetCanvas()->isClipRect();
+}
+
+const SkMatrix& RecordPaintCanvas::getTotalMatrix() const {
+ return GetCanvas()->getTotalMatrix();
+}
+
+void RecordPaintCanvas::Annotate(AnnotationType type,
+ const SkRect& rect,
+ sk_sp<SkData> data) {
+ buffer_->push<AnnotateOp>(type, rect, data);
+}
+
+const SkNoDrawCanvas* RecordPaintCanvas::GetCanvas() const {
+ return const_cast<RecordPaintCanvas*>(this)->GetCanvas();
+}
+
+SkNoDrawCanvas* RecordPaintCanvas::GetCanvas() {
+ if (canvas_)
+ return &*canvas_;
+
+ // Size the canvas to be large enough to contain the |recording_bounds|, which
+ // may not be positioned at th origin.
+ SkIRect enclosing_rect = recording_bounds_.roundOut();
+ canvas_.emplace(enclosing_rect.right(), enclosing_rect.bottom());
+
+ // 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_;
+}
+
+} // namespace cc
diff --git a/chromium/cc/paint/record_paint_canvas.h b/chromium/cc/paint/record_paint_canvas.h
new file mode 100644
index 00000000000..4eb391d747a
--- /dev/null
+++ b/chromium/cc/paint/record_paint_canvas.h
@@ -0,0 +1,158 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_PAINT_RECORD_PAINT_CANVAS_H_
+#define CC_PAINT_RECORD_PAINT_CANVAS_H_
+
+#include <memory>
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/optional.h"
+#include "build/build_config.h"
+#include "cc/paint/paint_canvas.h"
+#include "cc/paint/paint_flags.h"
+#include "cc/paint/paint_record.h"
+#include "third_party/skia/include/utils/SkNoDrawCanvas.h"
+
+namespace cc {
+
+class PaintOpBuffer;
+class PaintFlags;
+
+class CC_PAINT_EXPORT RecordPaintCanvas final : public PaintCanvas {
+ public:
+ explicit RecordPaintCanvas(PaintOpBuffer* buffer, const SkRect& bounds);
+ ~RecordPaintCanvas() override;
+
+ SkMetaData& getMetaData() override;
+ SkImageInfo imageInfo() const override;
+
+ void flush() override;
+
+ int save() override;
+ int saveLayer(const SkRect* bounds, const PaintFlags* flags) override;
+ int saveLayerAlpha(const SkRect* bounds, uint8_t alpha) override;
+
+ void restore() override;
+ int getSaveCount() const override;
+ 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;
+ void concat(const SkMatrix& matrix) override;
+ void setMatrix(const SkMatrix& matrix) override;
+
+ void clipRect(const SkRect& rect, SkClipOp op, bool antialias) override;
+ void clipRRect(const SkRRect& rrect, SkClipOp op, bool antialias) override;
+ void clipPath(const SkPath& path, SkClipOp op, bool antialias) override;
+ bool quickReject(const SkRect& rect) const override;
+ bool quickReject(const SkPath& path) const override;
+ SkRect getLocalClipBounds() const override;
+ bool getLocalClipBounds(SkRect* bounds) const override;
+ SkIRect getDeviceClipBounds() const override;
+ bool getDeviceClipBounds(SkIRect* bounds) const override;
+ void drawColor(SkColor color, SkBlendMode mode) override;
+ void clear(SkColor color) override;
+
+ void drawLine(SkScalar x0,
+ SkScalar y0,
+ SkScalar x1,
+ SkScalar y1,
+ const PaintFlags& flags) override;
+ void drawRect(const SkRect& rect, const PaintFlags& flags) override;
+ void drawIRect(const SkIRect& rect, const PaintFlags& flags) override;
+ void drawOval(const SkRect& oval, const PaintFlags& flags) override;
+ void drawRRect(const SkRRect& rrect, const PaintFlags& flags) override;
+ void drawDRRect(const SkRRect& outer,
+ const SkRRect& inner,
+ const PaintFlags& flags) override;
+ void drawCircle(SkScalar cx,
+ SkScalar cy,
+ SkScalar radius,
+ const PaintFlags& flags) override;
+ void drawArc(const SkRect& oval,
+ SkScalar start_angle,
+ SkScalar sweep_angle,
+ bool use_center,
+ const PaintFlags& flags) override;
+ void drawRoundRect(const SkRect& rect,
+ SkScalar rx,
+ SkScalar ry,
+ const PaintFlags& flags) override;
+ void drawPath(const SkPath& path, const PaintFlags& flags) override;
+ void drawImage(const PaintImage& image,
+ SkScalar left,
+ SkScalar top,
+ const PaintFlags* flags) override;
+ void drawImageRect(const PaintImage& image,
+ const SkRect& src,
+ const SkRect& dst,
+ const PaintFlags* flags,
+ SrcRectConstraint constraint) override;
+ void drawBitmap(const SkBitmap& bitmap,
+ SkScalar left,
+ SkScalar top,
+ const PaintFlags* flags) override;
+
+ void drawText(const void* text,
+ size_t byte_length,
+ SkScalar x,
+ SkScalar y,
+ const PaintFlags& flags) override;
+ void drawPosText(const void* text,
+ size_t byte_length,
+ const SkPoint pos[],
+ const PaintFlags& flags) override;
+ void drawTextBlob(sk_sp<SkTextBlob> blob,
+ SkScalar x,
+ SkScalar y,
+ const PaintFlags& flags) override;
+
+ void drawDisplayItemList(
+ scoped_refptr<DisplayItemList> display_item_list) override;
+
+ void drawPicture(sk_sp<const PaintRecord> record) override;
+
+ bool isClipEmpty() const override;
+ bool isClipRect() const override;
+ const SkMatrix& getTotalMatrix() const override;
+
+ void Annotate(AnnotationType type,
+ const SkRect& rect,
+ sk_sp<SkData> data) override;
+
+ // Don't shadow non-virtual helper functions.
+ using PaintCanvas::clipRect;
+ using PaintCanvas::clipRRect;
+ using PaintCanvas::clipPath;
+ using PaintCanvas::drawBitmap;
+ using PaintCanvas::drawColor;
+ using PaintCanvas::drawImage;
+ using PaintCanvas::drawPicture;
+
+ private:
+ const SkNoDrawCanvas* GetCanvas() const;
+ SkNoDrawCanvas* GetCanvas();
+
+ PaintOpBuffer* buffer_;
+
+ // 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 base::Optional<SkNoDrawCanvas> canvas_;
+ SkRect recording_bounds_;
+
+ DISALLOW_COPY_AND_ASSIGN(RecordPaintCanvas);
+};
+
+} // namespace cc
+
+#endif // CC_PAINT_RECORD_PAINT_CANVAS_H_
diff --git a/chromium/cc/paint/skia_paint_canvas.cc b/chromium/cc/paint/skia_paint_canvas.cc
index 94b0cfb7a30..8c69d875fb8 100644
--- a/chromium/cc/paint/skia_paint_canvas.cc
+++ b/chromium/cc/paint/skia_paint_canvas.cc
@@ -2,11 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "cc/paint/paint_canvas.h"
+#include "cc/paint/skia_paint_canvas.h"
#include "base/memory/ptr_util.h"
#include "cc/paint/display_item_list.h"
-#include "cc/paint/paint_record.h"
#include "cc/paint/paint_recorder.h"
#include "third_party/skia/include/core/SkAnnotation.h"
#include "third_party/skia/include/core/SkMetaData.h"
@@ -23,7 +22,6 @@ SkiaPaintCanvas::SkiaPaintCanvas(const SkBitmap& bitmap,
const SkSurfaceProps& props)
: canvas_(new SkCanvas(bitmap, props)), owned_(canvas_) {}
-SkiaPaintCanvas::SkiaPaintCanvas(SkiaPaintCanvas&& other) = default;
SkiaPaintCanvas::~SkiaPaintCanvas() = default;
SkMetaData& SkiaPaintCanvas::getMetaData() {
@@ -38,18 +36,6 @@ void SkiaPaintCanvas::flush() {
canvas_->flush();
}
-SkISize SkiaPaintCanvas::getBaseLayerSize() const {
- return canvas_->getBaseLayerSize();
-}
-
-bool SkiaPaintCanvas::writePixels(const SkImageInfo& info,
- const void* pixels,
- size_t row_bytes,
- int x,
- int y) {
- return canvas_->writePixels(info, pixels, row_bytes, x, y);
-}
-
int SkiaPaintCanvas::save() {
return canvas_->save();
}
@@ -58,7 +44,7 @@ int SkiaPaintCanvas::saveLayer(const SkRect* bounds, const PaintFlags* flags) {
return canvas_->saveLayer(bounds, ToSkPaint(flags));
}
-int SkiaPaintCanvas::saveLayerAlpha(const SkRect* bounds, U8CPU alpha) {
+int SkiaPaintCanvas::saveLayerAlpha(const SkRect* bounds, uint8_t alpha) {
return canvas_->saveLayerAlpha(bounds, alpha);
}
@@ -201,19 +187,19 @@ void SkiaPaintCanvas::drawPath(const SkPath& path, const PaintFlags& flags) {
canvas_->drawPath(path, ToSkPaint(flags));
}
-void SkiaPaintCanvas::drawImage(sk_sp<const SkImage> image,
+void SkiaPaintCanvas::drawImage(const PaintImage& image,
SkScalar left,
SkScalar top,
const PaintFlags* flags) {
- canvas_->drawImage(image.get(), left, top, ToSkPaint(flags));
+ canvas_->drawImage(image.sk_image().get(), left, top, ToSkPaint(flags));
}
-void SkiaPaintCanvas::drawImageRect(sk_sp<const SkImage> image,
+void SkiaPaintCanvas::drawImageRect(const PaintImage& image,
const SkRect& src,
const SkRect& dst,
const PaintFlags* flags,
SrcRectConstraint constraint) {
- canvas_->drawImageRect(image.get(), src, dst, ToSkPaint(flags),
+ canvas_->drawImageRect(image.sk_image().get(), src, dst, ToSkPaint(flags),
static_cast<SkCanvas::SrcRectConstraint>(constraint));
}
@@ -248,7 +234,7 @@ void SkiaPaintCanvas::drawTextBlob(sk_sp<SkTextBlob> blob,
void SkiaPaintCanvas::drawDisplayItemList(
scoped_refptr<DisplayItemList> display_item_list) {
- display_item_list->Raster(canvas_, nullptr);
+ display_item_list->Raster(canvas_);
}
void SkiaPaintCanvas::drawPicture(sk_sp<const PaintRecord> record) {
@@ -267,29 +253,6 @@ const SkMatrix& SkiaPaintCanvas::getTotalMatrix() const {
return canvas_->getTotalMatrix();
}
-void SkiaPaintCanvas::temporary_internal_describeTopLayer(
- SkMatrix* matrix,
- SkIRect* clip_bounds) {
- return canvas_->temporary_internal_describeTopLayer(matrix, clip_bounds);
-}
-
-void SkiaPaintCanvas::PlaybackPaintRecord(sk_sp<const PaintRecord> record) {
- record->playback(canvas_);
-}
-
-bool SkiaPaintCanvas::ToPixmap(SkPixmap* output) {
- SkImageInfo info;
- size_t row_bytes;
- void* pixels = canvas_->accessTopLayerPixels(&info, &row_bytes);
- if (!pixels) {
- output->reset();
- return false;
- }
-
- output->reset(info, pixels, row_bytes);
- return true;
-}
-
void SkiaPaintCanvas::Annotate(AnnotationType type,
const SkRect& rect,
sk_sp<SkData> data) {
diff --git a/chromium/cc/paint/skia_paint_canvas.h b/chromium/cc/paint/skia_paint_canvas.h
index 669ca9b3e0b..1fd313b53ab 100644
--- a/chromium/cc/paint/skia_paint_canvas.h
+++ b/chromium/cc/paint/skia_paint_canvas.h
@@ -28,25 +28,16 @@ class CC_PAINT_EXPORT SkiaPaintCanvas final : public PaintCanvas {
explicit SkiaPaintCanvas(SkCanvas* canvas);
explicit SkiaPaintCanvas(const SkBitmap& bitmap);
explicit SkiaPaintCanvas(const SkBitmap& bitmap, const SkSurfaceProps& props);
- explicit SkiaPaintCanvas(SkiaPaintCanvas&& other);
~SkiaPaintCanvas() override;
- SkiaPaintCanvas& operator=(SkiaPaintCanvas&& other) = default;
-
SkMetaData& getMetaData() override;
SkImageInfo imageInfo() const override;
void flush() override;
- SkISize getBaseLayerSize() const override;
- bool writePixels(const SkImageInfo& info,
- const void* pixels,
- size_t row_bytes,
- int x,
- int y) override;
int save() override;
int saveLayer(const SkRect* bounds, const PaintFlags* flags) override;
- int saveLayerAlpha(const SkRect* bounds, U8CPU alpha) override;
+ int saveLayerAlpha(const SkRect* bounds, uint8_t alpha) override;
void restore() override;
int getSaveCount() const override;
@@ -97,11 +88,11 @@ class CC_PAINT_EXPORT SkiaPaintCanvas final : public PaintCanvas {
SkScalar ry,
const PaintFlags& flags) override;
void drawPath(const SkPath& path, const PaintFlags& flags) override;
- void drawImage(sk_sp<const SkImage> image,
+ void drawImage(const PaintImage& image,
SkScalar left,
SkScalar top,
const PaintFlags* flags) override;
- void drawImageRect(sk_sp<const SkImage> image,
+ void drawImageRect(const PaintImage& image,
const SkRect& src,
const SkRect& dst,
const PaintFlags* flags,
@@ -134,16 +125,10 @@ class CC_PAINT_EXPORT SkiaPaintCanvas final : public PaintCanvas {
bool isClipRect() const override;
const SkMatrix& getTotalMatrix() const override;
- void temporary_internal_describeTopLayer(SkMatrix* matrix,
- SkIRect* clip_bounds) override;
-
- bool ToPixmap(SkPixmap* output) override;
void Annotate(AnnotationType type,
const SkRect& rect,
sk_sp<SkData> data) override;
- void PlaybackPaintRecord(sk_sp<const PaintRecord> record) override;
-
// Don't shadow non-virtual helper functions.
using PaintCanvas::clipRect;
using PaintCanvas::clipRRect;
diff --git a/chromium/cc/paint/transform_display_item.cc b/chromium/cc/paint/transform_display_item.cc
index 6cc3e7f2d1e..54c034e8502 100644
--- a/chromium/cc/paint/transform_display_item.cc
+++ b/chromium/cc/paint/transform_display_item.cc
@@ -8,7 +8,11 @@ namespace cc {
TransformDisplayItem::TransformDisplayItem(const gfx::Transform& transform)
- : DisplayItem(TRANSFORM), transform(transform) {}
+ : DisplayItem(TRANSFORM), transform(transform) {
+ // The underlying SkMatrix in gfx::Transform is not thread-safe, unless
+ // getType() has been called.
+ this->transform.matrix().getType();
+}
TransformDisplayItem::~TransformDisplayItem() = default;
diff --git a/chromium/cc/paint/transform_display_item.h b/chromium/cc/paint/transform_display_item.h
index a75db2a4d87..50c2358d783 100644
--- a/chromium/cc/paint/transform_display_item.h
+++ b/chromium/cc/paint/transform_display_item.h
@@ -19,7 +19,7 @@ class CC_PAINT_EXPORT TransformDisplayItem : public DisplayItem {
~TransformDisplayItem() override;
size_t ExternalMemoryUsage() const { return 0; }
- int ApproximateOpCount() const { return 1; }
+ int OpCount() const { return 1; }
const gfx::Transform transform;
};
@@ -29,7 +29,7 @@ class CC_PAINT_EXPORT EndTransformDisplayItem : public DisplayItem {
EndTransformDisplayItem();
~EndTransformDisplayItem() override;
- int ApproximateOpCount() const { return 0; }
+ int OpCount() const { return 0; }
};
} // namespace cc
diff --git a/chromium/cc/quads/draw_polygon_unittest.cc b/chromium/cc/quads/draw_polygon_unittest.cc
index 5f9475360a5..6a5ff188adb 100644
--- a/chromium/cc/quads/draw_polygon_unittest.cc
+++ b/chromium/cc/quads/draw_polygon_unittest.cc
@@ -169,7 +169,7 @@ TEST(DrawPolygonConstructionTest, ManyVertexNormal) {
EXPECT_NORMAL(polygon_c, 0.0f, 0.0f, 1.0f);
CREATE_TEST_DRAW_FORWARD_POLYGON(polygon_d, vertices_d, 4);
- EXPECT_NORMAL(polygon_c, 0.0f, 0.0f, 1.0f);
+ EXPECT_NORMAL(polygon_d, 0.0f, 0.0f, 1.0f);
}
// A simple rect being transformed.
diff --git a/chromium/cc/quads/draw_quad.h b/chromium/cc/quads/draw_quad.h
index 5e46ea4d2f6..1b5775c2ec1 100644
--- a/chromium/cc/quads/draw_quad.h
+++ b/chromium/cc/quads/draw_quad.h
@@ -95,13 +95,13 @@ class CC_EXPORT DrawQuad {
// Is the right edge of this tile aligned with the originating layer's
// right edge?
bool IsRightEdge() const {
- return rect.right() == shared_quad_state->quad_layer_bounds.width();
+ return rect.right() == shared_quad_state->quad_layer_rect.right();
}
// Is the bottom edge of this tile aligned with the originating layer's
// bottom edge?
bool IsBottomEdge() const {
- return rect.bottom() == shared_quad_state->quad_layer_bounds.height();
+ return rect.bottom() == shared_quad_state->quad_layer_rect.bottom();
}
// Is any edge of this tile aligned with the originating layer's
diff --git a/chromium/cc/quads/draw_quad_perftest.cc b/chromium/cc/quads/draw_quad_perftest.cc
index 5d6c4c2ab33..669da217eeb 100644
--- a/chromium/cc/quads/draw_quad_perftest.cc
+++ b/chromium/cc/quads/draw_quad_perftest.cc
@@ -22,7 +22,7 @@ static const int kTimeCheckInterval = 10;
SharedQuadState* CreateSharedQuadState(RenderPass* render_pass) {
gfx::Transform quad_transform = gfx::Transform(1.0, 0.0, 0.5, 1.0, 0.5, 0.0);
- gfx::Size content_bounds(26, 28);
+ gfx::Rect content_rect(26, 28);
gfx::Rect visible_layer_rect(10, 12, 14, 16);
gfx::Rect clip_rect(19, 21, 23, 25);
bool is_clipped = false;
@@ -31,7 +31,7 @@ SharedQuadState* CreateSharedQuadState(RenderPass* render_pass) {
SkBlendMode blend_mode = SkBlendMode::kSrcOver;
SharedQuadState* state = render_pass->CreateAndAppendSharedQuadState();
- state->SetAll(quad_transform, content_bounds, visible_layer_rect, clip_rect,
+ state->SetAll(quad_transform, content_rect, visible_layer_rect, clip_rect,
is_clipped, opacity, blend_mode, sorting_context_id);
return state;
}
diff --git a/chromium/cc/quads/draw_quad_unittest.cc b/chromium/cc/quads/draw_quad_unittest.cc
index fce24b153d7..7f559054337 100644
--- a/chromium/cc/quads/draw_quad_unittest.cc
+++ b/chromium/cc/quads/draw_quad_unittest.cc
@@ -36,7 +36,7 @@ static constexpr FrameSinkId kArbitraryFrameSinkId(1, 1);
TEST(DrawQuadTest, CopySharedQuadState) {
gfx::Transform quad_transform = gfx::Transform(1.0, 0.0, 0.5, 1.0, 0.5, 0.0);
- gfx::Size layer_bounds(26, 28);
+ gfx::Rect layer_rect(26, 28);
gfx::Rect visible_layer_rect(10, 12, 14, 16);
gfx::Rect clip_rect(19, 21, 23, 25);
bool is_clipped = true;
@@ -45,7 +45,7 @@ TEST(DrawQuadTest, CopySharedQuadState) {
int sorting_context_id = 65536;
std::unique_ptr<SharedQuadState> state(new SharedQuadState);
- state->SetAll(quad_transform, layer_bounds, visible_layer_rect, clip_rect,
+ state->SetAll(quad_transform, layer_rect, visible_layer_rect, clip_rect,
is_clipped, opacity, blend_mode, sorting_context_id);
std::unique_ptr<SharedQuadState> copy(new SharedQuadState(*state));
@@ -59,7 +59,7 @@ TEST(DrawQuadTest, CopySharedQuadState) {
SharedQuadState* CreateSharedQuadState(RenderPass* render_pass) {
gfx::Transform quad_transform = gfx::Transform(1.0, 0.0, 0.5, 1.0, 0.5, 0.0);
- gfx::Size layer_bounds(26, 28);
+ gfx::Rect layer_rect(26, 28);
gfx::Rect visible_layer_rect(10, 12, 14, 16);
gfx::Rect clip_rect(19, 21, 23, 25);
bool is_clipped = false;
@@ -68,7 +68,7 @@ SharedQuadState* CreateSharedQuadState(RenderPass* render_pass) {
SkBlendMode blend_mode = SkBlendMode::kSrcOver;
SharedQuadState* state = render_pass->CreateAndAppendSharedQuadState();
- state->SetAll(quad_transform, layer_bounds, visible_layer_rect, clip_rect,
+ state->SetAll(quad_transform, layer_rect, visible_layer_rect, clip_rect,
is_clipped, opacity, blend_mode, sorting_context_id);
return state;
}
diff --git a/chromium/cc/quads/largest_draw_quad.cc b/chromium/cc/quads/largest_draw_quad.cc
index 68221da17a9..de99f54dc7f 100644
--- a/chromium/cc/quads/largest_draw_quad.cc
+++ b/chromium/cc/quads/largest_draw_quad.cc
@@ -19,28 +19,53 @@
#include "cc/quads/yuv_video_draw_quad.h"
namespace {
+
template <typename...>
struct MaxSize {};
template <class T, class... Args>
struct MaxSize<T, Args...> {
- static const size_t value = sizeof(T) > MaxSize<Args...>::value
- ? sizeof(T)
- : MaxSize<Args...>::value;
+ static constexpr size_t value = sizeof(T) > MaxSize<Args...>::value
+ ? sizeof(T)
+ : MaxSize<Args...>::value;
};
template <>
struct MaxSize<> {
- static const size_t value = 0;
+ static constexpr size_t value = 0;
+};
+
+constexpr size_t kLargestDrawQuadSize = MaxSize<cc::DebugBorderDrawQuad,
+ cc::PictureDrawQuad,
+ cc::RenderPassDrawQuad,
+ cc::SolidColorDrawQuad,
+ cc::StreamVideoDrawQuad,
+ cc::SurfaceDrawQuad,
+ cc::TextureDrawQuad,
+ cc::TileDrawQuad,
+ cc::YUVVideoDrawQuad>::value;
+
+template <typename...>
+struct MaxAlign {};
+template <class T, class... Args>
+struct MaxAlign<T, Args...> {
+ static constexpr size_t value = ALIGNOF(T) > MaxAlign<Args...>::value
+ ? ALIGNOF(T)
+ : MaxAlign<Args...>::value;
+};
+template <>
+struct MaxAlign<> {
+ static constexpr size_t value = 0;
};
-const size_t kLargestDrawQuadSize = MaxSize<cc::DebugBorderDrawQuad,
- cc::PictureDrawQuad,
- cc::RenderPassDrawQuad,
- cc::SolidColorDrawQuad,
- cc::StreamVideoDrawQuad,
- cc::SurfaceDrawQuad,
- cc::TextureDrawQuad,
- cc::TileDrawQuad,
- cc::YUVVideoDrawQuad>::value;
+constexpr size_t kLargestDrawQuadAlignment =
+ MaxAlign<cc::DebugBorderDrawQuad,
+ cc::PictureDrawQuad,
+ cc::RenderPassDrawQuad,
+ cc::SolidColorDrawQuad,
+ cc::StreamVideoDrawQuad,
+ cc::SurfaceDrawQuad,
+ cc::TextureDrawQuad,
+ cc::TileDrawQuad,
+ cc::YUVVideoDrawQuad>::value;
} // namespace
@@ -50,4 +75,8 @@ size_t LargestDrawQuadSize() {
return kLargestDrawQuadSize;
}
+size_t LargestDrawQuadAlignment() {
+ return kLargestDrawQuadAlignment;
+}
+
} // namespace cc
diff --git a/chromium/cc/quads/largest_draw_quad.h b/chromium/cc/quads/largest_draw_quad.h
index aefbd5ecee4..9069a3325eb 100644
--- a/chromium/cc/quads/largest_draw_quad.h
+++ b/chromium/cc/quads/largest_draw_quad.h
@@ -12,6 +12,7 @@
namespace cc {
CC_EXPORT size_t LargestDrawQuadSize();
+CC_EXPORT size_t LargestDrawQuadAlignment();
} // namespace cc
diff --git a/chromium/cc/quads/render_pass.cc b/chromium/cc/quads/render_pass.cc
index 3ad5fb0cf83..de49a226a22 100644
--- a/chromium/cc/quads/render_pass.cc
+++ b/chromium/cc/quads/render_pass.cc
@@ -37,12 +37,14 @@ const size_t kDefaultNumQuadsToReserve = 128;
namespace cc {
QuadList::QuadList()
- : ListContainer<DrawQuad>(LargestDrawQuadSize(),
+ : ListContainer<DrawQuad>(LargestDrawQuadAlignment(),
+ LargestDrawQuadSize(),
kDefaultNumSharedQuadStatesToReserve) {}
QuadList::QuadList(size_t default_size_to_reserve)
- : ListContainer<DrawQuad>(LargestDrawQuadSize(), default_size_to_reserve) {
-}
+ : ListContainer<DrawQuad>(LargestDrawQuadAlignment(),
+ LargestDrawQuadSize(),
+ default_size_to_reserve) {}
std::unique_ptr<RenderPass> RenderPass::Create() {
return base::WrapUnique(new RenderPass());
@@ -61,7 +63,8 @@ std::unique_ptr<RenderPass> RenderPass::Create(
RenderPass::RenderPass()
: quad_list(kDefaultNumQuadsToReserve),
- shared_quad_state_list(sizeof(SharedQuadState),
+ shared_quad_state_list(ALIGNOF(SharedQuadState),
+ sizeof(SharedQuadState),
kDefaultNumSharedQuadStatesToReserve) {}
// Each layer usually produces one shared quad state, so the number of layers
@@ -69,16 +72,17 @@ RenderPass::RenderPass()
RenderPass::RenderPass(size_t num_layers)
: has_transparent_background(true),
quad_list(kDefaultNumQuadsToReserve),
- shared_quad_state_list(sizeof(SharedQuadState), num_layers) {
-}
+ shared_quad_state_list(ALIGNOF(SharedQuadState),
+ sizeof(SharedQuadState),
+ num_layers) {}
RenderPass::RenderPass(size_t shared_quad_state_list_size,
size_t quad_list_size)
: has_transparent_background(true),
quad_list(quad_list_size),
- shared_quad_state_list(sizeof(SharedQuadState),
- shared_quad_state_list_size) {
-}
+ shared_quad_state_list(ALIGNOF(SharedQuadState),
+ sizeof(SharedQuadState),
+ shared_quad_state_list_size) {}
RenderPass::~RenderPass() {
TRACE_EVENT_OBJECT_DELETED_WITH_ID(
diff --git a/chromium/cc/quads/render_pass.h b/chromium/cc/quads/render_pass.h
index fbb43237b5a..0ad8debc892 100644
--- a/chromium/cc/quads/render_pass.h
+++ b/chromium/cc/quads/render_pass.h
@@ -7,7 +7,6 @@
#include <stddef.h>
-#include <unordered_map>
#include <utility>
#include <vector>
@@ -153,10 +152,6 @@ class CC_EXPORT RenderPass {
using RenderPassList = std::vector<std::unique_ptr<RenderPass>>;
-// List of pairs of render pass id and filter, sorted by render pass id so that
-// it can be searched using std::lower_bound.
-using RenderPassFilterList = std::vector<std::pair<int, FilterOperations*>>;
-
} // namespace cc
#endif // CC_QUADS_RENDER_PASS_H_
diff --git a/chromium/cc/quads/render_pass_unittest.cc b/chromium/cc/quads/render_pass_unittest.cc
index 9fced653723..485bf71946c 100644
--- a/chromium/cc/quads/render_pass_unittest.cc
+++ b/chromium/cc/quads/render_pass_unittest.cc
@@ -61,8 +61,8 @@ static void CompareRenderPassLists(const RenderPassList& expected_list,
exp_iter != expected->quad_list.cend();
++exp_iter, ++act_iter) {
EXPECT_EQ(exp_iter->rect.ToString(), act_iter->rect.ToString());
- EXPECT_EQ(exp_iter->shared_quad_state->quad_layer_bounds.ToString(),
- act_iter->shared_quad_state->quad_layer_bounds.ToString());
+ EXPECT_EQ(exp_iter->shared_quad_state->quad_layer_rect.ToString(),
+ act_iter->shared_quad_state->quad_layer_rect.ToString());
}
}
}
@@ -87,7 +87,7 @@ TEST(RenderPassTest, CopyShouldBeIdenticalExceptIdAndQuads) {
// Stick a quad in the pass, this should not get copied.
SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState();
- shared_state->SetAll(gfx::Transform(), gfx::Size(), gfx::Rect(), gfx::Rect(),
+ shared_state->SetAll(gfx::Transform(), gfx::Rect(), gfx::Rect(), gfx::Rect(),
false, 1, SkBlendMode::kSrcOver, 0);
SolidColorDrawQuad* color_quad =
@@ -135,7 +135,7 @@ TEST(RenderPassTest, CopyAllShouldBeIdentical) {
// Two quads using one shared state.
SharedQuadState* shared_state1 = pass->CreateAndAppendSharedQuadState();
- shared_state1->SetAll(gfx::Transform(), gfx::Size(1, 1), gfx::Rect(),
+ shared_state1->SetAll(gfx::Transform(), gfx::Rect(0, 0, 1, 1), gfx::Rect(),
gfx::Rect(), false, 1, SkBlendMode::kSrcOver, 0);
SolidColorDrawQuad* color_quad1 =
@@ -152,7 +152,7 @@ TEST(RenderPassTest, CopyAllShouldBeIdentical) {
// And two quads using another shared state.
SharedQuadState* shared_state2 = pass->CreateAndAppendSharedQuadState();
- shared_state2->SetAll(gfx::Transform(), gfx::Size(2, 2), gfx::Rect(),
+ shared_state2->SetAll(gfx::Transform(), gfx::Rect(0, 0, 2, 2), gfx::Rect(),
gfx::Rect(), false, 1, SkBlendMode::kSrcOver, 0);
SolidColorDrawQuad* color_quad3 =
@@ -188,8 +188,9 @@ TEST(RenderPassTest, CopyAllShouldBeIdentical) {
SharedQuadState* contrib_shared_state =
contrib->CreateAndAppendSharedQuadState();
- contrib_shared_state->SetAll(gfx::Transform(), gfx::Size(2, 2), gfx::Rect(),
- gfx::Rect(), false, 1, SkBlendMode::kSrcOver, 0);
+ contrib_shared_state->SetAll(gfx::Transform(), gfx::Rect(0, 0, 2, 2),
+ gfx::Rect(), gfx::Rect(), false, 1,
+ SkBlendMode::kSrcOver, 0);
SolidColorDrawQuad* contrib_quad =
contrib->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
@@ -235,7 +236,7 @@ TEST(RenderPassTest, CopyAllWithCulledQuads) {
// A shared state with a quad.
SharedQuadState* shared_state1 = pass->CreateAndAppendSharedQuadState();
- shared_state1->SetAll(gfx::Transform(), gfx::Size(1, 1), gfx::Rect(),
+ shared_state1->SetAll(gfx::Transform(), gfx::Rect(0, 0, 1, 1), gfx::Rect(),
gfx::Rect(), false, 1, SkBlendMode::kSrcOver, 0);
SolidColorDrawQuad* color_quad1 =
@@ -246,17 +247,17 @@ TEST(RenderPassTest, CopyAllWithCulledQuads) {
// A shared state with no quads, they were culled.
SharedQuadState* shared_state2 = pass->CreateAndAppendSharedQuadState();
- shared_state2->SetAll(gfx::Transform(), gfx::Size(2, 2), gfx::Rect(),
+ shared_state2->SetAll(gfx::Transform(), gfx::Rect(0, 0, 2, 2), gfx::Rect(),
gfx::Rect(), false, 1, SkBlendMode::kSrcOver, 0);
// A second shared state with no quads.
SharedQuadState* shared_state3 = pass->CreateAndAppendSharedQuadState();
- shared_state3->SetAll(gfx::Transform(), gfx::Size(2, 2), gfx::Rect(),
+ shared_state3->SetAll(gfx::Transform(), gfx::Rect(0, 0, 2, 2), gfx::Rect(),
gfx::Rect(), false, 1, SkBlendMode::kSrcOver, 0);
// A last shared state with a quad again.
SharedQuadState* shared_state4 = pass->CreateAndAppendSharedQuadState();
- shared_state4->SetAll(gfx::Transform(), gfx::Size(2, 2), gfx::Rect(),
+ shared_state4->SetAll(gfx::Transform(), gfx::Rect(0, 0, 2, 2), gfx::Rect(),
gfx::Rect(), false, 1, SkBlendMode::kSrcOver, 0);
SolidColorDrawQuad* color_quad2 =
diff --git a/chromium/cc/quads/shared_quad_state.cc b/chromium/cc/quads/shared_quad_state.cc
index de2d75e722c..bc6e15e9ee6 100644
--- a/chromium/cc/quads/shared_quad_state.cc
+++ b/chromium/cc/quads/shared_quad_state.cc
@@ -28,7 +28,7 @@ SharedQuadState::~SharedQuadState() {
}
void SharedQuadState::SetAll(const gfx::Transform& quad_to_target_transform,
- const gfx::Size& quad_layer_bounds,
+ const gfx::Rect& quad_layer_rect,
const gfx::Rect& visible_quad_layer_rect,
const gfx::Rect& clip_rect,
bool is_clipped,
@@ -36,7 +36,7 @@ void SharedQuadState::SetAll(const gfx::Transform& quad_to_target_transform,
SkBlendMode blend_mode,
int sorting_context_id) {
this->quad_to_target_transform = quad_to_target_transform;
- this->quad_layer_bounds = quad_layer_bounds;
+ this->quad_layer_rect = quad_layer_rect;
this->visible_quad_layer_rect = visible_quad_layer_rect;
this->clip_rect = clip_rect;
this->is_clipped = is_clipped;
@@ -47,7 +47,7 @@ void SharedQuadState::SetAll(const gfx::Transform& quad_to_target_transform,
void SharedQuadState::AsValueInto(base::trace_event::TracedValue* value) const {
MathUtil::AddToTracedValue("transform", quad_to_target_transform, value);
- MathUtil::AddToTracedValue("layer_content_bounds", quad_layer_bounds, value);
+ MathUtil::AddToTracedValue("layer_content_rect", quad_layer_rect, value);
MathUtil::AddToTracedValue("layer_visible_content_rect",
visible_quad_layer_rect, value);
diff --git a/chromium/cc/quads/shared_quad_state.h b/chromium/cc/quads/shared_quad_state.h
index f3758fb0d96..c496b7b35b2 100644
--- a/chromium/cc/quads/shared_quad_state.h
+++ b/chromium/cc/quads/shared_quad_state.h
@@ -32,7 +32,7 @@ class CC_EXPORT SharedQuadState {
~SharedQuadState();
void SetAll(const gfx::Transform& quad_to_target_transform,
- const gfx::Size& layer_bounds,
+ const gfx::Rect& layer_rect,
const gfx::Rect& visible_layer_rect,
const gfx::Rect& clip_rect,
bool is_clipped,
@@ -43,8 +43,8 @@ class CC_EXPORT SharedQuadState {
// Transforms quad rects into the target content space.
gfx::Transform quad_to_target_transform;
- // The size of the quads' originating layer in the space of the quad rects.
- gfx::Size quad_layer_bounds;
+ // The rect of the quads' originating layer in the space of the quad rects.
+ gfx::Rect quad_layer_rect;
// The size of the visible area in the quads' originating layer, in the space
// of the quad rects.
gfx::Rect visible_quad_layer_rect;
diff --git a/chromium/cc/raster/bitmap_raster_buffer_provider.cc b/chromium/cc/raster/bitmap_raster_buffer_provider.cc
index 470e6e03354..b69531a3ea3 100644
--- a/chromium/cc/raster/bitmap_raster_buffer_provider.cc
+++ b/chromium/cc/raster/bitmap_raster_buffer_provider.cc
@@ -98,6 +98,8 @@ void BitmapRasterBufferProvider::OrderingBarrier() {
// No need to sync resources as this provider does not use GL context.
}
+void BitmapRasterBufferProvider::Flush() {}
+
ResourceFormat BitmapRasterBufferProvider::GetResourceFormat(
bool must_support_alpha) const {
return resource_provider_->best_texture_format();
diff --git a/chromium/cc/raster/bitmap_raster_buffer_provider.h b/chromium/cc/raster/bitmap_raster_buffer_provider.h
index d4e44e7a00d..4f1301365c3 100644
--- a/chromium/cc/raster/bitmap_raster_buffer_provider.h
+++ b/chromium/cc/raster/bitmap_raster_buffer_provider.h
@@ -34,6 +34,7 @@ class CC_EXPORT BitmapRasterBufferProvider : public RasterBufferProvider {
uint64_t previous_content_id) override;
void ReleaseBufferForRaster(std::unique_ptr<RasterBuffer> buffer) override;
void OrderingBarrier() override;
+ void Flush() override;
ResourceFormat GetResourceFormat(bool must_support_alpha) const override;
bool IsResourceSwizzleRequired(bool must_support_alpha) const override;
bool CanPartialRasterIntoProvidedResource() const override;
diff --git a/chromium/cc/raster/gpu_raster_buffer_provider.cc b/chromium/cc/raster/gpu_raster_buffer_provider.cc
index de489ff8fde..1f2e8802e7d 100644
--- a/chromium/cc/raster/gpu_raster_buffer_provider.cc
+++ b/chromium/cc/raster/gpu_raster_buffer_provider.cc
@@ -175,6 +175,16 @@ void GpuRasterBufferProvider::OrderingBarrier() {
pending_raster_buffers_.clear();
}
+void GpuRasterBufferProvider::Flush() {
+ if (async_worker_context_enabled_) {
+ int32_t worker_stream_id =
+ worker_context_provider_->ContextSupport()->GetStreamId();
+
+ compositor_context_provider_->ContextSupport()
+ ->FlushOrderingBarrierOnStream(worker_stream_id);
+ }
+}
+
ResourceFormat GpuRasterBufferProvider::GetResourceFormat(
bool must_support_alpha) const {
if (resource_provider_->IsRenderBufferFormatSupported(
diff --git a/chromium/cc/raster/gpu_raster_buffer_provider.h b/chromium/cc/raster/gpu_raster_buffer_provider.h
index 0777db294c3..d699795e8b2 100644
--- a/chromium/cc/raster/gpu_raster_buffer_provider.h
+++ b/chromium/cc/raster/gpu_raster_buffer_provider.h
@@ -33,6 +33,7 @@ class CC_EXPORT GpuRasterBufferProvider : public RasterBufferProvider {
uint64_t previous_content_id) override;
void ReleaseBufferForRaster(std::unique_ptr<RasterBuffer> buffer) override;
void OrderingBarrier() override;
+ void Flush() override;
ResourceFormat GetResourceFormat(bool must_support_alpha) const override;
bool IsResourceSwizzleRequired(bool must_support_alpha) const override;
bool CanPartialRasterIntoProvidedResource() const override;
diff --git a/chromium/cc/raster/image_hijack_canvas.cc b/chromium/cc/raster/image_hijack_canvas.cc
index 150be23fa5d..a0a8c847835 100644
--- a/chromium/cc/raster/image_hijack_canvas.cc
+++ b/chromium/cc/raster/image_hijack_canvas.cc
@@ -22,13 +22,15 @@ SkIRect RoundOutRect(const SkRect& rect) {
class ScopedDecodedImageLock {
public:
ScopedDecodedImageLock(ImageDecodeCache* image_decode_cache,
- sk_sp<const SkImage> image,
+ sk_sp<SkImage> image,
const SkRect& src_rect,
const SkMatrix& matrix,
const SkPaint* paint,
const gfx::ColorSpace& target_color_space)
: image_decode_cache_(image_decode_cache),
- draw_image_(std::move(image),
+ // TODO(khushalsagar): Using the wrong id should not be necessary once
+ // the hijack canvas is eliminated.
+ draw_image_(PaintImage(PaintImage::kUnknownStableId, std::move(image)),
RoundOutRect(src_rect),
paint ? paint->getFilterQuality() : kNone_SkFilterQuality,
matrix,
@@ -133,7 +135,7 @@ const SkImage* GetImageInPaint(const SkPaint& paint) {
ImageHijackCanvas::ImageHijackCanvas(int width,
int height,
ImageDecodeCache* image_decode_cache,
- const ImageIdFlatSet* images_to_skip,
+ const SkImageIdFlatSet* images_to_skip,
const gfx::ColorSpace& target_color_space)
: SkNWayCanvas(width, height),
image_decode_cache_(image_decode_cache),
@@ -156,6 +158,11 @@ void ImageHijackCanvas::onDrawImage(const SkImage* image,
const SkPaint* paint) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"ImageHijackCanvas::onDrawImage");
+ SkRect rect = SkRect::MakeXYWH(x, y, SkIntToScalar(image->width()),
+ SkIntToScalar(image->height()));
+ if (QuickRejectDraw(rect, paint))
+ return;
+
if (!image->isLazyGenerated()) {
DCHECK(!ShouldSkipImage(image));
SkNWayCanvas::onDrawImage(image, x, y, paint);
@@ -168,7 +175,7 @@ void ImageHijackCanvas::onDrawImage(const SkImage* image,
SkMatrix ctm = getTotalMatrix();
ScopedDecodedImageLock scoped_lock(
- image_decode_cache_, sk_ref_sp(image),
+ image_decode_cache_, sk_ref_sp(const_cast<SkImage*>(image)),
SkRect::MakeIWH(image->width(), image->height()), ctm, paint,
target_color_space_);
const DecodedDrawImage& decoded_image = scoped_lock.decoded_image();
@@ -197,6 +204,9 @@ void ImageHijackCanvas::onDrawImageRect(const SkImage* image,
SrcRectConstraint constraint) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"ImageHijackCanvas::onDrawImageRect");
+ if (QuickRejectDraw(dst, paint))
+ return;
+
if (!image->isLazyGenerated()) {
DCHECK(!ShouldSkipImage(image));
SkNWayCanvas::onDrawImageRect(image, src, dst, paint, constraint);
@@ -215,7 +225,8 @@ void ImageHijackCanvas::onDrawImageRect(const SkImage* image,
matrix.setRectToRect(*src, dst, SkMatrix::kFill_ScaleToFit);
matrix.postConcat(getTotalMatrix());
- ScopedDecodedImageLock scoped_lock(image_decode_cache_, sk_ref_sp(image),
+ ScopedDecodedImageLock scoped_lock(image_decode_cache_,
+ sk_ref_sp(const_cast<SkImage*>(image)),
*src, matrix, paint, target_color_space_);
const DecodedDrawImage& decoded_image = scoped_lock.decoded_image();
if (!decoded_image.image())
@@ -240,6 +251,9 @@ void ImageHijackCanvas::onDrawImageRect(const SkImage* image,
void ImageHijackCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"ImageHijackCanvas::onDrawRect");
+ if (QuickRejectDraw(r, &paint))
+ return;
+
if (ShouldSkipImageInPaint(paint))
return;
@@ -255,6 +269,9 @@ void ImageHijackCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
void ImageHijackCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"ImageHijackCanvas::onDrawPath");
+ if (QuickRejectDraw(path.getBounds(), &paint))
+ return;
+
if (ShouldSkipImageInPaint(paint))
return;
@@ -270,6 +287,9 @@ void ImageHijackCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
void ImageHijackCanvas::onDrawOval(const SkRect& r, const SkPaint& paint) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"ImageHijackCanvas::onDrawOval");
+ if (QuickRejectDraw(r, &paint))
+ return;
+
if (ShouldSkipImageInPaint(paint))
return;
@@ -289,6 +309,9 @@ void ImageHijackCanvas::onDrawArc(const SkRect& r,
const SkPaint& paint) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"ImageHijackCanvas::onDrawArc");
+ if (QuickRejectDraw(r, &paint))
+ return;
+
if (ShouldSkipImageInPaint(paint))
return;
@@ -305,6 +328,9 @@ void ImageHijackCanvas::onDrawArc(const SkRect& r,
void ImageHijackCanvas::onDrawRRect(const SkRRect& rr, const SkPaint& paint) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"ImageHijackCanvas::onDrawRRect");
+ if (QuickRejectDraw(rr.rect(), &paint))
+ return;
+
if (ShouldSkipImageInPaint(paint))
return;
@@ -339,4 +365,16 @@ bool ImageHijackCanvas::ShouldSkipImageInPaint(const SkPaint& paint) const {
return image ? ShouldSkipImage(image) : false;
}
+bool ImageHijackCanvas::QuickRejectDraw(const SkRect& rect,
+ const SkPaint* paint) const {
+ if (nullptr == paint || paint->canComputeFastBounds()) {
+ SkRect tmp = rect;
+ if (paint)
+ paint->computeFastBounds(tmp, &tmp);
+ return quickReject(tmp);
+ }
+
+ return false;
+}
+
} // namespace cc
diff --git a/chromium/cc/raster/image_hijack_canvas.h b/chromium/cc/raster/image_hijack_canvas.h
index 4693e8d8622..a71c662f49a 100644
--- a/chromium/cc/raster/image_hijack_canvas.h
+++ b/chromium/cc/raster/image_hijack_canvas.h
@@ -22,7 +22,7 @@ class CC_EXPORT ImageHijackCanvas : public SkNWayCanvas {
ImageHijackCanvas(int width,
int height,
ImageDecodeCache* image_decode_cache,
- const ImageIdFlatSet* images_to_skip,
+ const SkImageIdFlatSet* images_to_skip,
const gfx::ColorSpace& target_color_space);
private:
@@ -56,9 +56,10 @@ class CC_EXPORT ImageHijackCanvas : public SkNWayCanvas {
bool ShouldSkipImage(const SkImage* image) const;
bool ShouldSkipImageInPaint(const SkPaint& paint) const;
+ bool QuickRejectDraw(const SkRect& rect, const SkPaint* paint) const;
ImageDecodeCache* image_decode_cache_;
- const ImageIdFlatSet* images_to_skip_;
+ const SkImageIdFlatSet* images_to_skip_;
const gfx::ColorSpace target_color_space_;
DISALLOW_COPY_AND_ASSIGN(ImageHijackCanvas);
diff --git a/chromium/cc/raster/image_hijack_canvas_unittest.cc b/chromium/cc/raster/image_hijack_canvas_unittest.cc
index 070070f2632..8a9f4affdc3 100644
--- a/chromium/cc/raster/image_hijack_canvas_unittest.cc
+++ b/chromium/cc/raster/image_hijack_canvas_unittest.cc
@@ -32,13 +32,14 @@ class MockImageDecodeCache : public ImageDecodeCache {
MOCK_METHOD0(ClearCache, void());
MOCK_METHOD2(GetOutOfRasterDecodeTaskForImageAndRef,
bool(const DrawImage& image, scoped_refptr<TileTask>* task));
+ MOCK_CONST_METHOD0(GetMaximumMemoryLimitBytes, size_t());
};
TEST(ImageHijackCanvasTest, NonLazyImagesSkipped) {
// Use a strict mock so that if *any* ImageDecodeCache methods are called, we
// will hit an error.
testing::StrictMock<MockImageDecodeCache> image_decode_cache;
- ImageIdFlatSet images_to_skip;
+ SkImageIdFlatSet images_to_skip;
gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateSRGB();
ImageHijackCanvas canvas(100, 100, &image_decode_cache, &images_to_skip,
target_color_space);
@@ -71,7 +72,7 @@ TEST(ImageHijackCanvasTest, ImagesToSkipAreSkipped) {
// Use a strict mock so that if *any* ImageDecodeCache methods are called, we
// will hit an error.
testing::StrictMock<MockImageDecodeCache> image_decode_cache;
- ImageIdFlatSet images_to_skip;
+ SkImageIdFlatSet images_to_skip;
sk_sp<SkImage> image = CreateDiscardableImage(gfx::Size(10, 10));
images_to_skip.insert(image->uniqueID());
gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateSRGB();
@@ -87,6 +88,29 @@ TEST(ImageHijackCanvasTest, ImagesToSkipAreSkipped) {
canvas.drawRect(SkRect::MakeXYWH(10, 10, 10, 10), paint);
}
+TEST(ImageHijackCanvasTest, ClippedOpsAreSkipped) {
+ testing::StrictMock<MockImageDecodeCache> image_decode_cache;
+ SkImageIdFlatSet images_to_skip;
+ gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateSRGB();
+ ImageHijackCanvas canvas(100, 100, &image_decode_cache, &images_to_skip,
+ target_color_space);
+ SkPaint paint;
+ SkRect draw_rect = SkRect::MakeXYWH(200, 200, 100, 100);
+ sk_sp<SkImage> image = CreateDiscardableImage(gfx::Size(10, 10));
+ canvas.drawImage(image, 200, 200, &paint);
+ canvas.drawImageRect(image, SkRect::MakeXYWH(0, 0, 10, 10), draw_rect,
+ &paint);
+ paint.setShader(image->makeShader(SkShader::kClamp_TileMode,
+ SkShader::kClamp_TileMode, nullptr));
+ canvas.drawRect(draw_rect, paint);
+ SkPath path;
+ path.addRect(draw_rect, SkPath::kCW_Direction);
+ canvas.drawPath(path, paint);
+ canvas.drawOval(draw_rect, paint);
+ canvas.drawArc(draw_rect, 0, 40, true, paint);
+ canvas.drawRRect(SkRRect::MakeRect(draw_rect), paint);
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/raster/one_copy_raster_buffer_provider.cc b/chromium/cc/raster/one_copy_raster_buffer_provider.cc
index abc63e46fc3..f662e6c1509 100644
--- a/chromium/cc/raster/one_copy_raster_buffer_provider.cc
+++ b/chromium/cc/raster/one_copy_raster_buffer_provider.cc
@@ -140,6 +140,16 @@ void OneCopyRasterBufferProvider::OrderingBarrier() {
pending_raster_buffers_.clear();
}
+void OneCopyRasterBufferProvider::Flush() {
+ if (async_worker_context_enabled_) {
+ int32_t worker_stream_id =
+ worker_context_provider_->ContextSupport()->GetStreamId();
+
+ compositor_context_provider_->ContextSupport()
+ ->FlushOrderingBarrierOnStream(worker_stream_id);
+ }
+}
+
ResourceFormat OneCopyRasterBufferProvider::GetResourceFormat(
bool must_support_alpha) const {
if (resource_provider_->IsTextureFormatSupported(preferred_tile_format_) &&
@@ -240,7 +250,7 @@ void OneCopyRasterBufferProvider::PlaybackAndCopyOnWorkerThread(
playback_settings, previous_content_id, new_content_id);
CopyOnWorkerThread(staging_buffer.get(), resource_lock, sync_token,
- raster_source, previous_content_id, new_content_id);
+ raster_source, raster_full_rect);
staging_pool_.ReleaseStagingBuffer(std::move(staging_buffer));
}
@@ -312,8 +322,7 @@ void OneCopyRasterBufferProvider::CopyOnWorkerThread(
ResourceProvider::ScopedWriteLockGL* resource_lock,
const gpu::SyncToken& sync_token,
const RasterSource* raster_source,
- uint64_t previous_content_id,
- uint64_t new_content_id) {
+ const gfx::Rect& rect_to_copy) {
ContextProvider::ScopedContextLock scoped_context(worker_context_provider_);
gpu::gles2::GLES2Interface* gl = scoped_context.ContextGL();
DCHECK(gl);
@@ -375,22 +384,21 @@ void OneCopyRasterBufferProvider::CopyOnWorkerThread(
resource_texture_id);
} else {
int bytes_per_row = ResourceUtil::UncheckedWidthInBytes<int>(
- resource_lock->size().width(), resource_lock->format());
+ rect_to_copy.width(), resource_lock->format());
int chunk_size_in_rows =
std::max(1, max_bytes_per_copy_operation_ / bytes_per_row);
// Align chunk size to 4. Required to support compressed texture formats.
chunk_size_in_rows = MathUtil::UncheckedRoundUp(chunk_size_in_rows, 4);
int y = 0;
- int height = resource_lock->size().height();
+ int height = rect_to_copy.height();
while (y < height) {
// Copy at most |chunk_size_in_rows|.
int rows_to_copy = std::min(chunk_size_in_rows, height - y);
DCHECK_GT(rows_to_copy, 0);
- gl->CopySubTextureCHROMIUM(staging_buffer->texture_id, 0, GL_TEXTURE_2D,
- resource_texture_id, 0, 0, y, 0, y,
- resource_lock->size().width(), rows_to_copy,
- false, false, false);
+ gl->CopySubTextureCHROMIUM(
+ staging_buffer->texture_id, 0, GL_TEXTURE_2D, resource_texture_id, 0,
+ 0, y, 0, y, rect_to_copy.width(), rows_to_copy, false, false, false);
y += rows_to_copy;
// Increment |bytes_scheduled_since_last_flush_| by the amount of memory
diff --git a/chromium/cc/raster/one_copy_raster_buffer_provider.h b/chromium/cc/raster/one_copy_raster_buffer_provider.h
index 5d82849cc6c..581bc493b40 100644
--- a/chromium/cc/raster/one_copy_raster_buffer_provider.h
+++ b/chromium/cc/raster/one_copy_raster_buffer_provider.h
@@ -38,6 +38,7 @@ class CC_EXPORT OneCopyRasterBufferProvider : public RasterBufferProvider {
uint64_t previous_content_id) override;
void ReleaseBufferForRaster(std::unique_ptr<RasterBuffer> buffer) override;
void OrderingBarrier() override;
+ void Flush() override;
ResourceFormat GetResourceFormat(bool must_support_alpha) const override;
bool IsResourceSwizzleRequired(bool must_support_alpha) const override;
bool CanPartialRasterIntoProvidedResource() const override;
@@ -110,8 +111,7 @@ class CC_EXPORT OneCopyRasterBufferProvider : public RasterBufferProvider {
ResourceProvider::ScopedWriteLockGL* resource_lock,
const gpu::SyncToken& sync_token,
const RasterSource* raster_source,
- uint64_t previous_content_id,
- uint64_t new_content_id);
+ const gfx::Rect& rect_to_copy);
gfx::BufferUsage StagingBufferUsage() const;
ContextProvider* const compositor_context_provider_;
diff --git a/chromium/cc/raster/raster_buffer_provider.cc b/chromium/cc/raster/raster_buffer_provider.cc
index 7b3dfc6710f..f3e281063ad 100644
--- a/chromium/cc/raster/raster_buffer_provider.cc
+++ b/chromium/cc/raster/raster_buffer_provider.cc
@@ -12,6 +12,7 @@
#include "cc/resources/platform_color.h"
#include "cc/resources/resource_format_utils.h"
#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkMath.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "ui/gfx/geometry/axis_transform2d.h"
@@ -23,6 +24,58 @@ RasterBufferProvider::~RasterBufferProvider() {}
namespace {
+// TODO(enne): http://crbug.com/721744. Add CHECKs for conditions that would
+// cause Skia to not create a surface here to diagnose what's going wrong. This
+// replicates SkSurfaceValidateRasterInfo and needs to be kept in sync with
+// the corresponding Skia code. This code should be removed as quickly as
+// possible once a diagnosis is made.
+void CheckValidRasterInfo(const SkImageInfo& info,
+ void* pixels,
+ size_t row_bytes) {
+ CHECK(pixels);
+ CHECK(!info.isEmpty());
+
+ static const size_t kMaxTotalSize = SK_MaxS32;
+
+ int shift = 0;
+ switch (info.colorType()) {
+ case kAlpha_8_SkColorType:
+ CHECK(!info.colorSpace());
+ shift = 0;
+ break;
+ case kRGB_565_SkColorType:
+ CHECK(!info.colorSpace());
+ shift = 1;
+ break;
+ case kN32_SkColorType:
+ if (info.colorSpace())
+ CHECK(info.colorSpace()->gammaCloseToSRGB());
+ shift = 2;
+ break;
+ case kRGBA_F16_SkColorType:
+ if (info.colorSpace())
+ CHECK(info.colorSpace()->gammaIsLinear());
+ shift = 3;
+ break;
+ default:
+ CHECK(false) << "Unknown color type";
+ break;
+ }
+
+ static constexpr size_t kIgnoreRowBytesValue = static_cast<size_t>(~0);
+ if (kIgnoreRowBytesValue == row_bytes)
+ return;
+
+ uint64_t min_row_bytes = static_cast<uint64_t>(info.width()) << shift;
+ CHECK_LE(min_row_bytes, row_bytes);
+
+ size_t aligned_row_bytes = row_bytes >> shift << shift;
+ CHECK_EQ(aligned_row_bytes, row_bytes);
+
+ uint64_t size = sk_64_mul(info.height(), row_bytes);
+ CHECK_LE(size, kMaxTotalSize);
+}
+
bool IsSupportedPlaybackToMemoryFormat(ResourceFormat format) {
switch (format) {
case RGBA_4444:
@@ -80,8 +133,10 @@ void RasterBufferProvider::PlaybackToMemory(
case RGBA_8888:
case BGRA_8888:
case RGBA_F16: {
+ CheckValidRasterInfo(info, memory, stride);
sk_sp<SkSurface> surface =
SkSurface::MakeRasterDirect(info, memory, stride, &surface_props);
+ CHECK(surface);
raster_source->PlaybackToCanvas(surface->getCanvas(), target_color_space,
canvas_bitmap_rect, canvas_playback_rect,
transform, playback_settings);
diff --git a/chromium/cc/raster/raster_buffer_provider.h b/chromium/cc/raster/raster_buffer_provider.h
index 40611dfb96b..6055ccdacd6 100644
--- a/chromium/cc/raster/raster_buffer_provider.h
+++ b/chromium/cc/raster/raster_buffer_provider.h
@@ -54,6 +54,10 @@ class CC_EXPORT RasterBufferProvider {
// Used for syncing resources to the worker context.
virtual void OrderingBarrier() = 0;
+ // In addition to above, also ensures that pending work is sent to the GPU
+ // process.
+ virtual void Flush() = 0;
+
// Returns the format to use for the tiles.
virtual ResourceFormat GetResourceFormat(bool must_support_alpha) const = 0;
diff --git a/chromium/cc/raster/raster_source.cc b/chromium/cc/raster/raster_source.cc
index b1443e61770..409d214f407 100644
--- a/chromium/cc/raster/raster_source.cc
+++ b/chromium/cc/raster/raster_source.cc
@@ -101,7 +101,7 @@ void RasterSource::PlaybackToCanvas(SkCanvas* input_canvas,
if (settings.skip_images) {
SkipImageCanvas canvas(raster_canvas);
- RasterCommon(&canvas, nullptr);
+ RasterCommon(&canvas);
} else if (settings.use_image_hijack_canvas) {
const SkImageInfo& info = raster_canvas->imageInfo();
ImageHijackCanvas canvas(info.width(), info.height(), image_decode_cache_,
@@ -115,9 +115,9 @@ void RasterSource::PlaybackToCanvas(SkCanvas* input_canvas,
canvas.setMatrix(raster_canvas->getTotalMatrix());
canvas.addCanvas(raster_canvas);
- RasterCommon(&canvas, nullptr);
+ RasterCommon(&canvas);
} else {
- RasterCommon(raster_canvas, nullptr);
+ RasterCommon(raster_canvas);
}
}
@@ -225,7 +225,7 @@ sk_sp<SkPicture> RasterSource::GetFlattenedPicture() {
SkCanvas* canvas = recorder.beginRecording(size_.width(), size_.height());
if (!size_.IsEmpty()) {
PrepareForPlaybackToCanvas(canvas);
- RasterCommon(canvas, nullptr);
+ RasterCommon(canvas);
}
return recorder.finishRecordingAsPicture();
@@ -265,7 +265,7 @@ void RasterSource::GetDiscardableImagesInRect(
target_color_space, images);
}
-gfx::Rect RasterSource::GetRectForImage(ImageId image_id) const {
+gfx::Rect RasterSource::GetRectForImage(PaintImage::Id image_id) const {
if (!display_list_)
return gfx::Rect();
return display_list_->GetRectForImage(image_id);
diff --git a/chromium/cc/raster/raster_source.h b/chromium/cc/raster/raster_source.h
index df899ab220c..92e429bd24f 100644
--- a/chromium/cc/raster/raster_source.h
+++ b/chromium/cc/raster/raster_source.h
@@ -51,7 +51,7 @@ class CC_EXPORT RasterSource : public base::RefCountedThreadSafe<RasterSource> {
// during raster.
// TODO(khushalsagar): Consolidate more settings for playback here? See
// crbug.com/691076.
- ImageIdFlatSet images_to_skip;
+ SkImageIdFlatSet images_to_skip;
};
static scoped_refptr<RasterSource> CreateFromRecordingSource(
@@ -121,7 +121,7 @@ class CC_EXPORT RasterSource : public base::RefCountedThreadSafe<RasterSource> {
// Valid rectangle in which everything is recorded and can be rastered from.
virtual gfx::Rect RecordedViewport() const;
- gfx::Rect GetRectForImage(ImageId image_id) const;
+ gfx::Rect GetRectForImage(PaintImage::Id image_id) const;
// Tracing functionality.
virtual void DidBeginTracing();
@@ -168,7 +168,7 @@ class CC_EXPORT RasterSource : public base::RefCountedThreadSafe<RasterSource> {
private:
void RasterCommon(SkCanvas* canvas,
- SkPicture::AbortCallback* callback) const;
+ SkPicture::AbortCallback* callback = nullptr) const;
void PrepareForPlaybackToCanvas(SkCanvas* canvas) const;
diff --git a/chromium/cc/raster/raster_source_unittest.cc b/chromium/cc/raster/raster_source_unittest.cc
index 344205714c4..5cb06aaf7c3 100644
--- a/chromium/cc/raster/raster_source_unittest.cc
+++ b/chromium/cc/raster/raster_source_unittest.cc
@@ -207,7 +207,6 @@ TEST(RasterSourceTest, PixelRefIteratorDiscardableRefsOneTile) {
recording_source->add_draw_image(discardable_image[0][1], gfx::Point(260, 0));
recording_source->add_draw_image(discardable_image[1][1],
gfx::Point(260, 260));
- recording_source->SetGenerateDiscardableImagesMetadata(true);
recording_source->Rerecord();
scoped_refptr<RasterSource> raster =
@@ -593,7 +592,6 @@ TEST(RasterSourceTest, ImageHijackCanvasRespectsSharedCanvasTransform) {
recording_source->add_draw_rect_with_flags(
gfx::Rect(size.width() - 4, size.height() - 4, 4, 4), flags);
- recording_source->SetGenerateDiscardableImagesMetadata(true);
recording_source->Rerecord();
bool can_use_lcd = true;
diff --git a/chromium/cc/raster/staging_buffer_pool.cc b/chromium/cc/raster/staging_buffer_pool.cc
index 526e864ebdc..3cb4b14dfe6 100644
--- a/chromium/cc/raster/staging_buffer_pool.cc
+++ b/chromium/cc/raster/staging_buffer_pool.cc
@@ -114,8 +114,8 @@ void StagingBuffer::OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
const uint64_t tracing_process_id =
base::trace_event::MemoryDumpManager::GetInstance()
->GetTracingProcessId();
- MemoryAllocatorDumpGuid shared_buffer_guid =
- gfx::GetGpuMemoryBufferGUIDForTracing(tracing_process_id, buffer_id);
+ auto shared_buffer_guid =
+ gpu_memory_buffer->GetGUIDForTracing(tracing_process_id);
pmd->CreateSharedGlobalAllocatorDump(shared_buffer_guid);
// By creating an edge with a higher |importance| (w.r.t. browser-side dumps)
diff --git a/chromium/cc/raster/zero_copy_raster_buffer_provider.cc b/chromium/cc/raster/zero_copy_raster_buffer_provider.cc
index 85db2c4684f..9542fe4ac3e 100644
--- a/chromium/cc/raster/zero_copy_raster_buffer_provider.cc
+++ b/chromium/cc/raster/zero_copy_raster_buffer_provider.cc
@@ -100,6 +100,8 @@ void ZeroCopyRasterBufferProvider::OrderingBarrier() {
// No need to sync resources as this provider does not use GL context.
}
+void ZeroCopyRasterBufferProvider::Flush() {}
+
ResourceFormat ZeroCopyRasterBufferProvider::GetResourceFormat(
bool must_support_alpha) const {
if (resource_provider_->IsTextureFormatSupported(preferred_tile_format_) &&
diff --git a/chromium/cc/raster/zero_copy_raster_buffer_provider.h b/chromium/cc/raster/zero_copy_raster_buffer_provider.h
index 686ba7ad5a2..16f2c6bdeef 100644
--- a/chromium/cc/raster/zero_copy_raster_buffer_provider.h
+++ b/chromium/cc/raster/zero_copy_raster_buffer_provider.h
@@ -36,6 +36,7 @@ class CC_EXPORT ZeroCopyRasterBufferProvider : public RasterBufferProvider {
uint64_t previous_content_id) override;
void ReleaseBufferForRaster(std::unique_ptr<RasterBuffer> buffer) override;
void OrderingBarrier() override;
+ void Flush() override;
ResourceFormat GetResourceFormat(bool must_support_alpha) const override;
bool IsResourceSwizzleRequired(bool must_support_alpha) const override;
bool CanPartialRasterIntoProvidedResource() const override;
diff --git a/chromium/cc/resources/resource_pool.cc b/chromium/cc/resources/resource_pool.cc
index ee516d50ebf..5ad2f6a5344 100644
--- a/chromium/cc/resources/resource_pool.cc
+++ b/chromium/cc/resources/resource_pool.cc
@@ -24,8 +24,39 @@ using base::trace_event::MemoryAllocatorDump;
using base::trace_event::MemoryDumpLevelOfDetail;
namespace cc {
+namespace {
+bool ResourceMeetsSizeRequirements(const gfx::Size& requested_size,
+ const gfx::Size& actual_size,
+ bool disallow_non_exact_reuse) {
+ const float kReuseThreshold = 2.0f;
+
+ if (disallow_non_exact_reuse)
+ return requested_size == actual_size;
+
+ // Allocating new resources is expensive, and we'd like to re-use our
+ // existing ones within reason. Allow a larger resource to be used for a
+ // smaller request.
+ if (actual_size.width() < requested_size.width() ||
+ actual_size.height() < requested_size.height())
+ return false;
+
+ // GetArea will crash on overflow, however all sizes in use are tile sizes.
+ // These are capped at ResourceProvider::max_texture_size(), and will not
+ // overflow.
+ float actual_area = actual_size.GetArea();
+ float requested_area = requested_size.GetArea();
+ // Don't use a resource that is more than |kReuseThreshold| times the
+ // requested pixel area, as we want to free unnecessarily large resources.
+ if (actual_area / requested_area > kReuseThreshold)
+ return false;
+
+ return true;
+}
+
+} // namespace
+
base::TimeDelta ResourcePool::kDefaultExpirationDelay =
- base::TimeDelta::FromSeconds(1);
+ base::TimeDelta::FromSeconds(5);
void ResourcePool::PoolResource::OnMemoryDump(
base::trace_event::ProcessMemoryDump* pmd,
@@ -56,12 +87,14 @@ void ResourcePool::PoolResource::OnMemoryDump(
ResourcePool::ResourcePool(ResourceProvider* resource_provider,
base::SingleThreadTaskRunner* task_runner,
gfx::BufferUsage usage,
- const base::TimeDelta& expiration_delay)
+ const base::TimeDelta& expiration_delay,
+ bool disallow_non_exact_reuse)
: resource_provider_(resource_provider),
use_gpu_memory_buffers_(true),
usage_(usage),
task_runner_(task_runner),
resource_expiration_delay_(expiration_delay),
+ disallow_non_exact_reuse_(disallow_non_exact_reuse),
weak_ptr_factory_(this) {
base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
this, "cc::ResourcePool", task_runner_.get());
@@ -73,12 +106,14 @@ ResourcePool::ResourcePool(ResourceProvider* resource_provider,
ResourcePool::ResourcePool(ResourceProvider* resource_provider,
base::SingleThreadTaskRunner* task_runner,
ResourceProvider::TextureHint hint,
- const base::TimeDelta& expiration_delay)
+ const base::TimeDelta& expiration_delay,
+ bool disallow_non_exact_reuse)
: resource_provider_(resource_provider),
use_gpu_memory_buffers_(false),
hint_(hint),
task_runner_(task_runner),
resource_expiration_delay_(expiration_delay),
+ disallow_non_exact_reuse_(disallow_non_exact_reuse),
weak_ptr_factory_(this) {
base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
this, "cc::ResourcePool", task_runner_.get());
@@ -119,7 +154,8 @@ Resource* ResourcePool::ReuseResource(const gfx::Size& size,
if (resource->format() != format)
continue;
- if (resource->size() != size)
+ if (!ResourceMeetsSizeRequirements(size, resource->size(),
+ disallow_non_exact_reuse_))
continue;
if (resource->color_space() != color_space)
continue;
diff --git a/chromium/cc/resources/resource_pool.h b/chromium/cc/resources/resource_pool.h
index 8932364ee4c..33291874d26 100644
--- a/chromium/cc/resources/resource_pool.h
+++ b/chromium/cc/resources/resource_pool.h
@@ -33,18 +33,22 @@ class CC_EXPORT ResourcePool : public base::trace_event::MemoryDumpProvider,
ResourceProvider* resource_provider,
base::SingleThreadTaskRunner* task_runner,
gfx::BufferUsage usage,
- const base::TimeDelta& expiration_delay) {
+ const base::TimeDelta& expiration_delay,
+ bool disallow_non_exact_reuse) {
return base::WrapUnique(new ResourcePool(resource_provider, task_runner,
- usage, expiration_delay));
+ usage, expiration_delay,
+ disallow_non_exact_reuse));
}
static std::unique_ptr<ResourcePool> Create(
ResourceProvider* resource_provider,
base::SingleThreadTaskRunner* task_runner,
ResourceProvider::TextureHint hint,
- const base::TimeDelta& expiration_delay) {
+ const base::TimeDelta& expiration_delay,
+ bool disallow_non_exact_reuse) {
return base::WrapUnique(new ResourcePool(resource_provider, task_runner,
- hint, expiration_delay));
+ hint, expiration_delay,
+ disallow_non_exact_reuse));
}
~ResourcePool() override;
@@ -102,16 +106,19 @@ class CC_EXPORT ResourcePool : public base::trace_event::MemoryDumpProvider,
ResourcePool(ResourceProvider* resource_provider,
base::SingleThreadTaskRunner* task_runner,
gfx::BufferUsage usage,
- const base::TimeDelta& expiration_delay);
+ const base::TimeDelta& expiration_delay,
+ bool disallow_non_exact_reuse);
// Constructor for creating standard resources.
ResourcePool(ResourceProvider* resource_provider,
base::SingleThreadTaskRunner* task_runner,
ResourceProvider::TextureHint hint,
- const base::TimeDelta& expiration_delay);
+ const base::TimeDelta& expiration_delay,
+ bool disallow_non_exact_reuse);
private:
FRIEND_TEST_ALL_PREFIXES(ResourcePoolTest, ReuseResource);
+ FRIEND_TEST_ALL_PREFIXES(ResourcePoolTest, ExactRequestsRespected);
class PoolResource : public ScopedResource {
public:
static std::unique_ptr<PoolResource> Create(
@@ -186,6 +193,7 @@ class CC_EXPORT ResourcePool : public base::trace_event::MemoryDumpProvider,
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
bool evict_expired_resources_pending_ = false;
const base::TimeDelta resource_expiration_delay_;
+ const bool disallow_non_exact_reuse_ = false;
base::WeakPtrFactory<ResourcePool> weak_ptr_factory_;
diff --git a/chromium/cc/resources/resource_pool_unittest.cc b/chromium/cc/resources/resource_pool_unittest.cc
index aa8e853e0c4..34f7aca0c58 100644
--- a/chromium/cc/resources/resource_pool_unittest.cc
+++ b/chromium/cc/resources/resource_pool_unittest.cc
@@ -7,6 +7,7 @@
#include <stddef.h>
#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "cc/resources/resource_util.h"
#include "cc/resources/scoped_resource.h"
@@ -29,10 +30,16 @@ class ResourcePoolTest : public testing::Test {
resource_pool_ =
ResourcePool::Create(resource_provider_.get(), task_runner_.get(),
ResourceProvider::TEXTURE_HINT_IMMUTABLE,
- ResourcePool::kDefaultExpirationDelay);
+ ResourcePool::kDefaultExpirationDelay, false);
}
protected:
+ void CheckAndReturnResource(Resource* resource) {
+ EXPECT_NE(nullptr, resource);
+ resource_pool_->ReleaseResource(resource);
+ resource_pool_->CheckBusyResources();
+ }
+
scoped_refptr<TestContextProvider> context_provider_;
std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_;
std::unique_ptr<ResourceProvider> resource_provider_;
@@ -105,32 +112,28 @@ TEST_F(ResourcePoolTest, SimpleResourceReuse) {
gfx::ColorSpace color_space1;
gfx::ColorSpace color_space2 = gfx::ColorSpace::CreateSRGB();
- Resource* resource =
- resource_pool_->AcquireResource(size, format, color_space1);
- resource_pool_->ReleaseResource(resource);
- resource_pool_->CheckBusyResources();
+ CheckAndReturnResource(
+ resource_pool_->AcquireResource(size, format, color_space1));
EXPECT_EQ(1u, resource_provider_->num_resources());
// Same size/format should re-use resource.
- resource = resource_pool_->AcquireResource(size, format, color_space1);
+ Resource* resource =
+ resource_pool_->AcquireResource(size, format, color_space1);
EXPECT_EQ(1u, resource_provider_->num_resources());
- resource_pool_->ReleaseResource(resource);
- resource_pool_->CheckBusyResources();
+ CheckAndReturnResource(resource);
EXPECT_EQ(1u, resource_provider_->num_resources());
// Different size/format should allocate new resource.
resource = resource_pool_->AcquireResource(gfx::Size(50, 50), LUMINANCE_8,
color_space1);
EXPECT_EQ(2u, resource_provider_->num_resources());
- resource_pool_->ReleaseResource(resource);
- resource_pool_->CheckBusyResources();
+ CheckAndReturnResource(resource);
EXPECT_EQ(2u, resource_provider_->num_resources());
// Different color space should allocate new resource.
resource = resource_pool_->AcquireResource(size, format, color_space2);
EXPECT_EQ(3u, resource_provider_->num_resources());
- resource_pool_->ReleaseResource(resource);
- resource_pool_->CheckBusyResources();
+ CheckAndReturnResource(resource);
EXPECT_EQ(3u, resource_provider_->num_resources());
}
@@ -160,7 +163,7 @@ TEST_F(ResourcePoolTest, BusyResourcesEventuallyFreed) {
resource_pool_ =
ResourcePool::Create(resource_provider_.get(), task_runner_.get(),
ResourceProvider::TEXTURE_HINT_IMMUTABLE,
- base::TimeDelta::FromMilliseconds(10));
+ base::TimeDelta::FromMilliseconds(10), false);
// Limits high enough to not be hit by this test.
size_t bytes_limit = 10 * 1024 * 1024;
@@ -201,7 +204,7 @@ TEST_F(ResourcePoolTest, UnusedResourcesEventuallyFreed) {
resource_pool_ =
ResourcePool::Create(resource_provider_.get(), task_runner_.get(),
ResourceProvider::TEXTURE_HINT_IMMUTABLE,
- base::TimeDelta::FromMilliseconds(100));
+ base::TimeDelta::FromMilliseconds(100), false);
// Limits high enough to not be hit by this test.
size_t bytes_limit = 10 * 1024 * 1024;
@@ -317,25 +320,47 @@ TEST_F(ResourcePoolTest, ReuseResource) {
ResourceFormat format = RGBA_8888;
gfx::ColorSpace color_space = gfx::ColorSpace::CreateSRGB();
- // Create unused resources with sizes close to 100, 100.
- resource_pool_->ReleaseResource(
- resource_pool_->CreateResource(gfx::Size(99, 100), format, color_space));
- resource_pool_->ReleaseResource(
- resource_pool_->CreateResource(gfx::Size(99, 99), format, color_space));
- resource_pool_->ReleaseResource(
- resource_pool_->CreateResource(gfx::Size(100, 99), format, color_space));
- resource_pool_->ReleaseResource(
- resource_pool_->CreateResource(gfx::Size(101, 101), format, color_space));
- resource_pool_->CheckBusyResources();
-
- gfx::Size size(100, 100);
- Resource* resource = resource_pool_->ReuseResource(size, format, color_space);
- EXPECT_EQ(nullptr, resource);
- size = gfx::Size(100, 99);
- resource = resource_pool_->ReuseResource(size, format, color_space);
- EXPECT_NE(nullptr, resource);
- ASSERT_EQ(nullptr, resource_pool_->ReuseResource(size, format, color_space));
- resource_pool_->ReleaseResource(resource);
+ // Create unused resource with size 100x100.
+ CheckAndReturnResource(
+ resource_pool_->CreateResource(gfx::Size(100, 100), format, color_space));
+
+ // Try some cases that are too large, none should succeed.
+ EXPECT_EQ(nullptr, resource_pool_->ReuseResource(gfx::Size(101, 100), format,
+ color_space));
+ EXPECT_EQ(nullptr, resource_pool_->ReuseResource(gfx::Size(100, 101), format,
+ color_space));
+ EXPECT_EQ(nullptr, resource_pool_->ReuseResource(gfx::Size(90, 120), format,
+ color_space));
+ EXPECT_EQ(nullptr, resource_pool_->ReuseResource(gfx::Size(120, 120), format,
+ color_space));
+
+ // Try some cases that are more than 2x smaller than 100x100 in area and
+ // won't be re-used.
+ EXPECT_EQ(nullptr, resource_pool_->ReuseResource(gfx::Size(49, 100), format,
+ color_space));
+ EXPECT_EQ(nullptr, resource_pool_->ReuseResource(gfx::Size(100, 49), format,
+ color_space));
+ EXPECT_EQ(nullptr, resource_pool_->ReuseResource(gfx::Size(50, 50), format,
+ color_space));
+ EXPECT_EQ(nullptr, resource_pool_->ReuseResource(gfx::Size(70, 70), format,
+ color_space));
+
+ // Try some cases that are smaller than 100x100, but within 2x area. Reuse
+ // should succeed.
+ CheckAndReturnResource(
+ resource_pool_->ReuseResource(gfx::Size(50, 100), format, color_space));
+ CheckAndReturnResource(
+ resource_pool_->ReuseResource(gfx::Size(100, 50), format, color_space));
+ CheckAndReturnResource(
+ resource_pool_->ReuseResource(gfx::Size(71, 71), format, color_space));
+
+ // 100x100 is an exact match and should succeed. A subsequent request for
+ // the same size should fail (the resource is already in use).
+ Resource* resource =
+ resource_pool_->ReuseResource(gfx::Size(100, 100), format, color_space);
+ EXPECT_EQ(nullptr, resource_pool_->ReuseResource(gfx::Size(100, 100), format,
+ color_space));
+ CheckAndReturnResource(resource);
}
TEST_F(ResourcePoolTest, MemoryStateSuspended) {
@@ -380,7 +405,7 @@ TEST_F(ResourcePoolTest, TextureHintRespected) {
resource_pool_ =
ResourcePool::Create(resource_provider_.get(), task_runner_.get(),
ResourceProvider::TEXTURE_HINT_IMMUTABLE,
- base::TimeDelta::FromMilliseconds(100));
+ base::TimeDelta::FromMilliseconds(100), false);
Resource* resource =
resource_pool_->AcquireResource(size, format, color_space);
EXPECT_TRUE(resource_provider_->IsImmutable(resource->id()));
@@ -389,10 +414,41 @@ TEST_F(ResourcePoolTest, TextureHintRespected) {
resource_pool_ =
ResourcePool::Create(resource_provider_.get(), task_runner_.get(),
ResourceProvider::TEXTURE_HINT_DEFAULT,
- base::TimeDelta::FromMilliseconds(100));
+ base::TimeDelta::FromMilliseconds(100), false);
resource = resource_pool_->AcquireResource(size, format, color_space);
EXPECT_FALSE(resource_provider_->IsImmutable(resource->id()));
resource_pool_->ReleaseResource(resource);
}
+TEST_F(ResourcePoolTest, ExactRequestsRespected) {
+ ResourceFormat format = RGBA_8888;
+ gfx::ColorSpace color_space = gfx::ColorSpace::CreateSRGB();
+
+ resource_pool_ =
+ ResourcePool::Create(resource_provider_.get(), task_runner_.get(),
+ ResourceProvider::TEXTURE_HINT_DEFAULT,
+ base::TimeDelta::FromMilliseconds(100), true);
+
+ // Create unused resource with size 100x100.
+ CheckAndReturnResource(
+ resource_pool_->CreateResource(gfx::Size(100, 100), format, color_space));
+
+ // Try some cases that are smaller than 100x100, but within 2x area which
+ // would typically allow reuse. Reuse should fail due to the .
+ EXPECT_EQ(nullptr, resource_pool_->ReuseResource(gfx::Size(50, 100), format,
+ color_space));
+ EXPECT_EQ(nullptr, resource_pool_->ReuseResource(gfx::Size(100, 50), format,
+ color_space));
+ EXPECT_EQ(nullptr, resource_pool_->ReuseResource(gfx::Size(71, 71), format,
+ color_space));
+
+ // 100x100 is an exact match and should succeed. A subsequent request for
+ // the same size should fail (the resource is already in use).
+ Resource* resource =
+ resource_pool_->ReuseResource(gfx::Size(100, 100), format, color_space);
+ EXPECT_EQ(nullptr, resource_pool_->ReuseResource(gfx::Size(100, 100), format,
+ color_space));
+ CheckAndReturnResource(resource);
+}
+
} // namespace cc
diff --git a/chromium/cc/resources/resource_provider.cc b/chromium/cc/resources/resource_provider.cc
index 5275af92daf..8d5a3fce7fe 100644
--- a/chromium/cc/resources/resource_provider.cc
+++ b/chromium/cc/resources/resource_provider.cc
@@ -1623,7 +1623,7 @@ void ResourceProvider::ReceiveFromChild(
// Don't allocate a texture for a child.
resource->allocated = true;
resource->imported_count = 1;
- child_info.parent_to_child_map[local_id] = it->id;
+ resource->id_in_child = it->id;
child_info.child_to_parent_map[it->id] = local_id;
}
}
@@ -1835,9 +1835,8 @@ void ResourceProvider::DeleteAndReturnUnusedResourcesToChild(
Resource& resource = it->second;
DCHECK(!resource.locked_for_write);
- DCHECK(child_info->parent_to_child_map.count(local_id));
- ResourceId child_id = child_info->parent_to_child_map[local_id];
+ ResourceId child_id = resource.id_in_child;
DCHECK(child_info->child_to_parent_map.count(child_id));
bool is_lost = resource.lost ||
@@ -1892,7 +1891,6 @@ void ResourceProvider::DeleteAndReturnUnusedResourcesToChild(
}
}
- child_info->parent_to_child_map.erase(local_id);
child_info->child_to_parent_map.erase(child_id);
resource.imported_count = 0;
DeleteResourceInternal(it, style);
@@ -1924,8 +1922,7 @@ void ResourceProvider::DeleteAndReturnUnusedResourcesToChild(
blocking_main_thread_task_runner_);
if (child_info->marked_for_deletion &&
- child_info->parent_to_child_map.empty()) {
- DCHECK(child_info->child_to_parent_map.empty());
+ child_info->child_to_parent_map.empty()) {
children_.erase(child_it);
}
}
@@ -2177,8 +2174,8 @@ bool ResourceProvider::OnMemoryDump(
base::trace_event::MemoryAllocatorDumpGuid guid;
switch (resource.type) {
case RESOURCE_TYPE_GPU_MEMORY_BUFFER:
- guid = gfx::GetGpuMemoryBufferGUIDForTracing(
- tracing_process_id, resource.gpu_memory_buffer->GetHandle().id);
+ guid =
+ resource.gpu_memory_buffer->GetGUIDForTracing(tracing_process_id);
break;
case RESOURCE_TYPE_GL_TEXTURE:
DCHECK(resource.gl_id);
diff --git a/chromium/cc/resources/resource_provider.h b/chromium/cc/resources/resource_provider.h
index c323d4282ed..2b664ffd702 100644
--- a/chromium/cc/resources/resource_provider.h
+++ b/chromium/cc/resources/resource_provider.h
@@ -619,6 +619,7 @@ class CC_EXPORT ResourceProvider
void WaitSyncToken(gpu::gles2::GLES2Interface* gl);
int child_id;
+ ResourceId id_in_child;
unsigned gl_id;
// Pixel buffer used for set pixels without unnecessary copying.
unsigned gl_pixel_buffer_id;
@@ -696,7 +697,6 @@ class CC_EXPORT ResourceProvider
~Child();
ResourceIdMap child_to_parent_map;
- ResourceIdMap parent_to_child_map;
ReturnCallback return_callback;
bool marked_for_deletion;
bool needs_sync_tokens;
@@ -800,7 +800,7 @@ class CC_EXPORT ResourceProvider
// immediately.
bool batch_return_resources_ = false;
// Maps from a child id to the set of resources to be returned to it.
- base::SmallMap<std::map<int, ResourceIdArray>> batched_returning_resources_;
+ base::small_map<std::map<int, ResourceIdArray>> batched_returning_resources_;
base::ThreadChecker thread_checker_;
diff --git a/chromium/cc/resources/ui_resource_bitmap.cc b/chromium/cc/resources/ui_resource_bitmap.cc
index 4d8d2816175..0061e042118 100644
--- a/chromium/cc/resources/ui_resource_bitmap.cc
+++ b/chromium/cc/resources/ui_resource_bitmap.cc
@@ -36,23 +36,20 @@ UIResourceBitmap::UIResourceFormat SkColorTypeToUIResourceFormat(
} // namespace
void UIResourceBitmap::Create(sk_sp<SkPixelRef> pixel_ref,
- const gfx::Size& size,
+ const SkImageInfo& info,
UIResourceFormat format) {
- DCHECK(size.width());
- DCHECK(size.height());
+ DCHECK(info.width());
+ DCHECK(info.height());
DCHECK(pixel_ref);
DCHECK(pixel_ref->isImmutable());
format_ = format;
- size_ = size;
+ info_ = info;
pixel_ref_ = std::move(pixel_ref);
-
- // Default values for secondary parameters.
- opaque_ = (format == ETC1);
}
void UIResourceBitmap::DrawToCanvas(SkCanvas* canvas, SkPaint* paint) {
SkBitmap bitmap;
- bitmap.setInfo(pixel_ref_.get()->info(), pixel_ref_.get()->rowBytes());
+ bitmap.setInfo(info_, pixel_ref_.get()->rowBytes());
bitmap.setPixelRef(pixel_ref_, 0, 0);
canvas->drawBitmap(bitmap, 0, 0, paint);
canvas->flush();
@@ -63,11 +60,8 @@ UIResourceBitmap::UIResourceBitmap(const SkBitmap& skbitmap) {
DCHECK(skbitmap.isImmutable());
sk_sp<SkPixelRef> pixel_ref = sk_ref_sp(skbitmap.pixelRef());
- const SkImageInfo& info = pixel_ref->info();
- Create(std::move(pixel_ref), gfx::Size(info.width(), info.height()),
+ Create(std::move(pixel_ref), skbitmap.info(),
SkColorTypeToUIResourceFormat(skbitmap.colorType()));
-
- SetOpaque(skbitmap.isOpaque());
}
UIResourceBitmap::UIResourceBitmap(const gfx::Size& size, bool is_opaque) {
@@ -77,30 +71,17 @@ UIResourceBitmap::UIResourceBitmap(const gfx::Size& size, bool is_opaque) {
sk_sp<SkPixelRef> pixel_ref(
SkMallocPixelRef::MakeAllocate(info, info.minRowBytes(), NULL));
pixel_ref->setImmutable();
- Create(std::move(pixel_ref), size, UIResourceBitmap::RGBA8);
- SetOpaque(is_opaque);
+ Create(std::move(pixel_ref), info, UIResourceBitmap::RGBA8);
}
UIResourceBitmap::UIResourceBitmap(sk_sp<SkPixelRef> pixel_ref,
const gfx::Size& size) {
- Create(std::move(pixel_ref), size, UIResourceBitmap::ETC1);
+ SkImageInfo info =
+ SkImageInfo::MakeN32(size.width(), size.height(), kOpaque_SkAlphaType);
+ Create(std::move(pixel_ref), info, UIResourceBitmap::ETC1);
}
UIResourceBitmap::UIResourceBitmap(const UIResourceBitmap& other) = default;
UIResourceBitmap::~UIResourceBitmap() {}
-
-AutoLockUIResourceBitmap::AutoLockUIResourceBitmap(
- const UIResourceBitmap& bitmap) : bitmap_(bitmap) {
- bitmap_.pixel_ref_->lockPixels();
-}
-
-AutoLockUIResourceBitmap::~AutoLockUIResourceBitmap() {
- bitmap_.pixel_ref_->unlockPixels();
-}
-
-const uint8_t* AutoLockUIResourceBitmap::GetPixels() const {
- return static_cast<const uint8_t*>(bitmap_.pixel_ref_->pixels());
-}
-
} // namespace cc
diff --git a/chromium/cc/resources/ui_resource_bitmap.h b/chromium/cc/resources/ui_resource_bitmap.h
index 66a8a38d1cf..1c058e0a6f1 100644
--- a/chromium/cc/resources/ui_resource_bitmap.h
+++ b/chromium/cc/resources/ui_resource_bitmap.h
@@ -32,10 +32,9 @@ class CC_EXPORT UIResourceBitmap {
ETC1
};
- gfx::Size GetSize() const { return size_; }
+ gfx::Size GetSize() const { return gfx::Size(info_.width(), info_.height()); }
UIResourceFormat GetFormat() const { return format_; }
- bool GetOpaque() const { return opaque_; }
- void SetOpaque(bool opaque) { opaque_ = opaque; }
+ bool GetOpaque() const { return info_.isOpaque(); }
// Draw the UIResourceBitmap onto the provided |canvas| using the style
// information specified by |paint|.
@@ -51,30 +50,23 @@ class CC_EXPORT UIResourceBitmap {
// Returns the memory usage of the bitmap.
size_t EstimateMemoryUsage() const {
- return pixel_ref_ ? pixel_ref_->rowBytes() * size_.height() : 0;
+ return pixel_ref_ ? pixel_ref_->rowBytes() * info_.height() : 0;
+ }
+
+ const uint8_t* GetPixels() const {
+ return static_cast<const uint8_t*>(pixel_ref_->pixels());
}
private:
friend class AutoLockUIResourceBitmap;
void Create(sk_sp<SkPixelRef> pixel_ref,
- const gfx::Size& size,
+ const SkImageInfo& info,
UIResourceFormat format);
sk_sp<SkPixelRef> pixel_ref_;
UIResourceFormat format_;
- gfx::Size size_;
- bool opaque_;
-};
-
-class CC_EXPORT AutoLockUIResourceBitmap {
- public:
- explicit AutoLockUIResourceBitmap(const UIResourceBitmap& bitmap);
- ~AutoLockUIResourceBitmap();
- const uint8_t* GetPixels() const;
-
- private:
- const UIResourceBitmap& bitmap_;
+ SkImageInfo info_;
};
} // namespace cc
diff --git a/chromium/cc/resources/video_resource_updater.cc b/chromium/cc/resources/video_resource_updater.cc
index 1c53b32da57..9e697580d3f 100644
--- a/chromium/cc/resources/video_resource_updater.cc
+++ b/chromium/cc/resources/video_resource_updater.cc
@@ -174,8 +174,8 @@ VideoFrameExternalResources::~VideoFrameExternalResources() {}
VideoResourceUpdater::VideoResourceUpdater(ContextProvider* context_provider,
ResourceProvider* resource_provider)
: context_provider_(context_provider),
- resource_provider_(resource_provider) {
-}
+ resource_provider_(resource_provider),
+ weak_ptr_factory_(this) {}
VideoResourceUpdater::~VideoResourceUpdater() {
for (const PlaneResource& plane_resource : all_resources_)
@@ -418,8 +418,9 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes(
if (software_compositor) {
external_resources.software_resources.push_back(
plane_resource.resource_id());
- external_resources.software_release_callback = base::Bind(
- &RecycleResource, AsWeakPtr(), plane_resource.resource_id());
+ external_resources.software_release_callback =
+ base::Bind(&RecycleResource, weak_ptr_factory_.GetWeakPtr(),
+ plane_resource.resource_id());
external_resources.type = VideoFrameExternalResources::SOFTWARE_RESOURCE;
} else {
// VideoResourceUpdater shares a context with the compositor so
@@ -429,8 +430,9 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes(
plane_resource.resource_id()));
mailbox.set_color_space(output_color_space);
external_resources.mailboxes.push_back(mailbox);
- external_resources.release_callbacks.push_back(base::Bind(
- &RecycleResource, AsWeakPtr(), plane_resource.resource_id()));
+ external_resources.release_callbacks.push_back(
+ base::Bind(&RecycleResource, weak_ptr_factory_.GetWeakPtr(),
+ plane_resource.resource_id()));
external_resources.type = VideoFrameExternalResources::RGBA_RESOURCE;
}
return external_resources;
@@ -532,8 +534,9 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForSoftwarePlanes(
plane_resource.resource_id()));
mailbox.set_color_space(output_color_space);
external_resources.mailboxes.push_back(mailbox);
- external_resources.release_callbacks.push_back(base::Bind(
- &RecycleResource, AsWeakPtr(), plane_resource.resource_id()));
+ external_resources.release_callbacks.push_back(
+ base::Bind(&RecycleResource, weak_ptr_factory_.GetWeakPtr(),
+ plane_resource.resource_id()));
}
external_resources.type = VideoFrameExternalResources::YUV_RESOURCE;
@@ -609,7 +612,8 @@ void VideoResourceUpdater::CopyPlaneTexture(
external_resources->mailboxes.push_back(mailbox);
external_resources->release_callbacks.push_back(
- base::Bind(&RecycleResource, AsWeakPtr(), resource->resource_id()));
+ base::Bind(&RecycleResource, weak_ptr_factory_.GetWeakPtr(),
+ resource->resource_id()));
}
VideoFrameExternalResources VideoResourceUpdater::CreateForHardwarePlanes(
@@ -660,8 +664,8 @@ VideoFrameExternalResources VideoResourceUpdater::CreateForHardwarePlanes(
media::VideoFrameMetadata::WANTS_PROMOTION_HINT));
#endif
external_resources.mailboxes.push_back(mailbox);
- external_resources.release_callbacks.push_back(
- base::Bind(&ReturnTexture, AsWeakPtr(), video_frame));
+ external_resources.release_callbacks.push_back(base::Bind(
+ &ReturnTexture, weak_ptr_factory_.GetWeakPtr(), video_frame));
}
}
return external_resources;
diff --git a/chromium/cc/resources/video_resource_updater.h b/chromium/cc/resources/video_resource_updater.h
index 603b4a35d09..f5f949c7d6d 100644
--- a/chromium/cc/resources/video_resource_updater.h
+++ b/chromium/cc/resources/video_resource_updater.h
@@ -70,8 +70,7 @@ class CC_EXPORT VideoFrameExternalResources {
// VideoResourceUpdater is used by the video system to produce frame content as
// resources consumable by the compositor.
-class CC_EXPORT VideoResourceUpdater
- : public base::SupportsWeakPtr<VideoResourceUpdater> {
+class CC_EXPORT VideoResourceUpdater {
public:
VideoResourceUpdater(ContextProvider* context_provider,
ResourceProvider* resource_provider);
@@ -183,6 +182,8 @@ class CC_EXPORT VideoResourceUpdater
// data transfers.
ResourceList all_resources_;
+ base::WeakPtrFactory<VideoResourceUpdater> weak_ptr_factory_;
+
DISALLOW_COPY_AND_ASSIGN(VideoResourceUpdater);
};
diff --git a/chromium/cc/scheduler/begin_frame_source.cc b/chromium/cc/scheduler/begin_frame_source.cc
index 4db7202a02c..be6394e617a 100644
--- a/chromium/cc/scheduler/begin_frame_source.cc
+++ b/chromium/cc/scheduler/begin_frame_source.cc
@@ -27,9 +27,9 @@ static const double kDoubleTickDivisor = 2.0;
}
// BeginFrameObserverBase -------------------------------------------------
-BeginFrameObserverBase::BeginFrameObserverBase()
- : last_begin_frame_args_(), dropped_begin_frame_args_(0) {
-}
+BeginFrameObserverBase::BeginFrameObserverBase() = default;
+
+BeginFrameObserverBase::~BeginFrameObserverBase() = default;
const BeginFrameArgs& BeginFrameObserverBase::LastUsedBeginFrameArgs() const {
return last_begin_frame_args_;
@@ -50,6 +50,15 @@ void BeginFrameObserverBase::OnBeginFrame(const BeginFrameArgs& args) {
}
}
+void BeginFrameObserverBase::AsValueInto(
+ base::trace_event::TracedValue* state) const {
+ state->SetInteger("dropped_begin_frame_args", dropped_begin_frame_args_);
+
+ state->BeginDictionary("last_begin_frame_args");
+ last_begin_frame_args_.AsValueInto(state);
+ state->EndDictionary();
+}
+
// BeginFrameSource -------------------------------------------------------
namespace {
static base::StaticAtomicSequenceNumber g_next_source_id;
@@ -57,8 +66,11 @@ static base::StaticAtomicSequenceNumber g_next_source_id;
BeginFrameSource::BeginFrameSource() : source_id_(g_next_source_id.GetNext()) {}
-uint32_t BeginFrameSource::source_id() const {
- return source_id_;
+BeginFrameSource::~BeginFrameSource() = default;
+
+void BeginFrameSource::AsValueInto(
+ base::trace_event::TracedValue* state) const {
+ state->SetInteger("source_id", source_id_);
}
// StubBeginFrameSource ---------------------------------------------------
@@ -240,100 +252,6 @@ void DelayBasedBeginFrameSource::OnTimerTick() {
}
}
-// BeginFrameObserverAckTracker -------------------------------------------
-BeginFrameObserverAckTracker::BeginFrameObserverAckTracker()
- : current_source_id_(0),
- current_sequence_number_(BeginFrameArgs::kStartingFrameNumber),
- observers_had_damage_(false) {}
-
-BeginFrameObserverAckTracker::~BeginFrameObserverAckTracker() {}
-
-void BeginFrameObserverAckTracker::OnBeginFrame(const BeginFrameArgs& args) {
- if (current_source_id_ != args.source_id)
- SourceChanged(args);
-
- DCHECK_GE(args.sequence_number, current_sequence_number_);
- // Reset for new BeginFrame.
- current_sequence_number_ = args.sequence_number;
- finished_observers_.clear();
- observers_had_damage_ = false;
-}
-
-void BeginFrameObserverAckTracker::SourceChanged(const BeginFrameArgs& args) {
- current_source_id_ = args.source_id;
- current_sequence_number_ = args.sequence_number;
-
- // Mark all observers invalid: We report an invalid frame until every observer
- // has confirmed the frame.
- for (auto& entry : latest_confirmed_sequence_numbers_)
- entry.second = BeginFrameArgs::kInvalidFrameNumber;
-}
-
-void BeginFrameObserverAckTracker::OnObserverFinishedFrame(
- BeginFrameObserver* obs,
- const BeginFrameAck& ack) {
- if (ack.source_id != current_source_id_)
- return;
-
- DCHECK_LE(ack.sequence_number, current_sequence_number_);
- if (ack.sequence_number != current_sequence_number_)
- return;
-
- finished_observers_.insert(obs);
- observers_had_damage_ |= ack.has_damage;
-
- // We max() with the current value in |latest_confirmed_sequence_numbers_| to
- // handle situations where an observer just started observing (again) and may
- // acknowledge with an ancient latest_confirmed_sequence_number.
- latest_confirmed_sequence_numbers_[obs] =
- std::max(ack.latest_confirmed_sequence_number,
- latest_confirmed_sequence_numbers_[obs]);
-}
-
-void BeginFrameObserverAckTracker::OnObserverAdded(BeginFrameObserver* obs) {
- observers_.insert(obs);
-
- // Since the observer didn't want BeginFrames before, we consider it
- // up-to-date up to the last BeginFrame, except if it already handled the
- // current BeginFrame. In which case, we consider it up-to-date up to the
- // current one.
- DCHECK_LT(BeginFrameArgs::kInvalidFrameNumber, current_sequence_number_);
- const BeginFrameArgs& last_args = obs->LastUsedBeginFrameArgs();
- if (last_args.IsValid() &&
- last_args.sequence_number == current_sequence_number_ &&
- last_args.source_id == current_source_id_) {
- latest_confirmed_sequence_numbers_[obs] = current_sequence_number_;
- finished_observers_.insert(obs);
- } else {
- latest_confirmed_sequence_numbers_[obs] = current_sequence_number_ - 1;
- }
-}
-
-void BeginFrameObserverAckTracker::OnObserverRemoved(BeginFrameObserver* obs) {
- observers_.erase(obs);
- finished_observers_.erase(obs);
- latest_confirmed_sequence_numbers_.erase(obs);
-}
-
-bool BeginFrameObserverAckTracker::AllObserversFinishedFrame() const {
- if (finished_observers_.size() < observers_.size())
- return false;
- return base::STLIncludes(finished_observers_, observers_);
-}
-
-bool BeginFrameObserverAckTracker::AnyObserversHadDamage() const {
- return observers_had_damage_;
-}
-
-uint64_t BeginFrameObserverAckTracker::LatestConfirmedSequenceNumber() const {
- uint64_t latest_confirmed_sequence_number = current_sequence_number_;
- for (const auto& entry : latest_confirmed_sequence_numbers_) {
- latest_confirmed_sequence_number =
- std::min(latest_confirmed_sequence_number, entry.second);
- }
- return latest_confirmed_sequence_number;
-}
-
// ExternalBeginFrameSource -----------------------------------------------
ExternalBeginFrameSource::ExternalBeginFrameSource(
ExternalBeginFrameSourceClient* client)
@@ -343,28 +261,41 @@ ExternalBeginFrameSource::ExternalBeginFrameSource(
ExternalBeginFrameSource::~ExternalBeginFrameSource() = default;
+void ExternalBeginFrameSource::AsValueInto(
+ base::trace_event::TracedValue* state) const {
+ BeginFrameSource::AsValueInto(state);
+
+ state->SetBoolean("paused", paused_);
+ state->SetInteger("num_observers", observers_.size());
+
+ state->BeginDictionary("last_begin_frame_args");
+ last_begin_frame_args_.AsValueInto(state);
+ state->EndDictionary();
+}
+
void ExternalBeginFrameSource::AddObserver(BeginFrameObserver* obs) {
DCHECK(obs);
DCHECK(observers_.find(obs) == observers_.end());
bool observers_was_empty = observers_.empty();
observers_.insert(obs);
- ack_tracker_.OnObserverAdded(obs);
obs->OnBeginFrameSourcePausedChanged(paused_);
if (observers_was_empty)
client_->OnNeedsBeginFrames(true);
// Send a MISSED begin frame if necessary.
- if (missed_begin_frame_args_.IsValid()) {
+ if (last_begin_frame_args_.IsValid()) {
const BeginFrameArgs& last_args = obs->LastUsedBeginFrameArgs();
if (!last_args.IsValid() ||
- (missed_begin_frame_args_.frame_time > last_args.frame_time)) {
- DCHECK((missed_begin_frame_args_.source_id != last_args.source_id) ||
- (missed_begin_frame_args_.sequence_number >
- last_args.sequence_number))
- << "current " << missed_begin_frame_args_.AsValue()->ToString()
+ (last_begin_frame_args_.frame_time > last_args.frame_time)) {
+ DCHECK(
+ (last_begin_frame_args_.source_id != last_args.source_id) ||
+ (last_begin_frame_args_.sequence_number > last_args.sequence_number))
+ << "current " << last_begin_frame_args_.AsValue()->ToString()
<< ", last " << last_args.AsValue()->ToString();
- obs->OnBeginFrame(missed_begin_frame_args_);
+ BeginFrameArgs missed_args = last_begin_frame_args_;
+ missed_args.type = BeginFrameArgs::MISSED;
+ obs->OnBeginFrame(missed_args);
}
}
}
@@ -374,19 +305,14 @@ void ExternalBeginFrameSource::RemoveObserver(BeginFrameObserver* obs) {
DCHECK(observers_.find(obs) != observers_.end());
observers_.erase(obs);
- ack_tracker_.OnObserverRemoved(obs);
- MaybeFinishFrame();
if (observers_.empty()) {
- missed_begin_frame_args_ = BeginFrameArgs();
+ last_begin_frame_args_ = BeginFrameArgs();
client_->OnNeedsBeginFrames(false);
}
}
void ExternalBeginFrameSource::DidFinishFrame(BeginFrameObserver* obs,
- const BeginFrameAck& ack) {
- ack_tracker_.OnObserverFinishedFrame(obs, ack);
- MaybeFinishFrame();
-}
+ const BeginFrameAck& ack) {}
bool ExternalBeginFrameSource::IsThrottled() const {
return true;
@@ -402,13 +328,7 @@ void ExternalBeginFrameSource::OnSetBeginFrameSourcePaused(bool paused) {
}
void ExternalBeginFrameSource::OnBeginFrame(const BeginFrameArgs& args) {
- if (frame_active_)
- FinishFrame();
-
- frame_active_ = true;
- missed_begin_frame_args_ = args;
- missed_begin_frame_args_.type = BeginFrameArgs::MISSED;
- ack_tracker_.OnBeginFrame(args);
+ last_begin_frame_args_ = args;
std::unordered_set<BeginFrameObserver*> observers(observers_);
for (auto* obs : observers) {
// It is possible that the source in which |args| originate changes, or that
@@ -423,23 +343,6 @@ void ExternalBeginFrameSource::OnBeginFrame(const BeginFrameArgs& args) {
obs->OnBeginFrame(args);
}
}
- MaybeFinishFrame();
-}
-
-void ExternalBeginFrameSource::MaybeFinishFrame() {
- if (!frame_active_ || !ack_tracker_.AllObserversFinishedFrame())
- return;
- FinishFrame();
-}
-
-void ExternalBeginFrameSource::FinishFrame() {
- frame_active_ = false;
-
- BeginFrameAck ack(missed_begin_frame_args_.source_id,
- missed_begin_frame_args_.sequence_number,
- ack_tracker_.LatestConfirmedSequenceNumber(),
- ack_tracker_.AnyObserversHadDamage());
- client_->OnDidFinishFrame(ack);
}
} // namespace cc
diff --git a/chromium/cc/scheduler/begin_frame_source.h b/chromium/cc/scheduler/begin_frame_source.h
index 9d5ce242b27..98ea3771b39 100644
--- a/chromium/cc/scheduler/begin_frame_source.h
+++ b/chromium/cc/scheduler/begin_frame_source.h
@@ -74,6 +74,7 @@ class CC_EXPORT BeginFrameObserver {
class CC_EXPORT BeginFrameObserverBase : public BeginFrameObserver {
public:
BeginFrameObserverBase();
+ ~BeginFrameObserverBase() override;
// BeginFrameObserver
@@ -84,12 +85,13 @@ class CC_EXPORT BeginFrameObserverBase : public BeginFrameObserver {
const BeginFrameArgs& LastUsedBeginFrameArgs() const override;
protected:
- // Subclasses should override this method!
// Return true if the given argument is (or will be) used.
virtual bool OnBeginFrameDerivedImpl(const BeginFrameArgs& args) = 0;
+ void AsValueInto(base::trace_event::TracedValue* state) const;
+
BeginFrameArgs last_begin_frame_args_;
- int64_t dropped_begin_frame_args_;
+ int64_t dropped_begin_frame_args_ = 0;
private:
DISALLOW_COPY_AND_ASSIGN(BeginFrameObserverBase);
@@ -107,7 +109,13 @@ class CC_EXPORT BeginFrameObserverBase : public BeginFrameObserver {
class CC_EXPORT BeginFrameSource {
public:
BeginFrameSource();
- virtual ~BeginFrameSource() {}
+ virtual ~BeginFrameSource();
+
+ // Returns an identifier for this BeginFrameSource. Guaranteed unique within a
+ // process, but not across processes. This is used to create BeginFrames that
+ // originate at this source. Note that BeginFrameSources may pass on
+ // BeginFrames created by other sources, with different IDs.
+ uint32_t source_id() const { return source_id_; }
// BeginFrameObservers use DidFinishFrame to acknowledge that they have
// completed handling a BeginFrame.
@@ -138,14 +146,12 @@ class CC_EXPORT BeginFrameSource {
// begin frames without waiting.
virtual bool IsThrottled() const = 0;
- // Returns an identifier for this BeginFrameSource. Guaranteed unique within a
- // process, but not across processes. This is used to create BeginFrames that
- // originate at this source. Note that BeginFrameSources may pass on
- // BeginFrames created by other sources, with different IDs.
- uint32_t source_id() const;
+ virtual void AsValueInto(base::trace_event::TracedValue* state) const;
private:
uint32_t source_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(BeginFrameSource);
};
// A BeginFrameSource that does nothing.
@@ -241,50 +247,10 @@ class CC_EXPORT DelayBasedBeginFrameSource : public SyntheticBeginFrameSource,
DISALLOW_COPY_AND_ASSIGN(DelayBasedBeginFrameSource);
};
-// Helper class that tracks outstanding acknowledgments from
-// BeginFrameObservers.
-class CC_EXPORT BeginFrameObserverAckTracker {
- public:
- BeginFrameObserverAckTracker();
- virtual ~BeginFrameObserverAckTracker();
-
- // The BeginFrameSource uses these methods to notify us when a BeginFrame was
- // started, an observer finished a frame, or an observer was added/removed.
- void OnBeginFrame(const BeginFrameArgs& args);
- void OnObserverFinishedFrame(BeginFrameObserver* obs,
- const BeginFrameAck& ack);
- void OnObserverAdded(BeginFrameObserver* obs);
- void OnObserverRemoved(BeginFrameObserver* obs);
-
- // Returns |true| if all the source's observers completed the current frame.
- bool AllObserversFinishedFrame() const;
-
- // Returns |true| if any observer had damage during the current frame.
- bool AnyObserversHadDamage() const;
-
- // Return the sequence number of the latest frame that all active observers
- // have confirmed.
- uint64_t LatestConfirmedSequenceNumber() const;
-
- private:
- void SourceChanged(const BeginFrameArgs& args);
-
- uint32_t current_source_id_;
- uint64_t current_sequence_number_;
- // Small sets, but order matters for intersection computation.
- base::flat_set<BeginFrameObserver*> observers_;
- base::flat_set<BeginFrameObserver*> finished_observers_;
- bool observers_had_damage_;
- base::SmallMap<std::map<BeginFrameObserver*, uint64_t>, 4>
- latest_confirmed_sequence_numbers_;
-};
-
class CC_EXPORT ExternalBeginFrameSourceClient {
public:
// Only called when changed. Assumed false by default.
virtual void OnNeedsBeginFrames(bool needs_begin_frames) = 0;
- // Called when all observers have completed a frame.
- virtual void OnDidFinishFrame(const BeginFrameAck& ack) = 0;
};
// A BeginFrameSource that is only ticked manually. Usually the endpoint
@@ -303,20 +269,16 @@ class CC_EXPORT ExternalBeginFrameSource : public BeginFrameSource {
void DidFinishFrame(BeginFrameObserver* obs,
const BeginFrameAck& ack) override;
bool IsThrottled() const override;
+ void AsValueInto(base::trace_event::TracedValue* state) const override;
void OnSetBeginFrameSourcePaused(bool paused);
void OnBeginFrame(const BeginFrameArgs& args);
protected:
- void MaybeFinishFrame();
- void FinishFrame();
-
- BeginFrameArgs missed_begin_frame_args_;
+ BeginFrameArgs last_begin_frame_args_;
std::unordered_set<BeginFrameObserver*> observers_;
ExternalBeginFrameSourceClient* client_;
bool paused_ = false;
- bool frame_active_ = false;
- BeginFrameObserverAckTracker ack_tracker_;
private:
DISALLOW_COPY_AND_ASSIGN(ExternalBeginFrameSource);
diff --git a/chromium/cc/scheduler/begin_frame_source_unittest.cc b/chromium/cc/scheduler/begin_frame_source_unittest.cc
index a15c4be4ebb..a6884d35cf7 100644
--- a/chromium/cc/scheduler/begin_frame_source_unittest.cc
+++ b/chromium/cc/scheduler/begin_frame_source_unittest.cc
@@ -14,7 +14,7 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-using testing::StrictMock;
+using testing::NiceMock;
namespace cc {
namespace {
@@ -44,7 +44,7 @@ class BackToBackBeginFrameSourceTest : public ::testing::Test {
new TestDelayBasedTimeSource(now_src_.get(), task_runner_.get()));
delay_based_time_source_ = time_source.get();
source_.reset(new BackToBackBeginFrameSource(std::move(time_source)));
- obs_ = base::WrapUnique(new ::testing::StrictMock<MockBeginFrameObserver>);
+ obs_ = base::WrapUnique(new ::testing::NiceMock<MockBeginFrameObserver>);
}
void TearDown() override { obs_.reset(); }
@@ -230,7 +230,7 @@ TEST_F(BackToBackBeginFrameSourceTest, DelayInPostedTaskProducesCorrectFrame) {
}
TEST_F(BackToBackBeginFrameSourceTest, MultipleObserversSynchronized) {
- StrictMock<MockBeginFrameObserver> obs1, obs2;
+ NiceMock<MockBeginFrameObserver> obs1, obs2;
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs1, false);
source_->AddObserver(&obs1);
@@ -266,7 +266,7 @@ TEST_F(BackToBackBeginFrameSourceTest, MultipleObserversSynchronized) {
}
TEST_F(BackToBackBeginFrameSourceTest, MultipleObserversInterleaved) {
- StrictMock<MockBeginFrameObserver> obs1, obs2;
+ NiceMock<MockBeginFrameObserver> obs1, obs2;
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs1, false);
source_->AddObserver(&obs1);
@@ -310,7 +310,7 @@ TEST_F(BackToBackBeginFrameSourceTest, MultipleObserversInterleaved) {
}
TEST_F(BackToBackBeginFrameSourceTest, MultipleObserversAtOnce) {
- StrictMock<MockBeginFrameObserver> obs1, obs2;
+ NiceMock<MockBeginFrameObserver> obs1, obs2;
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs1, false);
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs2, false);
@@ -462,7 +462,7 @@ TEST_F(DelayBasedBeginFrameSourceTest, AuthoritativeVSyncChanges) {
}
TEST_F(DelayBasedBeginFrameSourceTest, MultipleObservers) {
- StrictMock<MockBeginFrameObserver> obs1, obs2;
+ NiceMock<MockBeginFrameObserver> obs1, obs2;
// now_src_ starts off at 1000.
task_runner_->RunForPeriod(base::TimeDelta::FromMicroseconds(9010));
@@ -497,7 +497,7 @@ TEST_F(DelayBasedBeginFrameSourceTest, MultipleObservers) {
}
TEST_F(DelayBasedBeginFrameSourceTest, DoubleTick) {
- StrictMock<MockBeginFrameObserver> obs;
+ NiceMock<MockBeginFrameObserver> obs;
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, false);
EXPECT_BEGIN_FRAME_USED_MISSED(obs, source_->source_id(), 1, 0, 10000, 10000);
@@ -519,7 +519,7 @@ TEST_F(DelayBasedBeginFrameSourceTest, DoubleTick) {
}
TEST_F(DelayBasedBeginFrameSourceTest, DoubleTickMissedFrame) {
- StrictMock<MockBeginFrameObserver> obs;
+ NiceMock<MockBeginFrameObserver> obs;
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(obs, false);
EXPECT_BEGIN_FRAME_USED_MISSED(obs, source_->source_id(), 1, 0, 10000, 10000);
@@ -550,224 +550,11 @@ TEST_F(DelayBasedBeginFrameSourceTest, DoubleTickMissedFrame) {
source_->RemoveObserver(&obs);
}
-// BeginFrameObserverAckTracker testing ----------------------------------------
-class TestBeginFrameConsumer : public BeginFrameObserverBase {
- private:
- bool OnBeginFrameDerivedImpl(const BeginFrameArgs& args) override {
- // Consume the args.
- return true;
- }
- void OnBeginFrameSourcePausedChanged(bool paused) override {}
-};
-
-// Use EXPECT_TRUE instead of EXPECT_EQ for |finished| and |damage| as gcc 4.7
-// issues the following warning on EXPECT_EQ(false, x), which is turned into an
-// error with -Werror=conversion-null:
-//
-// converting 'false' to pointer type for argument 1 of
-// 'char testing::internal::IsNullLiteralHelper(testing::internal::Secret*)'
-#define EXPECT_ACK_TRACKER_STATE(finished, damage, latest_confirmed) \
- EXPECT_TRUE(finished == tracker_->AllObserversFinishedFrame()) \
- << "expected: " << finished; \
- EXPECT_TRUE(damage == tracker_->AnyObserversHadDamage()) << "expected: " \
- << damage; \
- EXPECT_EQ(latest_confirmed, tracker_->LatestConfirmedSequenceNumber())
-
-class BeginFrameObserverAckTrackerTest : public ::testing::Test {
- public:
- BeginFrameArgs current_args_;
- std::unique_ptr<BeginFrameObserverAckTracker> tracker_;
- TestBeginFrameConsumer obs1_;
- TestBeginFrameConsumer obs2_;
-
- void SetUp() override {
- current_args_ = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1);
- tracker_.reset(new BeginFrameObserverAckTracker());
- }
-};
-
-TEST_F(BeginFrameObserverAckTrackerTest, CorrectnessWithoutObservers) {
- // Check initial state.
- EXPECT_ACK_TRACKER_STATE(true, false, 1u);
-
- // A new BeginFrame is immediately finished and confirmed.
- current_args_ = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 2);
- tracker_->OnBeginFrame(current_args_);
- EXPECT_ACK_TRACKER_STATE(true, false, 2u);
-}
-
-TEST_F(BeginFrameObserverAckTrackerTest, CorrectnessWith1Observer) {
- // Check initial state.
- EXPECT_ACK_TRACKER_STATE(true, false, 1u);
-
- // After adding an observer, the BeginFrame is not finished or confirmed.
- tracker_->OnObserverAdded(&obs1_);
- EXPECT_ACK_TRACKER_STATE(false, false, 0u); // up to date to previous frame.
-
- // On removing it, the BeginFrame is back to original state.
- tracker_->OnObserverRemoved(&obs1_);
- EXPECT_ACK_TRACKER_STATE(true, false, 1u);
-
- // After adding it back, the BeginFrame is again not finished or confirmed.
- tracker_->OnObserverAdded(&obs1_);
- EXPECT_ACK_TRACKER_STATE(false, false, 0u); // up to date to previous frame.
-
- // When the observer finishes and confirms, the BeginFrame is finished
- // and confirmed.
- obs1_.OnBeginFrame(current_args_);
- tracker_->OnObserverFinishedFrame(&obs1_, BeginFrameAck(0, 1, 1, false));
- EXPECT_ACK_TRACKER_STATE(true, false, 1u);
-
- // A new BeginFrame is initially not finished or confirmed.
- current_args_ = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 2);
- tracker_->OnBeginFrame(current_args_);
- EXPECT_ACK_TRACKER_STATE(false, false, 1u);
-
- // Stray ACK for an old BeginFrame is ignored.
- tracker_->OnObserverFinishedFrame(&obs1_, BeginFrameAck(0, 1, 1, false));
- EXPECT_ACK_TRACKER_STATE(false, false, 1u);
-
- // When the observer finishes but doesn't confirm, the BeginFrame is finished
- // but not confirmed.
- obs1_.OnBeginFrame(current_args_);
- tracker_->OnObserverFinishedFrame(&obs1_, BeginFrameAck(0, 2, 1, false));
- EXPECT_ACK_TRACKER_STATE(true, false, 1u);
-
- // Damage from ACK propagates.
- current_args_ = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 3);
- tracker_->OnBeginFrame(current_args_);
- EXPECT_ACK_TRACKER_STATE(false, false, 1u);
- obs1_.OnBeginFrame(current_args_);
- tracker_->OnObserverFinishedFrame(&obs1_, BeginFrameAck(0, 3, 3, true));
- EXPECT_ACK_TRACKER_STATE(true, true, 3u);
-
- // Removing an out-of-date observer confirms the latest BeginFrame.
- current_args_ = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 4);
- tracker_->OnBeginFrame(current_args_);
- EXPECT_ACK_TRACKER_STATE(false, false, 3u);
- obs1_.OnBeginFrame(current_args_);
- tracker_->OnObserverFinishedFrame(&obs1_, BeginFrameAck(0, 4, 3, false));
- EXPECT_ACK_TRACKER_STATE(true, false, 3u);
- tracker_->OnObserverRemoved(&obs1_);
- EXPECT_ACK_TRACKER_STATE(true, false, 4u);
-}
-
-TEST_F(BeginFrameObserverAckTrackerTest, CorrectnessWith2Observers) {
- // Check initial state.
- EXPECT_ACK_TRACKER_STATE(true, false, 1u);
-
- // After adding observers, the BeginFrame is not finished or confirmed.
- tracker_->OnObserverAdded(&obs1_);
- EXPECT_ACK_TRACKER_STATE(false, false, 0u); // up to date to previous frame.
- tracker_->OnObserverAdded(&obs2_);
- EXPECT_ACK_TRACKER_STATE(false, false, 0u); // up to date to previous frame.
-
- // Removing one of them changes nothing. Same for adding back.
- tracker_->OnObserverRemoved(&obs1_);
- EXPECT_ACK_TRACKER_STATE(false, false, 0u);
- tracker_->OnObserverAdded(&obs1_);
- EXPECT_ACK_TRACKER_STATE(false, false, 0u);
-
- // When one observer finishes and confirms, nothing changes.
- obs1_.OnBeginFrame(current_args_);
- tracker_->OnObserverFinishedFrame(&obs1_, BeginFrameAck(0, 1, 1, false));
- EXPECT_ACK_TRACKER_STATE(false, false, 0u);
- // When both finish and confirm, the BeginFrame is finished and confirmed.
- obs2_.OnBeginFrame(current_args_);
- tracker_->OnObserverFinishedFrame(&obs2_, BeginFrameAck(0, 1, 1, false));
- EXPECT_ACK_TRACKER_STATE(true, false, 1u);
-
- // A new BeginFrame is not finished or confirmed.
- current_args_ = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 2);
- tracker_->OnBeginFrame(current_args_);
- EXPECT_ACK_TRACKER_STATE(false, false, 1u);
-
- // When both observers finish but only one confirms, the BeginFrame is
- // finished but not confirmed.
- obs1_.OnBeginFrame(current_args_);
- tracker_->OnObserverFinishedFrame(&obs1_, BeginFrameAck(0, 2, 2, false));
- EXPECT_ACK_TRACKER_STATE(false, false, 1u);
- obs2_.OnBeginFrame(current_args_);
- tracker_->OnObserverFinishedFrame(&obs2_, BeginFrameAck(0, 2, 1, false));
- EXPECT_ACK_TRACKER_STATE(true, false, 1u);
-
- // With reversed confirmations in the next ACKs, the latest confirmed frame
- // increases but the latest BeginFrame remains unconfirmed.
- current_args_ = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 3);
- tracker_->OnBeginFrame(current_args_);
- EXPECT_ACK_TRACKER_STATE(false, false, 1u);
- obs1_.OnBeginFrame(current_args_);
- tracker_->OnObserverFinishedFrame(&obs1_, BeginFrameAck(0, 3, 2, false));
- EXPECT_ACK_TRACKER_STATE(false, false, 1u);
- obs2_.OnBeginFrame(current_args_);
- tracker_->OnObserverFinishedFrame(&obs2_, BeginFrameAck(0, 3, 3, false));
- EXPECT_ACK_TRACKER_STATE(true, false, 2u);
-
- // Only a single ACK with damage suffices.
- current_args_ = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 4);
- tracker_->OnBeginFrame(current_args_);
- EXPECT_ACK_TRACKER_STATE(false, false, 2u);
- obs1_.OnBeginFrame(current_args_);
- tracker_->OnObserverFinishedFrame(&obs1_, BeginFrameAck(0, 4, 4, true));
- EXPECT_ACK_TRACKER_STATE(false, true, 3u);
- obs2_.OnBeginFrame(current_args_);
- tracker_->OnObserverFinishedFrame(&obs2_, BeginFrameAck(0, 4, 4, false));
- EXPECT_ACK_TRACKER_STATE(true, true, 4u);
-
- // Removing the damaging observer makes no difference in this case.
- tracker_->OnObserverRemoved(&obs1_);
- EXPECT_ACK_TRACKER_STATE(true, true, 4u);
-
- // Adding the observer back considers it up to date up to the current
- // BeginFrame, because it is the last used one. Thus, the current BeginFrame
- // is still finished, too.
- tracker_->OnObserverAdded(&obs1_);
- EXPECT_ACK_TRACKER_STATE(true, true, 4u);
-
- // Adding the observer back after the next BeginFrame considers it up to date
- // up to last BeginFrame only.
- tracker_->OnObserverRemoved(&obs1_);
- current_args_ = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 5);
- tracker_->OnBeginFrame(current_args_);
- tracker_->OnObserverAdded(&obs1_);
- EXPECT_ACK_TRACKER_STATE(false, false, 4u);
- // Both observers need to finish for the BeginFrame to be finished.
- obs1_.OnBeginFrame(current_args_);
- tracker_->OnObserverFinishedFrame(&obs1_, BeginFrameAck(0, 5, 5, false));
- EXPECT_ACK_TRACKER_STATE(false, false, 4u);
- obs2_.OnBeginFrame(current_args_);
- tracker_->OnObserverFinishedFrame(&obs2_, BeginFrameAck(0, 5, 5, false));
- EXPECT_ACK_TRACKER_STATE(true, false, 5u);
-}
-
-TEST_F(BeginFrameObserverAckTrackerTest, ChangingSourceIdOnBeginFrame) {
- // Check initial state.
- EXPECT_ACK_TRACKER_STATE(true, false, 1u);
-
- // Changing source id without observer updates confirmed BeginFrame.
- current_args_ = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 1, 10);
- tracker_->OnBeginFrame(current_args_);
- EXPECT_ACK_TRACKER_STATE(true, false, 10u);
-
- // Setup an observer for current BeginFrame.
- tracker_->OnObserverAdded(&obs1_);
- EXPECT_ACK_TRACKER_STATE(false, false, 9u); // up to date to previous frame.
- obs1_.OnBeginFrame(current_args_);
- tracker_->OnObserverFinishedFrame(&obs1_, BeginFrameAck(1, 10, 10, true));
- EXPECT_ACK_TRACKER_STATE(true, true, 10u);
-
- // Changing source id with an observer sets confirmed BeginFrame to invalid.
- current_args_ = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 2, 20);
- tracker_->OnBeginFrame(current_args_);
- EXPECT_ACK_TRACKER_STATE(false, false, BeginFrameArgs::kInvalidFrameNumber);
-}
-
// ExternalBeginFrameSource testing --------------------------------------------
class MockExternalBeginFrameSourceClient
: public ExternalBeginFrameSourceClient {
public:
MOCK_METHOD1(OnNeedsBeginFrames, void(bool));
- MOCK_METHOD1(OnDidFinishFrame, void(const BeginFrameAck&));
};
class ExternalBeginFrameSourceTest : public ::testing::Test {
@@ -788,69 +575,6 @@ class ExternalBeginFrameSourceTest : public ::testing::Test {
}
};
-TEST_F(ExternalBeginFrameSourceTest, CallsOnDidFinishFrameWithoutObservers) {
- EXPECT_CALL((*client_), OnDidFinishFrame(BeginFrameAck(0, 2, 2, false)))
- .Times(1);
- source_->OnBeginFrame(CreateBeginFrameArgsForTesting(
- BEGINFRAME_FROM_HERE, 0, 2, base::TimeTicks::FromInternalValue(10000)));
-}
-
-TEST_F(ExternalBeginFrameSourceTest,
- CallsOnDidFinishFrameWhenObserverFinishes) {
- EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
- EXPECT_CALL((*client_), OnNeedsBeginFrames(true)).Times(1);
- source_->AddObserver(obs_.get());
-
- BeginFrameArgs args = CreateBeginFrameArgsForTesting(
- BEGINFRAME_FROM_HERE, 0, 2, base::TimeTicks::FromInternalValue(10000));
- EXPECT_BEGIN_FRAME_ARGS_USED(*obs_, args);
- source_->OnBeginFrame(args);
-
- EXPECT_CALL((*client_), OnDidFinishFrame(BeginFrameAck(0, 2, 2, true)))
- .Times(1);
- source_->DidFinishFrame(obs_.get(), BeginFrameAck(0, 2, 2, true));
-
- args = CreateBeginFrameArgsForTesting(
- BEGINFRAME_FROM_HERE, 0, 3, base::TimeTicks::FromInternalValue(20000));
- EXPECT_BEGIN_FRAME_ARGS_USED(*obs_, args);
- source_->OnBeginFrame(args);
-
- EXPECT_CALL((*client_), OnDidFinishFrame(BeginFrameAck(0, 3, 2, false)))
- .Times(1);
- source_->DidFinishFrame(obs_.get(), BeginFrameAck(0, 3, 2, false));
-}
-
-TEST_F(ExternalBeginFrameSourceTest,
- CallsOnDidFinishFrameWhenObserverDropsBeginFrame) {
- EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
- EXPECT_CALL((*client_), OnNeedsBeginFrames(true)).Times(1);
- source_->AddObserver(obs_.get());
-
- BeginFrameArgs args = CreateBeginFrameArgsForTesting(
- BEGINFRAME_FROM_HERE, 0, 2, base::TimeTicks::FromInternalValue(10000));
- EXPECT_BEGIN_FRAME_ARGS_DROP(*obs_, args);
- source_->OnBeginFrame(args);
- EXPECT_CALL((*client_), OnDidFinishFrame(BeginFrameAck(0, 2, 0, false)))
- .Times(1);
- source_->DidFinishFrame(obs_.get(), BeginFrameAck(0, 2, 0, false));
-}
-
-TEST_F(ExternalBeginFrameSourceTest, CallsOnDidFinishFrameWhenObserverRemoved) {
- EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
- EXPECT_CALL((*client_), OnNeedsBeginFrames(true)).Times(1);
- source_->AddObserver(obs_.get());
-
- BeginFrameArgs args = CreateBeginFrameArgsForTesting(
- BEGINFRAME_FROM_HERE, 0, 2, base::TimeTicks::FromInternalValue(10000));
- EXPECT_BEGIN_FRAME_ARGS_USED(*obs_, args);
- source_->OnBeginFrame(args);
-
- EXPECT_CALL((*client_), OnDidFinishFrame(BeginFrameAck(0, 2, 2, false)))
- .Times(1);
- EXPECT_CALL((*client_), OnNeedsBeginFrames(false)).Times(1);
- source_->RemoveObserver(obs_.get());
-}
-
// https://crbug.com/690127: Duplicate BeginFrame caused DCHECK crash.
TEST_F(ExternalBeginFrameSourceTest, OnBeginFrameChecksBeginFrameContinuity) {
EXPECT_BEGIN_FRAME_SOURCE_PAUSED(*obs_, false);
@@ -863,8 +587,6 @@ TEST_F(ExternalBeginFrameSourceTest, OnBeginFrameChecksBeginFrameContinuity) {
source_->OnBeginFrame(args);
// Providing same args again to OnBeginFrame() should not notify observer.
- EXPECT_CALL((*client_), OnDidFinishFrame(BeginFrameAck(0, 2, 0, false)))
- .Times(1);
source_->OnBeginFrame(args);
// Providing same args through a different ExternalBeginFrameSource also does
diff --git a/chromium/cc/scheduler/begin_frame_tracker.cc b/chromium/cc/scheduler/begin_frame_tracker.cc
index dc18beaa4d3..fb39ee1eb1d 100644
--- a/chromium/cc/scheduler/begin_frame_tracker.cc
+++ b/chromium/cc/scheduler/begin_frame_tracker.cc
@@ -80,10 +80,11 @@ base::TimeDelta BeginFrameTracker::Interval() const {
void BeginFrameTracker::AsValueInto(
base::TimeTicks now,
base::trace_event::TracedValue* state) const {
- state->SetInteger("updated_at_us",
- (current_updated_at_ - base::TimeTicks()).InMicroseconds());
- state->SetInteger("finished_at_us", (current_finished_at_ - base::TimeTicks())
- .InMicroseconds());
+ state->SetDouble("updated_at_ms",
+ (current_updated_at_ - base::TimeTicks()).InMillisecondsF());
+ state->SetDouble(
+ "finished_at_ms",
+ (current_finished_at_ - base::TimeTicks()).InMillisecondsF());
if (HasFinished()) {
state->SetString("state", "FINISHED");
state->BeginDictionary("current_args_");
diff --git a/chromium/cc/scheduler/scheduler.cc b/chromium/cc/scheduler/scheduler.cc
index 7212416461f..e3fdef521d8 100644
--- a/chromium/cc/scheduler/scheduler.cc
+++ b/chromium/cc/scheduler/scheduler.cc
@@ -37,16 +37,9 @@ Scheduler::Scheduler(
client_(client),
layer_tree_host_id_(layer_tree_host_id),
task_runner_(task_runner),
- begin_frame_source_(nullptr),
- observing_begin_frame_source_(false),
compositor_timing_history_(std::move(compositor_timing_history)),
- begin_impl_frame_deadline_mode_(
- SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_NONE),
begin_impl_frame_tracker_(BEGINFRAMETRACKER_FROM_HERE),
state_machine_(settings),
- inside_process_scheduled_actions_(false),
- inside_action_(SchedulerStateMachine::ACTION_NONE),
- stopped_(false),
weak_factory_(this) {
TRACE_EVENT1("cc", "Scheduler::Scheduler", "settings", settings_.AsValue());
DCHECK(client_);
@@ -215,6 +208,12 @@ base::TimeTicks Scheduler::LastBeginImplFrameTime() {
return begin_impl_frame_tracker_.Current().frame_time;
}
+void Scheduler::BeginMainFrameNotExpectedUntil(base::TimeTicks time) {
+ TRACE_EVENT1("cc", "Scheduler::BeginMainFrameNotExpectedUntil",
+ "remaining_time", (time - Now()).InMillisecondsF());
+ client_->ScheduledActionBeginMainFrameNotExpectedUntil(time);
+}
+
void Scheduler::BeginImplFrameNotExpectedSoon() {
compositor_timing_history_->BeginImplFrameNotExpectedSoon();
@@ -331,10 +330,13 @@ void Scheduler::BeginImplFrameWithDeadline(const BeginFrameArgs& args) {
// Discard missed begin frames if they are too late.
if (adjusted_args.type == BeginFrameArgs::MISSED &&
now > adjusted_args.deadline) {
+ skipped_last_frame_missed_exceeded_deadline_ = true;
SendBeginFrameAck(adjusted_args, kBeginFrameSkipped);
return;
}
+ skipped_last_frame_missed_exceeded_deadline_ = false;
+
// Run the previous deadline if any.
if (state_machine_.begin_impl_frame_state() ==
SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME) {
@@ -405,10 +407,13 @@ void Scheduler::BeginImplFrameWithDeadline(const BeginFrameArgs& args) {
can_activate_before_deadline)) {
TRACE_EVENT_INSTANT0("cc", "SkipBeginImplFrameToReduceLatency",
TRACE_EVENT_SCOPE_THREAD);
+ skipped_last_frame_to_reduce_latency_ = true;
SendBeginFrameAck(begin_main_frame_args_, kBeginFrameSkipped);
return;
}
+ skipped_last_frame_to_reduce_latency_ = false;
+
BeginImplFrame(adjusted_args, now);
}
@@ -457,6 +462,8 @@ void Scheduler::SendBeginFrameAck(const BeginFrameArgs& args,
BeginFrameAck ack(args.source_id, args.sequence_number,
latest_confirmed_sequence_number, did_submit);
begin_frame_source_->DidFinishFrame(this, ack);
+ if (!did_submit)
+ client_->DidNotProduceFrame(ack);
}
// BeginImplFrame starts a compositor frame that will wait up until a deadline
@@ -488,7 +495,6 @@ void Scheduler::ScheduleBeginImplFrameDeadline() {
begin_impl_frame_deadline_mode_ =
state_machine_.CurrentBeginImplFrameDeadlineMode();
- base::TimeTicks deadline;
switch (begin_impl_frame_deadline_mode_) {
case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_NONE:
// No deadline.
@@ -496,18 +502,18 @@ void Scheduler::ScheduleBeginImplFrameDeadline() {
case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE:
// We are ready to draw a new active tree immediately.
// We don't use Now() here because it's somewhat expensive to call.
- deadline = base::TimeTicks();
+ deadline_ = base::TimeTicks();
break;
case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_REGULAR:
// We are animating on the impl thread but we can wait for some time.
- deadline = begin_impl_frame_tracker_.Current().deadline;
+ deadline_ = begin_impl_frame_tracker_.Current().deadline;
break;
case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE:
// We are blocked for one reason or another and we should wait.
// TODO(brianderson): Handle long deadlines (that are past the next
// frame's frame time) properly instead of using this hack.
- deadline = begin_impl_frame_tracker_.Current().frame_time +
- begin_impl_frame_tracker_.Current().interval;
+ deadline_ = begin_impl_frame_tracker_.Current().frame_time +
+ begin_impl_frame_tracker_.Current().interval;
break;
case SchedulerStateMachine::
BEGIN_IMPL_FRAME_DEADLINE_MODE_BLOCKED_ON_READY_TO_DRAW:
@@ -521,9 +527,11 @@ void Scheduler::ScheduleBeginImplFrameDeadline() {
TRACE_EVENT2("cc", "Scheduler::ScheduleBeginImplFrameDeadline", "mode",
SchedulerStateMachine::BeginImplFrameDeadlineModeToString(
begin_impl_frame_deadline_mode_),
- "deadline", deadline);
+ "deadline", deadline_);
- base::TimeDelta delta = std::max(deadline - Now(), base::TimeDelta());
+ deadline_scheduled_at_ = Now();
+ base::TimeDelta delta =
+ std::max(deadline_ - deadline_scheduled_at_, base::TimeDelta());
task_runner_->PostDelayedTask(
FROM_HERE, begin_impl_frame_deadline_task_.callback(), delta);
}
@@ -629,6 +637,11 @@ void Scheduler::ProcessScheduledActions() {
// TODO(brianderson): Pass begin_main_frame_args_ directly to client.
client_->ScheduledActionSendBeginMainFrame(begin_main_frame_args_);
break;
+ case SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT:
+ state_machine_.WillNotifyBeginMainFrameNotSent();
+ BeginMainFrameNotExpectedUntil(begin_main_frame_args_.frame_time +
+ begin_main_frame_args_.interval);
+ break;
case SchedulerStateMachine::ACTION_COMMIT: {
bool commit_has_no_updates = false;
state_machine_.WillCommit(commit_has_no_updates);
@@ -680,39 +693,62 @@ void Scheduler::ProcessScheduledActions() {
std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
Scheduler::AsValue() const {
- std::unique_ptr<base::trace_event::TracedValue> state(
- new base::trace_event::TracedValue());
+ auto state = base::MakeUnique<base::trace_event::TracedValue>();
+ AsValueInto(state.get());
+ return std::move(state);
+}
+
+void Scheduler::AsValueInto(base::trace_event::TracedValue* state) const {
base::TimeTicks now = Now();
state->BeginDictionary("state_machine");
- state_machine_.AsValueInto(state.get());
+ state_machine_.AsValueInto(state);
state->EndDictionary();
- state->BeginDictionary("scheduler_state");
state->SetBoolean("observing_begin_frame_source",
observing_begin_frame_source_);
state->SetBoolean("begin_impl_frame_deadline_task",
!begin_impl_frame_deadline_task_.IsCancelled());
state->SetBoolean("missed_begin_frame_task",
!missed_begin_frame_task_.IsCancelled());
+ state->SetBoolean("skipped_last_frame_missed_exceeded_deadline",
+ skipped_last_frame_missed_exceeded_deadline_);
+ state->SetBoolean("skipped_last_frame_to_reduce_latency",
+ skipped_last_frame_to_reduce_latency_);
state->SetString("inside_action",
SchedulerStateMachine::ActionToString(inside_action_));
-
- state->BeginDictionary("begin_impl_frame_tracker");
- begin_impl_frame_tracker_.AsValueInto(now, state.get());
- state->EndDictionary();
-
-
state->SetString("begin_impl_frame_deadline_mode",
SchedulerStateMachine::BeginImplFrameDeadlineModeToString(
begin_impl_frame_deadline_mode_));
+
+ state->SetDouble("deadline_ms",
+ (deadline_ - base::TimeTicks()).InMillisecondsF());
+ state->SetDouble(
+ "deadline_scheduled_at_ms",
+ (deadline_scheduled_at_ - base::TimeTicks()).InMillisecondsF());
+
+ state->SetDouble("now_ms", (Now() - base::TimeTicks()).InMillisecondsF());
+ state->SetDouble("now_to_deadline_ms", (deadline_ - Now()).InMillisecondsF());
+ state->SetDouble("now_to_deadline_scheduled_at_ms",
+ (deadline_scheduled_at_ - Now()).InMillisecondsF());
+
+ state->BeginDictionary("begin_impl_frame_args");
+ begin_impl_frame_tracker_.AsValueInto(now, state);
state->EndDictionary();
- state->BeginDictionary("compositor_timing_history");
- compositor_timing_history_->AsValueInto(state.get());
+ state->BeginDictionary("begin_frame_observer_state");
+ BeginFrameObserverBase::AsValueInto(state);
state->EndDictionary();
- return std::move(state);
+ if (begin_frame_source_) {
+ state->BeginDictionary("begin_frame_source_state");
+ begin_frame_source_->AsValueInto(state);
+ state->EndDictionary();
+ }
+
+ state->BeginDictionary("compositor_timing_history");
+ compositor_timing_history_->AsValueInto(state);
+ state->EndDictionary();
}
void Scheduler::UpdateCompositorTimingHistoryRecordingEnabled() {
diff --git a/chromium/cc/scheduler/scheduler.h b/chromium/cc/scheduler/scheduler.h
index 9efd831d76a..6c9ccc4fd71 100644
--- a/chromium/cc/scheduler/scheduler.h
+++ b/chromium/cc/scheduler/scheduler.h
@@ -47,7 +47,10 @@ class SchedulerClient {
virtual void ScheduledActionInvalidateCompositorFrameSink() = 0;
virtual void ScheduledActionPerformImplSideInvalidation() = 0;
virtual void DidFinishImplFrame() = 0;
+ virtual void DidNotProduceFrame(const BeginFrameAck& ack) = 0;
virtual void SendBeginMainFrameNotExpectedSoon() = 0;
+ virtual void ScheduledActionBeginMainFrameNotExpectedUntil(
+ base::TimeTicks time) = 0;
protected:
virtual ~SchedulerClient() {}
@@ -146,6 +149,8 @@ class CC_EXPORT Scheduler : public BeginFrameObserverBase {
std::unique_ptr<base::trace_event::ConvertableToTraceFormat> AsValue() const;
+ void AsValueInto(base::trace_event::TracedValue* state) const;
+
void SetVideoNeedsBeginFrames(bool video_needs_begin_frames);
const BeginFrameSource* begin_frame_source() const {
@@ -159,19 +164,24 @@ class CC_EXPORT Scheduler : public BeginFrameObserverBase {
virtual base::TimeTicks Now() const;
const SchedulerSettings settings_;
- // Not owned.
- SchedulerClient* client_;
- int layer_tree_host_id_;
+ SchedulerClient* const client_;
+ const int layer_tree_host_id_;
base::SingleThreadTaskRunner* task_runner_;
- // Not owned. May be null.
- BeginFrameSource* begin_frame_source_;
- bool observing_begin_frame_source_;
+ BeginFrameSource* begin_frame_source_ = nullptr;
+ bool observing_begin_frame_source_ = false;
+
+ bool skipped_last_frame_missed_exceeded_deadline_ = false;
+ bool skipped_last_frame_to_reduce_latency_ = false;
std::unique_ptr<CompositorTimingHistory> compositor_timing_history_;
SchedulerStateMachine::BeginImplFrameDeadlineMode
- begin_impl_frame_deadline_mode_;
+ begin_impl_frame_deadline_mode_ =
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_NONE;
+ base::TimeTicks deadline_;
+ base::TimeTicks deadline_scheduled_at_;
+
BeginFrameTracker begin_impl_frame_tracker_;
BeginFrameArgs begin_main_frame_args_;
@@ -180,15 +190,17 @@ class CC_EXPORT Scheduler : public BeginFrameObserverBase {
base::CancelableClosure missed_begin_frame_task_;
SchedulerStateMachine state_machine_;
- bool inside_process_scheduled_actions_;
- SchedulerStateMachine::Action inside_action_;
+ bool inside_process_scheduled_actions_ = false;
+ SchedulerStateMachine::Action inside_action_ =
+ SchedulerStateMachine::ACTION_NONE;
- bool stopped_;
+ bool stopped_ = false;
private:
void ScheduleBeginImplFrameDeadline();
void ScheduleBeginImplFrameDeadlineIfNeeded();
void BeginImplFrameNotExpectedSoon();
+ void BeginMainFrameNotExpectedUntil(base::TimeTicks time);
void SetupNextBeginFrameIfNeeded();
void DrawIfPossible();
void DrawForced();
diff --git a/chromium/cc/scheduler/scheduler_state_machine.cc b/chromium/cc/scheduler/scheduler_state_machine.cc
index e73508ce1ab..210a2bdc43b 100644
--- a/chromium/cc/scheduler/scheduler_state_machine.cc
+++ b/chromium/cc/scheduler/scheduler_state_machine.cc
@@ -10,7 +10,6 @@
#include "base/trace_event/trace_event.h"
#include "base/trace_event/trace_event_argument.h"
#include "base/values.h"
-#include "cc/output/begin_frame_args.h"
namespace cc {
@@ -20,62 +19,9 @@ const int kMaxPendingSubmitFrames = 1;
} // namespace
SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings)
- : settings_(settings),
- compositor_frame_sink_state_(COMPOSITOR_FRAME_SINK_NONE),
- begin_impl_frame_state_(BEGIN_IMPL_FRAME_STATE_IDLE),
- begin_main_frame_state_(BEGIN_MAIN_FRAME_STATE_IDLE),
- forced_redraw_state_(FORCED_REDRAW_STATE_IDLE),
- begin_frame_source_id_(0),
- begin_frame_sequence_number_(BeginFrameArgs::kInvalidFrameNumber),
- last_begin_frame_sequence_number_begin_main_frame_sent_(
- BeginFrameArgs::kInvalidFrameNumber),
- last_begin_frame_sequence_number_pending_tree_was_fresh_(
- BeginFrameArgs::kInvalidFrameNumber),
- last_begin_frame_sequence_number_active_tree_was_fresh_(
- BeginFrameArgs::kInvalidFrameNumber),
- last_begin_frame_sequence_number_compositor_frame_was_fresh_(
- BeginFrameArgs::kInvalidFrameNumber),
- commit_count_(0),
- current_frame_number_(0),
- last_frame_number_submit_performed_(-1),
- last_frame_number_draw_performed_(-1),
- last_frame_number_begin_main_frame_sent_(-1),
- last_frame_number_invalidate_compositor_frame_sink_performed_(-1),
- draw_funnel_(false),
- send_begin_main_frame_funnel_(true),
- invalidate_compositor_frame_sink_funnel_(false),
- impl_side_invalidation_funnel_(false),
- prepare_tiles_funnel_(0),
- consecutive_checkerboard_animations_(0),
- pending_submit_frames_(0),
- submit_frames_with_current_compositor_frame_sink_(0),
- needs_redraw_(false),
- needs_prepare_tiles_(false),
- needs_begin_main_frame_(false),
- needs_one_begin_impl_frame_(false),
- visible_(false),
- begin_frame_source_paused_(false),
- resourceless_draw_(false),
- can_draw_(false),
- has_pending_tree_(false),
- pending_tree_is_ready_for_activation_(false),
- active_tree_needs_first_draw_(false),
- did_create_and_initialize_first_compositor_frame_sink_(false),
- tree_priority_(NEW_CONTENT_TAKES_PRIORITY),
- scroll_handler_state_(
- ScrollHandlerState::SCROLL_DOES_NOT_AFFECT_SCROLL_HANDLER),
- critical_begin_main_frame_to_activate_is_fast_(true),
- main_thread_missed_last_deadline_(false),
- skip_next_begin_main_frame_to_reduce_latency_(false),
- defer_commits_(false),
- video_needs_begin_frames_(false),
- last_commit_had_no_updates_(false),
- wait_for_ready_to_draw_(false),
- did_draw_in_last_frame_(false),
- did_submit_in_last_frame_(false),
- needs_impl_side_invalidation_(false),
- previous_pending_tree_was_impl_side_(false),
- current_pending_tree_is_impl_side_(false) {}
+ : settings_(settings) {}
+
+SchedulerStateMachine::~SchedulerStateMachine() = default;
const char* SchedulerStateMachine::CompositorFrameSinkStateToString(
CompositorFrameSinkState state) {
@@ -194,6 +140,8 @@ const char* SchedulerStateMachine::ActionToString(Action action) {
return "ACTION_INVALIDATE_COMPOSITOR_FRAME_SINK";
case ACTION_PERFORM_IMPL_SIDE_INVALIDATION:
return "ACTION_PERFORM_IMPL_SIDE_INVALIDATION";
+ case ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT:
+ return "ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT";
}
NOTREACHED();
return "???";
@@ -216,7 +164,7 @@ void SchedulerStateMachine::AsValueInto(
state->SetString("begin_main_frame_state",
BeginMainFrameStateToString(begin_main_frame_state_));
state->SetString(
- "compositor_frame_sink_state_",
+ "compositor_frame_sink_state",
CompositorFrameSinkStateToString(compositor_frame_sink_state_));
state->SetString("forced_redraw_state",
ForcedRedrawOnTimeoutStateToString(forced_redraw_state_));
@@ -243,17 +191,20 @@ void SchedulerStateMachine::AsValueInto(
state->SetInteger(
"last_begin_frame_sequence_number_compositor_frame_was_fresh",
last_begin_frame_sequence_number_compositor_frame_was_fresh_);
- state->SetBoolean("funnel: draw_funnel", draw_funnel_);
- state->SetBoolean("funnel: send_begin_main_frame_funnel",
- send_begin_main_frame_funnel_);
- state->SetInteger("funnel: prepare_tiles_funnel", prepare_tiles_funnel_);
- state->SetBoolean("funnel: invalidate_compositor_frame_sink_funnel",
- invalidate_compositor_frame_sink_funnel_);
- state->SetBoolean("funnel: impl_side_invalidation_funnel",
- impl_side_invalidation_funnel_);
+ state->SetBoolean("did_draw", did_draw_);
+ state->SetBoolean("did_send_begin_main_frame_for_current_frame",
+ did_send_begin_main_frame_for_current_frame_);
+ state->SetBoolean("did_notify_begin_main_frame_not_sent",
+ did_notify_begin_main_frame_not_sent_);
+ state->SetBoolean("did_commit_during_frame", did_commit_during_frame_);
+ state->SetBoolean("did_invalidate_compositor_frame_sink",
+ did_invalidate_compositor_frame_sink_);
+ state->SetBoolean("did_perform_impl_side_invalidaion",
+ did_perform_impl_side_invalidation_);
+ state->SetBoolean("did_prepare_tiles", did_prepare_tiles_);
state->SetInteger("consecutive_checkerboard_animations",
consecutive_checkerboard_animations_);
- state->SetInteger("pending_submit_frames_", pending_submit_frames_);
+ state->SetInteger("pending_submit_frames", pending_submit_frames_);
state->SetInteger("submit_frames_with_current_compositor_frame_sink",
submit_frames_with_current_compositor_frame_sink_);
state->SetBoolean("needs_redraw", needs_redraw_);
@@ -275,7 +226,7 @@ void SchedulerStateMachine::AsValueInto(
state->SetString("tree_priority", TreePriorityToString(tree_priority_));
state->SetString("scroll_handler_state",
ScrollHandlerStateToString(scroll_handler_state_));
- state->SetBoolean("critical_begin_main_frame_to_activate_is_fast_",
+ state->SetBoolean("critical_begin_main_frame_to_activate_is_fast",
critical_begin_main_frame_to_activate_is_fast_);
state->SetBoolean("main_thread_missed_last_deadline",
main_thread_missed_last_deadline_);
@@ -288,6 +239,10 @@ void SchedulerStateMachine::AsValueInto(
state->SetBoolean("did_submit_in_last_frame", did_submit_in_last_frame_);
state->SetBoolean("needs_impl_side_invalidation",
needs_impl_side_invalidation_);
+ state->SetBoolean("current_pending_tree_is_impl_side",
+ current_pending_tree_is_impl_side_);
+ state->SetBoolean("previous_pending_tree_was_impl_side",
+ previous_pending_tree_was_impl_side_);
state->EndDictionary();
}
@@ -372,10 +327,9 @@ bool SchedulerStateMachine::ShouldDraw() const {
if (PendingDrawsShouldBeAborted())
return active_tree_needs_first_draw_;
- // Do not draw too many times in a single frame. It's okay that we don't check
- // this before checking for aborted draws because aborted draws do not request
- // a swap.
- if (draw_funnel_)
+ // Do not draw more than once in the deadline. Aborted draws are ok because
+ // those are effectively nops.
+ if (did_draw_)
return false;
// Don't draw if we are waiting on the first commit after a surface.
@@ -428,6 +382,42 @@ bool SchedulerStateMachine::ShouldActivatePendingTree() const {
return pending_tree_is_ready_for_activation_;
}
+bool SchedulerStateMachine::ShouldNotifyBeginMainFrameNotSent() const {
+ // This method returns true if most of the conditions for sending a
+ // BeginMainFrame are met, but one is not actually requested. This gives the
+ // main thread the chance to do something else.
+
+ // Don't notify if a BeginMainFrame has already been requested or is in
+ // progress.
+ if (needs_begin_main_frame_ ||
+ begin_main_frame_state_ != BEGIN_MAIN_FRAME_STATE_IDLE)
+ return false;
+
+ // Only notify when we're visible.
+ if (!visible_)
+ return false;
+
+ // There are no BeginImplFrames while BeginFrameSource is paused, meaning
+ // the scheduler should send SendBeginMainFrameNotExpectedSoon instead,
+ // indicating a longer period of inactivity.
+ if (begin_frame_source_paused_)
+ return false;
+
+ // Do not notify that no BeginMainFrame was sent too many times in a single
+ // frame.
+ if (did_notify_begin_main_frame_not_sent_)
+ return false;
+
+ // Do not notify if a commit happened during this frame as the main thread
+ // will already be active and does not need to be woken up to make further
+ // actions. (This occurs if the main frame was scheduled but didn't complete
+ // before the vsync deadline).
+ if (did_commit_during_frame_)
+ return false;
+
+ return true;
+}
+
bool SchedulerStateMachine::CouldSendBeginMainFrame() const {
if (!needs_begin_main_frame_)
return false;
@@ -452,9 +442,8 @@ bool SchedulerStateMachine::ShouldSendBeginMainFrame() const {
if (!CouldSendBeginMainFrame())
return false;
- // Do not send begin main frame too many times in a single frame or before
- // the first BeginFrame.
- if (send_begin_main_frame_funnel_)
+ // Do not send more than one begin main frame in a begin frame.
+ if (did_send_begin_main_frame_for_current_frame_)
return false;
// Only send BeginMainFrame when there isn't another commit pending already.
@@ -542,14 +531,13 @@ bool SchedulerStateMachine::ShouldCommit() const {
}
bool SchedulerStateMachine::ShouldPrepareTiles() const {
- // PrepareTiles only really needs to be called immediately after commit
- // and then periodically after that. Use a funnel to make sure we average
- // one PrepareTiles per BeginImplFrame in the long run.
- if (prepare_tiles_funnel_ > 0)
+ // Do not prepare tiles if we've already done so in commit or impl side
+ // invalidation.
+ if (did_prepare_tiles_)
return false;
- // Limiting to once per-frame is not enough, since we only want to
- // prepare tiles _after_ draws.
+ // Limiting to once per-frame is not enough, since we only want to prepare
+ // tiles _after_ draws.
if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE)
return false;
@@ -557,8 +545,8 @@ bool SchedulerStateMachine::ShouldPrepareTiles() const {
}
bool SchedulerStateMachine::ShouldInvalidateCompositorFrameSink() const {
- // Do not invalidate too many times in a frame.
- if (invalidate_compositor_frame_sink_funnel_)
+ // Do not invalidate more than once per begin frame.
+ if (did_invalidate_compositor_frame_sink_)
return false;
// Only the synchronous compositor requires invalidations.
@@ -598,6 +586,8 @@ SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const {
return ACTION_INVALIDATE_COMPOSITOR_FRAME_SINK;
if (ShouldBeginCompositorFrameSinkCreation())
return ACTION_BEGIN_COMPOSITOR_FRAME_SINK_CREATION;
+ if (ShouldNotifyBeginMainFrameNotSent())
+ return ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT;
return ACTION_NONE;
}
@@ -605,6 +595,11 @@ bool SchedulerStateMachine::ShouldPerformImplSideInvalidation() const {
if (!needs_impl_side_invalidation_)
return false;
+ // Only perform impl side invalidation after the frame ends so that we wait
+ // for any commit to happen before invalidating.
+ if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE)
+ return false;
+
if (!CouldCreatePendingTree())
return false;
@@ -613,8 +608,9 @@ bool SchedulerStateMachine::ShouldPerformImplSideInvalidation() const {
if (begin_main_frame_state_ == BEGIN_MAIN_FRAME_STATE_READY_TO_COMMIT)
return false;
- // Don't invalidate too many times in the same frame.
- if (impl_side_invalidation_funnel_)
+ // Don't invalidate if we've already done so either from the scheduler or as
+ // part of commit.
+ if (did_perform_impl_side_invalidation_)
return false;
// If invalidations go to the active tree and we are waiting for the previous
@@ -624,22 +620,7 @@ bool SchedulerStateMachine::ShouldPerformImplSideInvalidation() const {
return false;
}
- // If we are inside the deadline and an impl-side invalidation request is
- // still pending, do it now. We restrict performing impl-side invalidations
- // until the deadline to give the main thread a chance to respond to a sent
- // BeginMainFrame. If the main thread responds with a commit, we know the
- // invalidations will have been merged with the main frame.
- // If the commit was aborted, or the main thread fails to respond within the
- // deadline, then we create a pending tree for impl-side invalidations now.
- // This also checks to make sure that the |prepare_tiles_funnel_| is not full,
- // since impl-side invalidations will cause a PrepareTiles.
- if (begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE &&
- prepare_tiles_funnel_ == 0) {
- return true;
- }
-
- // Wait till the deadline to perform impl-side invalidations.
- return false;
+ return true;
}
void SchedulerStateMachine::WillPerformImplSideInvalidation() {
@@ -653,7 +634,7 @@ void SchedulerStateMachine::WillPerformImplSideInvalidationInternal() {
needs_impl_side_invalidation_ = false;
has_pending_tree_ = true;
- impl_side_invalidation_funnel_ = true;
+ did_perform_impl_side_invalidation_ = true;
// TODO(eseckler): Track impl-side invalidations for pending/active tree and
// CompositorFrame freshness computation.
}
@@ -683,15 +664,22 @@ void SchedulerStateMachine::WillSendBeginMainFrame() {
DCHECK(!has_pending_tree_ || settings_.main_frame_before_activation_enabled);
DCHECK(visible_);
DCHECK(!begin_frame_source_paused_);
- DCHECK(!send_begin_main_frame_funnel_);
+ DCHECK(!did_send_begin_main_frame_for_current_frame_);
begin_main_frame_state_ = BEGIN_MAIN_FRAME_STATE_SENT;
needs_begin_main_frame_ = false;
- send_begin_main_frame_funnel_ = true;
+ did_send_begin_main_frame_for_current_frame_ = true;
last_frame_number_begin_main_frame_sent_ = current_frame_number_;
last_begin_frame_sequence_number_begin_main_frame_sent_ =
begin_frame_sequence_number_;
}
+void SchedulerStateMachine::WillNotifyBeginMainFrameNotSent() {
+ DCHECK(visible_);
+ DCHECK(!begin_frame_source_paused_);
+ DCHECK(!did_notify_begin_main_frame_not_sent_);
+ did_notify_begin_main_frame_not_sent_ = true;
+}
+
void SchedulerStateMachine::WillCommit(bool commit_has_no_updates) {
bool can_have_pending_tree =
commit_has_no_updates &&
@@ -701,6 +689,7 @@ void SchedulerStateMachine::WillCommit(bool commit_has_no_updates) {
commit_count_++;
last_commit_had_no_updates_ = commit_has_no_updates;
begin_main_frame_state_ = BEGIN_MAIN_FRAME_STATE_IDLE;
+ did_commit_during_frame_ = true;
if (commit_has_no_updates) {
// Pending tree might still exist from prior commit.
@@ -727,7 +716,7 @@ void SchedulerStateMachine::WillCommit(bool commit_has_no_updates) {
// request is received after the commit.
if (needs_impl_side_invalidation_)
WillPerformImplSideInvalidationInternal();
- impl_side_invalidation_funnel_ = true;
+ did_perform_impl_side_invalidation_ = true;
// We have a new pending tree.
has_pending_tree_ = true;
@@ -784,7 +773,7 @@ void SchedulerStateMachine::WillDrawInternal() {
// draw itself might request another draw.
needs_redraw_ = false;
- draw_funnel_ = true;
+ did_draw_ = true;
active_tree_needs_first_draw_ = false;
did_draw_in_last_frame_ = true;
last_frame_number_draw_performed_ = current_frame_number_;
@@ -840,7 +829,7 @@ void SchedulerStateMachine::DidDrawInternal(DrawResult draw_result) {
}
void SchedulerStateMachine::WillDraw() {
- DCHECK(!draw_funnel_);
+ DCHECK(!did_draw_);
WillDrawInternal();
}
@@ -877,8 +866,8 @@ void SchedulerStateMachine::WillBeginCompositorFrameSinkCreation() {
}
void SchedulerStateMachine::WillInvalidateCompositorFrameSink() {
- DCHECK(!invalidate_compositor_frame_sink_funnel_);
- invalidate_compositor_frame_sink_funnel_ = true;
+ DCHECK(!did_invalidate_compositor_frame_sink_);
+ did_invalidate_compositor_frame_sink_ = true;
last_frame_number_invalidate_compositor_frame_sink_performed_ =
current_frame_number_;
@@ -1046,27 +1035,18 @@ void SchedulerStateMachine::OnBeginImplFrame(uint32_t source_id,
did_submit_in_last_frame_ = false;
needs_one_begin_impl_frame_ = false;
- // Clear funnels for any actions we perform during the frame.
- send_begin_main_frame_funnel_ = false;
- invalidate_compositor_frame_sink_funnel_ = false;
- impl_side_invalidation_funnel_ = false;
-
- // "Drain" the PrepareTiles funnel.
- if (prepare_tiles_funnel_ > 0)
- prepare_tiles_funnel_--;
+ did_notify_begin_main_frame_not_sent_ = false;
+ did_send_begin_main_frame_for_current_frame_ = false;
+ did_commit_during_frame_ = false;
+ did_invalidate_compositor_frame_sink_ = false;
+ did_perform_impl_side_invalidation_ = false;
}
void SchedulerStateMachine::OnBeginImplFrameDeadline() {
begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE;
// Clear funnels for any actions we perform during the deadline.
- draw_funnel_ = false;
-
- // Allow one PrepareTiles per draw for synchronous compositor.
- if (settings_.using_synchronous_renderer_compositor) {
- if (prepare_tiles_funnel_ > 0)
- prepare_tiles_funnel_--;
- }
+ did_draw_ = false;
if (!settings_.using_synchronous_renderer_compositor)
UpdateBeginFrameSequenceNumbersForBeginFrameDeadline();
@@ -1075,6 +1055,12 @@ void SchedulerStateMachine::OnBeginImplFrameDeadline() {
void SchedulerStateMachine::OnBeginImplFrameIdle() {
begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_IDLE;
+ // Count any prepare tiles that happens in commits in between frames. We want
+ // to prevent a prepare tiles during the next frame's deadline in that case.
+ // This also allows synchronous compositor to do one PrepareTiles per draw.
+ // This is same as the old prepare tiles funnel behavior.
+ did_prepare_tiles_ = false;
+
skip_next_begin_main_frame_to_reduce_latency_ = false;
// If a new or undrawn active tree is pending after the deadline,
@@ -1085,7 +1071,7 @@ void SchedulerStateMachine::OnBeginImplFrameIdle() {
// If we're entering a state where we won't get BeginFrames set all the
// funnels so that we don't perform any actions that we shouldn't.
if (!BeginFrameNeeded())
- send_begin_main_frame_funnel_ = true;
+ did_send_begin_main_frame_for_current_frame_ = true;
// Synchronous compositor finishes BeginFrames before triggering their
// deadline. Therefore, we update sequence numbers when becoming idle, before
@@ -1161,8 +1147,7 @@ void SchedulerStateMachine::SetVisible(bool visible) {
if (visible)
main_thread_missed_last_deadline_ = false;
- // TODO(sunnyps): Change the funnel to a bool to avoid hacks like this.
- prepare_tiles_funnel_ = 0;
+ did_prepare_tiles_ = false;
wait_for_ready_to_draw_ = false;
}
@@ -1284,8 +1269,7 @@ void SchedulerStateMachine::BeginMainFrameAborted(CommitEarlyOutReason reason) {
void SchedulerStateMachine::DidPrepareTiles() {
needs_prepare_tiles_ = false;
- // "Fill" the PrepareTiles funnel.
- prepare_tiles_funnel_++;
+ did_prepare_tiles_ = true;
}
void SchedulerStateMachine::DidLoseCompositorFrameSink() {
diff --git a/chromium/cc/scheduler/scheduler_state_machine.h b/chromium/cc/scheduler/scheduler_state_machine.h
index cd4a7f2ee66..6656188de03 100644
--- a/chromium/cc/scheduler/scheduler_state_machine.h
+++ b/chromium/cc/scheduler/scheduler_state_machine.h
@@ -12,6 +12,7 @@
#include "base/macros.h"
#include "cc/cc_export.h"
+#include "cc/output/begin_frame_args.h"
#include "cc/scheduler/commit_earlyout_reason.h"
#include "cc/scheduler/draw_result.h"
#include "cc/scheduler/scheduler_settings.h"
@@ -47,6 +48,7 @@ class CC_EXPORT SchedulerStateMachine {
public:
// settings must be valid for the lifetime of this class.
explicit SchedulerStateMachine(const SchedulerSettings& settings);
+ ~SchedulerStateMachine();
enum CompositorFrameSinkState {
COMPOSITOR_FRAME_SINK_NONE,
@@ -123,6 +125,7 @@ class CC_EXPORT SchedulerStateMachine {
ACTION_BEGIN_COMPOSITOR_FRAME_SINK_CREATION,
ACTION_PREPARE_TILES,
ACTION_INVALIDATE_COMPOSITOR_FRAME_SINK,
+ ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT,
};
static const char* ActionToString(Action action);
@@ -131,6 +134,7 @@ class CC_EXPORT SchedulerStateMachine {
Action NextAction() const;
void WillSendBeginMainFrame();
+ void WillNotifyBeginMainFrameNotSent();
void WillCommit(bool commit_had_no_updates);
void WillActivate();
void WillDraw();
@@ -318,6 +322,7 @@ class CC_EXPORT SchedulerStateMachine {
bool ShouldCommit() const;
bool ShouldPrepareTiles() const;
bool ShouldInvalidateCompositorFrameSink() const;
+ bool ShouldNotifyBeginMainFrameNotSent() const;
void WillDrawInternal();
void WillPerformImplSideInvalidationInternal();
@@ -329,72 +334,78 @@ class CC_EXPORT SchedulerStateMachine {
const SchedulerSettings settings_;
- CompositorFrameSinkState compositor_frame_sink_state_;
- BeginImplFrameState begin_impl_frame_state_;
- BeginMainFrameState begin_main_frame_state_;
- ForcedRedrawOnTimeoutState forced_redraw_state_;
+ CompositorFrameSinkState compositor_frame_sink_state_ =
+ COMPOSITOR_FRAME_SINK_NONE;
+ BeginImplFrameState begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_IDLE;
+ BeginMainFrameState begin_main_frame_state_ = BEGIN_MAIN_FRAME_STATE_IDLE;
+ ForcedRedrawOnTimeoutState forced_redraw_state_ = FORCED_REDRAW_STATE_IDLE;
// These fields are used to track the freshness of pending updates in the
// commit/activate/draw pipeline. The Scheduler uses the CompositorFrame's
// freshness to fill the |latest_confirmed_sequence_number| field in
// BeginFrameAcks.
- uint32_t begin_frame_source_id_;
- uint64_t begin_frame_sequence_number_;
- uint64_t last_begin_frame_sequence_number_begin_main_frame_sent_;
- uint64_t last_begin_frame_sequence_number_pending_tree_was_fresh_;
- uint64_t last_begin_frame_sequence_number_active_tree_was_fresh_;
- uint64_t last_begin_frame_sequence_number_compositor_frame_was_fresh_;
+ uint32_t begin_frame_source_id_ = 0;
+ uint64_t begin_frame_sequence_number_ = BeginFrameArgs::kInvalidFrameNumber;
+ uint64_t last_begin_frame_sequence_number_begin_main_frame_sent_ =
+ BeginFrameArgs::kInvalidFrameNumber;
+ uint64_t last_begin_frame_sequence_number_pending_tree_was_fresh_ =
+ BeginFrameArgs::kInvalidFrameNumber;
+ uint64_t last_begin_frame_sequence_number_active_tree_was_fresh_ =
+ BeginFrameArgs::kInvalidFrameNumber;
+ uint64_t last_begin_frame_sequence_number_compositor_frame_was_fresh_ =
+ BeginFrameArgs::kInvalidFrameNumber;
// These are used for tracing only.
- int commit_count_;
- int current_frame_number_;
- int last_frame_number_submit_performed_;
- int last_frame_number_draw_performed_;
- int last_frame_number_begin_main_frame_sent_;
- int last_frame_number_invalidate_compositor_frame_sink_performed_;
+ int commit_count_ = 0;
+ int current_frame_number_ = 0;
+ int last_frame_number_submit_performed_ = -1;
+ int last_frame_number_draw_performed_ = -1;
+ int last_frame_number_begin_main_frame_sent_ = -1;
+ int last_frame_number_invalidate_compositor_frame_sink_performed_ = -1;
// These are used to ensure that an action only happens once per frame,
// deadline, etc.
- bool draw_funnel_;
- bool send_begin_main_frame_funnel_;
- bool invalidate_compositor_frame_sink_funnel_;
- bool impl_side_invalidation_funnel_;
- // prepare_tiles_funnel_ is "filled" each time PrepareTiles is called
- // and "drained" on each BeginImplFrame. If the funnel gets too full,
- // we start throttling ACTION_PREPARE_TILES such that we average one
- // PrepareTiles per BeginImplFrame.
- int prepare_tiles_funnel_;
-
- int consecutive_checkerboard_animations_;
- int pending_submit_frames_;
- int submit_frames_with_current_compositor_frame_sink_;
- bool needs_redraw_;
- bool needs_prepare_tiles_;
- bool needs_begin_main_frame_;
- bool needs_one_begin_impl_frame_;
- bool visible_;
- bool begin_frame_source_paused_;
- bool resourceless_draw_;
- bool can_draw_;
- bool has_pending_tree_;
- bool pending_tree_is_ready_for_activation_;
- bool active_tree_needs_first_draw_;
- bool did_create_and_initialize_first_compositor_frame_sink_;
- TreePriority tree_priority_;
- ScrollHandlerState scroll_handler_state_;
- bool critical_begin_main_frame_to_activate_is_fast_;
- bool main_thread_missed_last_deadline_;
- bool skip_next_begin_main_frame_to_reduce_latency_;
- bool defer_commits_;
- bool video_needs_begin_frames_;
- bool last_commit_had_no_updates_;
- bool wait_for_ready_to_draw_;
- bool did_draw_in_last_frame_;
- bool did_submit_in_last_frame_;
- bool needs_impl_side_invalidation_;
-
- bool previous_pending_tree_was_impl_side_;
- bool current_pending_tree_is_impl_side_;
+ bool did_draw_ = false;
+ bool did_send_begin_main_frame_for_current_frame_ = true;
+ // Initialized to true to prevent begin main frame before begin frames have
+ // started. Reset to true when we stop asking for begin frames.
+ bool did_notify_begin_main_frame_not_sent_ = true;
+ bool did_commit_during_frame_ = false;
+ bool did_invalidate_compositor_frame_sink_ = false;
+ bool did_perform_impl_side_invalidation_ = false;
+ bool did_prepare_tiles_ = false;
+
+ int consecutive_checkerboard_animations_ = 0;
+ int pending_submit_frames_ = 0;
+ int submit_frames_with_current_compositor_frame_sink_ = 0;
+ bool needs_redraw_ = false;
+ bool needs_prepare_tiles_ = false;
+ bool needs_begin_main_frame_ = false;
+ bool needs_one_begin_impl_frame_ = false;
+ bool visible_ = false;
+ bool begin_frame_source_paused_ = false;
+ bool resourceless_draw_ = false;
+ bool can_draw_ = false;
+ bool has_pending_tree_ = false;
+ bool pending_tree_is_ready_for_activation_ = false;
+ bool active_tree_needs_first_draw_ = false;
+ bool did_create_and_initialize_first_compositor_frame_sink_ = false;
+ TreePriority tree_priority_ = NEW_CONTENT_TAKES_PRIORITY;
+ ScrollHandlerState scroll_handler_state_ =
+ ScrollHandlerState::SCROLL_DOES_NOT_AFFECT_SCROLL_HANDLER;
+ bool critical_begin_main_frame_to_activate_is_fast_ = true;
+ bool main_thread_missed_last_deadline_ = false;
+ bool skip_next_begin_main_frame_to_reduce_latency_ = false;
+ bool defer_commits_ = false;
+ bool video_needs_begin_frames_ = false;
+ bool last_commit_had_no_updates_ = false;
+ bool wait_for_ready_to_draw_ = false;
+ bool did_draw_in_last_frame_ = false;
+ bool did_submit_in_last_frame_ = false;
+ bool needs_impl_side_invalidation_ = false;
+
+ bool previous_pending_tree_was_impl_side_ = false;
+ bool current_pending_tree_is_impl_side_ = false;
private:
DISALLOW_COPY_AND_ASSIGN(SchedulerStateMachine);
diff --git a/chromium/cc/scheduler/scheduler_state_machine_unittest.cc b/chromium/cc/scheduler/scheduler_state_machine_unittest.cc
index 0a99a0969a0..da53e5dea99 100644
--- a/chromium/cc/scheduler/scheduler_state_machine_unittest.cc
+++ b/chromium/cc/scheduler/scheduler_state_machine_unittest.cc
@@ -204,6 +204,10 @@ void PerformAction(StateMachine* sm, SchedulerStateMachine::Action action) {
sm->WillSendBeginMainFrame();
return;
+ case SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT:
+ sm->WillNotifyBeginMainFrameNotSent();
+ return;
+
case SchedulerStateMachine::ACTION_COMMIT: {
bool commit_has_no_updates = false;
sm->WillCommit(commit_has_no_updates);
@@ -290,6 +294,27 @@ TEST(SchedulerStateMachineTest, BeginFrameNeeded) {
EXPECT_FALSE(state.BeginFrameNeeded());
}
+TEST(SchedulerStateMachineTest, TestNextActionNotifyBeginMainFrameNotSent) {
+ SchedulerSettings default_scheduler_settings;
+ StateMachine state(default_scheduler_settings);
+ state.SetVisible(true);
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_BEGIN_COMPOSITOR_FRAME_SINK_CREATION);
+ state.IssueNextBeginImplFrame();
+ state.CreateAndInitializeCompositorFrameSinkWithActivatedCommit();
+ // A main frame was not requested so short idle work is scheduled instead.
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+
+ state.SetNeedsRedraw(true);
+ state.SetNeedsBeginMainFrame();
+ // Now a main frame is requested no short idle work is scheduled.
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
+}
+
TEST(SchedulerStateMachineTest, TestNextActionBeginsMainFrameIfNeeded) {
SchedulerSettings default_scheduler_settings;
@@ -309,6 +334,8 @@ TEST(SchedulerStateMachineTest, TestNextActionBeginsMainFrameIfNeeded) {
EXPECT_FALSE(state.NeedsCommit());
state.IssueNextBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
@@ -458,6 +485,8 @@ TEST(SchedulerStateMachineTest,
// Start a frame.
state.IssueNextBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
EXPECT_FALSE(state.CommitPending());
@@ -495,6 +524,8 @@ TEST(SchedulerStateMachineTest, FailedDrawForMissingHighResNeedsCommit) {
// Start a frame.
state.IssueNextBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
EXPECT_FALSE(state.CommitPending());
@@ -531,6 +562,8 @@ TEST(SchedulerStateMachineTest, FailedDrawForMissingHighResNeedsCommit) {
// Verify we draw with the new frame.
state.IssueNextBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
state.SetDrawResultForTest(DRAW_SUCCESS);
@@ -664,6 +697,8 @@ TEST(SchedulerStateMachineTest, TestFailedDrawIsRetriedInNextBeginImplFrame) {
state.SetNeedsRedraw(true);
EXPECT_TRUE(state.BeginFrameNeeded());
state.IssueNextBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
EXPECT_TRUE(state.RedrawPending());
@@ -700,6 +735,8 @@ TEST(SchedulerStateMachineTest, TestDoestDrawTwiceInSameFrame) {
// Draw the first frame.
EXPECT_TRUE(state.BeginFrameNeeded());
state.IssueNextBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
@@ -716,6 +753,8 @@ TEST(SchedulerStateMachineTest, TestDoestDrawTwiceInSameFrame) {
// Move to another frame. This should now draw.
EXPECT_TRUE(state.BeginFrameNeeded());
state.IssueNextBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_IF_POSSIBLE);
@@ -1400,6 +1439,8 @@ TEST(SchedulerStateMachineTest, TestAbortBeginMainFrameBecauseCommitNotNeeded) {
EXPECT_MAIN_FRAME_STATE(SchedulerStateMachine::BEGIN_MAIN_FRAME_STATE_IDLE);
state.IssueNextBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -1424,6 +1465,8 @@ TEST(SchedulerStateMachineTest, TestFirstContextCreation) {
// Check that the first init does not SetNeedsBeginMainFrame.
state.IssueNextBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -1478,6 +1521,8 @@ TEST(SchedulerStateMachineTest,
// Once context recreation begins, nothing should happen.
state.IssueNextBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -1528,6 +1573,8 @@ TEST(SchedulerStateMachineTest,
// automatically cause a redraw.
EXPECT_TRUE(state.RedrawPending());
state.IssueNextBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_IF_POSSIBLE);
@@ -1536,6 +1583,8 @@ TEST(SchedulerStateMachineTest,
// Next frame as no work to do.
state.IssueNextBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -1544,6 +1593,8 @@ TEST(SchedulerStateMachineTest,
// SetCanDraw if waiting on first draw after activate.
state.SetNeedsRedraw(true);
state.IssueNextBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION(SchedulerStateMachine::ACTION_DRAW_IF_POSSIBLE);
@@ -1636,6 +1687,8 @@ TEST(SchedulerStateMachineTest, TestContextLostWhileCommitInProgress) {
state.OnBeginImplFrame(0, 11);
EXPECT_IMPL_FRAME_STATE(
SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME);
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT);
EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
EXPECT_SEQUENCE_NUMBERS(11u, 10u, 10u, 10u,
BeginFrameArgs::kInvalidFrameNumber);
@@ -1993,7 +2046,8 @@ TEST(SchedulerStateMachineTest,
}
void FinishPreviousCommitAndDrawWithoutExitingDeadline(
- StateMachine* state_ptr) {
+ StateMachine* state_ptr,
+ bool expect_begin_main_frame_not_sent_before_impl_frame_deadline) {
// Gross, but allows us to use macros below.
StateMachine& state = *state_ptr;
@@ -2006,6 +2060,10 @@ void FinishPreviousCommitAndDrawWithoutExitingDeadline(
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.IssueNextBeginImplFrame();
+ if (expect_begin_main_frame_not_sent_before_impl_frame_deadline) {
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT);
+ }
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
EXPECT_TRUE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
@@ -2045,7 +2103,7 @@ TEST(SchedulerStateMachineTest, TestImplLatencyTakesPriority) {
// Request a new commit and finish the previous one.
state.SetNeedsBeginMainFrame();
- FinishPreviousCommitAndDrawWithoutExitingDeadline(&state);
+ FinishPreviousCommitAndDrawWithoutExitingDeadline(&state, false);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -2053,7 +2111,7 @@ TEST(SchedulerStateMachineTest, TestImplLatencyTakesPriority) {
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Finish the previous commit and draw it.
- FinishPreviousCommitAndDrawWithoutExitingDeadline(&state);
+ FinishPreviousCommitAndDrawWithoutExitingDeadline(&state, true);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Verify we do not send another BeginMainFrame if was are submit-frame
@@ -2234,6 +2292,8 @@ TEST(SchedulerStateMachineTest, ImplSideInvalidationOnlyInsideDeadline) {
state.SetNeedsImplSideInvalidation();
state.IssueNextBeginImplFrame();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(
@@ -2257,6 +2317,8 @@ TEST(SchedulerStateMachineTest,
state.SetNeedsImplSideInvalidation();
state.IssueNextBeginImplFrame();
state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Initializing the CompositorFrameSink puts us in a state waiting for the
@@ -2351,6 +2413,8 @@ TEST(SchedulerStateMachineTest,
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_PERFORM_IMPL_SIDE_INVALIDATION);
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Request another invalidation, which should wait until the pending tree is
@@ -2399,6 +2463,8 @@ TEST(SchedulerStateMachineTest, ImplSideInvalidationsThrottledOnDraw) {
state.SetNeedsImplSideInvalidation();
state.IssueNextBeginImplFrame();
state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Ack the previous frame and begin impl frame, which should perform the
@@ -2447,6 +2513,8 @@ TEST(SchedulerStateMachineTest, PrepareTilesWaitForImplSideInvalidation) {
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_PERFORM_IMPL_SIDE_INVALIDATION);
state.DidPrepareTiles();
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
}
@@ -2473,6 +2541,8 @@ TEST(SchedulerStateMachineTest, TestBeginFrameFreshnessWithoutUpdates) {
// OnBeginImplFrame() updates the sequence number.
state.OnBeginImplFrame(0, 10);
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
EXPECT_SEQUENCE_NUMBERS(10u, BeginFrameArgs::kInvalidFrameNumber,
BeginFrameArgs::kInvalidFrameNumber,
@@ -2500,6 +2570,8 @@ TEST(SchedulerStateMachineTest, TestBeginFrameFreshnessWithImplFrameUpdates) {
// OnBeginImplFrame() updates the sequence number.
state.OnBeginImplFrame(0, 10);
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
EXPECT_SEQUENCE_NUMBERS(10u, BeginFrameArgs::kInvalidFrameNumber,
BeginFrameArgs::kInvalidFrameNumber,
@@ -2583,6 +2655,8 @@ TEST(SchedulerStateMachineTest, TestBeginFrameFreshnessWithMainFrameUpdates) {
// If no further BeginMainFrame is needed, OnBeginFrameImplDeadline()
// updates the pending tree's frame number.
state.OnBeginImplFrame(0, 12);
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
EXPECT_SEQUENCE_NUMBERS(12u, 10u, 10u, BeginFrameArgs::kInvalidFrameNumber,
BeginFrameArgs::kInvalidFrameNumber);
@@ -2644,6 +2718,8 @@ TEST(SchedulerStateMachineTest, TestBeginFrameFreshnessWithMainFrameUpdates) {
// When no updates are required, OnBeginImplFrameDeadline() updates active
// tree and compositor frame freshness.
state.OnBeginImplFrame(0, 15);
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -2673,6 +2749,8 @@ TEST(SchedulerStateMachineTest, TestBeginFrameFreshnessWithMainFrameUpdates) {
// When the source changes, the current frame number is updated and frame
// numbers for freshness are reset to invalid numbers.
state.OnBeginImplFrame(1, 5);
+ EXPECT_ACTION_UPDATE_STATE(
+ SchedulerStateMachine::ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
EXPECT_SEQUENCE_NUMBERS(5u, BeginFrameArgs::kInvalidFrameNumber,
BeginFrameArgs::kInvalidFrameNumber,
diff --git a/chromium/cc/scheduler/scheduler_unittest.cc b/chromium/cc/scheduler/scheduler_unittest.cc
index 72e31f53735..1049445fa7f 100644
--- a/chromium/cc/scheduler/scheduler_unittest.cc
+++ b/chromium/cc/scheduler/scheduler_unittest.cc
@@ -123,6 +123,7 @@ class FakeSchedulerClient : public SchedulerClient,
EXPECT_TRUE(inside_begin_impl_frame_);
inside_begin_impl_frame_ = false;
}
+ void DidNotProduceFrame(const BeginFrameAck& ack) override {}
void ScheduledActionSendBeginMainFrame(const BeginFrameArgs& args) override {
PushAction("ScheduledActionSendBeginMainFrame");
@@ -179,6 +180,11 @@ class FakeSchedulerClient : public SchedulerClient,
PushAction("SendBeginMainFrameNotExpectedSoon");
}
+ void ScheduledActionBeginMainFrameNotExpectedUntil(
+ base::TimeTicks time) override {
+ PushAction("ScheduledActionBeginMainFrameNotExpectedUntil");
+ }
+
bool IsInsideBeginImplFrame() const { return inside_begin_impl_frame_; }
base::Callback<bool(void)> InsideBeginImplFrame(bool state) {
@@ -481,12 +487,14 @@ TEST_F(SchedulerTest, VideoNeedsBeginFrames) {
EXPECT_SCOPED(AdvanceFrame());
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
// WillBeginImplFrame is responsible for sending BeginFrames to video.
- EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2);
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2);
client_->Reset();
scheduler_->SetVideoNeedsBeginFrames(false);
@@ -537,7 +545,8 @@ TEST_F(SchedulerTest, RequestCommit) {
// BeginImplFrame should prepare the draw.
EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2);
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
@@ -552,7 +561,8 @@ TEST_F(SchedulerTest, RequestCommit) {
// The following BeginImplFrame deadline should SetNeedsBeginFrame(false)
// to avoid excessive toggles.
EXPECT_SCOPED(AdvanceFrame());
- EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2);
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
@@ -972,7 +982,8 @@ TEST_F(SchedulerTest, PrepareTiles) {
// the deadline task.
client->Reset();
EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 1);
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client, 1, 2);
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
// On the deadline, the actions should have occured in the right order.
@@ -999,7 +1010,8 @@ TEST_F(SchedulerTest, PrepareTiles) {
// the deadline task.
client->Reset();
EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 1);
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client, 1, 2);
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
// Draw. The draw will trigger SetNeedsPrepareTiles, and
@@ -1019,7 +1031,8 @@ TEST_F(SchedulerTest, PrepareTiles) {
// We need a BeginImplFrame where we don't swap to go idle.
client->Reset();
EXPECT_SCOPED(AdvanceFrame());
- EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client, 1, 2);
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client->Reset();
task_runner().RunPendingTasks(); // Run posted deadline.
@@ -1040,7 +1053,8 @@ TEST_F(SchedulerTest, PrepareTiles) {
// BeginImplFrame. There will be no draw, only PrepareTiles.
client->Reset();
EXPECT_SCOPED(AdvanceFrame());
- EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
+ EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client, 1, 2);
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client->Reset();
task_runner().RunPendingTasks(); // Run posted deadline.
@@ -1061,7 +1075,8 @@ TEST_F(SchedulerTest, PrepareTilesOncePerFrame) {
scheduler_->SetNeedsRedraw();
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2);
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->PrepareTilesPending());
@@ -1083,7 +1098,8 @@ TEST_F(SchedulerTest, PrepareTilesOncePerFrame) {
scheduler_->SetNeedsRedraw();
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2);
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
@@ -1105,7 +1121,8 @@ TEST_F(SchedulerTest, PrepareTilesOncePerFrame) {
scheduler_->SetNeedsRedraw();
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2);
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->PrepareTilesPending());
@@ -1129,7 +1146,8 @@ TEST_F(SchedulerTest, PrepareTilesOncePerFrame) {
scheduler_->SetNeedsRedraw();
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2);
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->PrepareTilesPending());
@@ -1147,7 +1165,8 @@ TEST_F(SchedulerTest, PrepareTilesOncePerFrame) {
scheduler_->SetNeedsRedraw();
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2);
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
@@ -1162,33 +1181,58 @@ TEST_F(SchedulerTest, PrepareTilesOncePerFrame) {
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
}
-TEST_F(SchedulerTest, PrepareTilesFunnelResetOnVisibilityChange) {
+TEST_F(SchedulerTest, DidPrepareTilesPreventsPrepareTilesForOneFrame) {
std::unique_ptr<SchedulerClientNeedsPrepareTilesInDraw> client =
base::WrapUnique(new SchedulerClientNeedsPrepareTilesInDraw);
SetUpScheduler(EXTERNAL_BFS, std::move(client));
- // Simulate a few visibility changes and associated PrepareTiles.
- for (int i = 0; i < 10; i++) {
- scheduler_->SetVisible(false);
- scheduler_->WillPrepareTiles();
- scheduler_->DidPrepareTiles();
+ client_->Reset();
+ scheduler_->SetNeedsRedraw();
+ EXPECT_SINGLE_ACTION("AddObserver(this)", client_);
- scheduler_->SetVisible(true);
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2);
+ EXPECT_TRUE(client_->IsInsideBeginImplFrame());
+
+ client_->Reset();
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_FALSE(client_->IsInsideBeginImplFrame());
+ EXPECT_ACTION("ScheduledActionDrawIfPossible", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionPrepareTiles", client_, 1, 2);
+
+ // We don't want to hinder scheduled prepare tiles for more than one frame
+ // even if we call unscheduled prepare tiles many times.
+ for (int i = 0; i < 10; i++) {
scheduler_->WillPrepareTiles();
scheduler_->DidPrepareTiles();
}
client_->Reset();
scheduler_->SetNeedsRedraw();
- EXPECT_SINGLE_ACTION("AddObserver(this)", client_);
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2);
+ EXPECT_TRUE(client_->IsInsideBeginImplFrame());
+ // No scheduled prepare tiles because we've already counted a prepare tiles in
+ // between frames.
client_->Reset();
- AdvanceFrame();
- EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1);
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_FALSE(client_->IsInsideBeginImplFrame());
+ EXPECT_SINGLE_ACTION("ScheduledActionDrawIfPossible", client_);
+
+ client_->Reset();
+ scheduler_->SetNeedsRedraw();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2);
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
+ // Resume scheduled prepare tiles.
client_->Reset();
- task_runner().RunTasksWhile(client_->InsideBeginImplFrame(true));
+ task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
EXPECT_ACTION("ScheduledActionDrawIfPossible", client_, 0, 2);
EXPECT_ACTION("ScheduledActionPrepareTiles", client_, 1, 2);
@@ -1671,8 +1715,9 @@ TEST_F(SchedulerTest,
scheduler_->SetNeedsRedraw();
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
SendNextBeginFrame();
- EXPECT_ACTION("AddObserver(this)", client_, 0, 2);
- EXPECT_ACTION("WillBeginImplFrame", client_, 1, 2);
+ EXPECT_ACTION("AddObserver(this)", client_, 0, 3);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 1, 3);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 2, 3);
client_->Reset();
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
@@ -1704,7 +1749,9 @@ TEST_F(SchedulerTest,
client_->Reset();
EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
SendNextBeginFrame();
- EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1,
+ 2);
client_->Reset();
// Deadline should be immediate.
@@ -2082,7 +2129,7 @@ void SchedulerTest::BeginFramesNotFromClient(BeginFrameSourceType bfs_type) {
// NotifyReadyToCommit should trigger the commit.
scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
scheduler_->NotifyReadyToCommit();
- EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+ EXPECT_ACTION("ScheduledActionCommit", client_, 0, 1);
client_->Reset();
// NotifyReadyToActivate should trigger the activation.
@@ -2093,8 +2140,9 @@ void SchedulerTest::BeginFramesNotFromClient(BeginFrameSourceType bfs_type) {
// BeginImplFrame deadline should draw. The following BeginImplFrame deadline
// should SetNeedsBeginFrame(false) to avoid excessive toggles.
EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTION("ScheduledActionDrawIfPossible", client_, 0, 2);
- EXPECT_ACTION("WillBeginImplFrame", client_, 1, 2);
+ EXPECT_ACTION("ScheduledActionDrawIfPossible", client_, 0, 3);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 1, 3);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 2, 3);
client_->Reset();
// Make sure SetNeedsBeginFrame isn't called on the client
@@ -2345,7 +2393,8 @@ TEST_F(SchedulerTest, DidLoseCompositorFrameSinkAfterSetNeedsPrepareTiles) {
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2);
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
@@ -2506,7 +2555,8 @@ TEST_F(SchedulerTest, SwitchFrameSourceToUnthrottled) {
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2);
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
@@ -2520,7 +2570,8 @@ TEST_F(SchedulerTest, SwitchFrameSourceToUnthrottled) {
// Unthrottled frame source will immediately begin a new frame.
task_runner().RunPendingTasks(); // Run posted BeginFrame.
- EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2);
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
@@ -2542,7 +2593,8 @@ TEST_F(SchedulerTest, SwitchFrameSourceToUnthrottledBeforeDeadline) {
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
- EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2);
// Switch to an unthrottled frame source before the frame deadline is hit.
scheduler_->SetBeginFrameSource(unthrottled_frame_source_.get());
@@ -2553,9 +2605,10 @@ TEST_F(SchedulerTest, SwitchFrameSourceToUnthrottledBeforeDeadline) {
client_->Reset();
task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTION("ScheduledActionDrawIfPossible", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionDrawIfPossible", client_, 0, 3);
// Unthrottled frame source will immediately begin a new frame.
- EXPECT_ACTION("WillBeginImplFrame", client_, 1, 2);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 1, 3);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 2, 3);
scheduler_->SetNeedsRedraw();
client_->Reset();
@@ -2575,7 +2628,8 @@ TEST_F(SchedulerTest, SwitchFrameSourceToThrottled) {
client_->Reset();
task_runner().RunPendingTasks(); // Run posted BeginFrame.
- EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2);
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
@@ -2595,7 +2649,8 @@ TEST_F(SchedulerTest, SwitchFrameSourceToThrottled) {
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2);
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
@@ -2611,7 +2666,8 @@ TEST_F(SchedulerTest, SwitchFrameSourceToNullInsideDeadline) {
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
- EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2);
client_->Reset();
// Switch to a null frame source.
@@ -2708,6 +2764,23 @@ TEST_F(SchedulerTest, SwitchFrameSourceWhenNotObserving) {
EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
}
+// Tests to ensure that we send a ScheduledActionBeginMainFrameNotExpectedUntil
+// when expected.
+TEST_F(SchedulerTest, ScheduledActionBeginMainFrameNotExpectedUntil) {
+ SetUpScheduler(EXTERNAL_BFS);
+
+ scheduler_->SetNeedsRedraw();
+ EXPECT_ACTION("AddObserver(this)", client_, 0, 1);
+ client_->Reset();
+
+ EXPECT_SCOPED(AdvanceFrame());
+ task_runner().RunPendingTasks();
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 3);
+ EXPECT_ACTION("ScheduledActionDrawIfPossible", client_, 2, 3);
+ client_->Reset();
+}
+
// Tests to ensure that we send a BeginMainFrameNotExpectedSoon when expected.
TEST_F(SchedulerTest, SendBeginMainFrameNotExpectedSoon) {
SetUpScheduler(EXTERNAL_BFS);
@@ -2733,7 +2806,8 @@ TEST_F(SchedulerTest, SendBeginMainFrameNotExpectedSoon) {
// The following BeginImplFrame deadline should SetNeedsBeginFrame(false)
// and send a SendBeginMainFrameNotExpectedSoon.
EXPECT_SCOPED(AdvanceFrame());
- EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2);
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
@@ -2758,8 +2832,9 @@ TEST_F(SchedulerTest, SynchronousCompositorAnimation) {
// Next vsync.
AdvanceFrame();
- EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
- EXPECT_ACTION("ScheduledActionInvalidateCompositorFrameSink", client_, 1, 2);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3);
+ EXPECT_ACTION("ScheduledActionInvalidateCompositorFrameSink", client_, 2, 3);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 3);
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
@@ -2777,8 +2852,9 @@ TEST_F(SchedulerTest, SynchronousCompositorAnimation) {
// Next vsync.
AdvanceFrame();
- EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
- EXPECT_ACTION("ScheduledActionInvalidateCompositorFrameSink", client_, 1, 2);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3);
+ EXPECT_ACTION("ScheduledActionInvalidateCompositorFrameSink", client_, 1, 3);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 2, 3);
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
@@ -2791,9 +2867,10 @@ TEST_F(SchedulerTest, SynchronousCompositorAnimation) {
// Idle on next vsync, as the animation has completed.
AdvanceFrame();
- EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3);
- EXPECT_ACTION("RemoveObserver(this)", client_, 1, 3);
- EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 4);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 4);
+ EXPECT_ACTION("RemoveObserver(this)", client_, 2, 4);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 3, 4);
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
}
@@ -2812,9 +2889,10 @@ TEST_F(SchedulerTest, SynchronousCompositorOnDrawDuringIdle) {
// Idle on next vsync.
AdvanceFrame();
- EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3);
- EXPECT_ACTION("RemoveObserver(this)", client_, 1, 3);
- EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 4);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 4);
+ EXPECT_ACTION("RemoveObserver(this)", client_, 2, 4);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 3, 4);
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
}
@@ -2834,7 +2912,8 @@ TEST_F(SchedulerTest, SetNeedsOneBeginImplFrame) {
// Next vsync, the first requested frame happens.
EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2);
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
@@ -2843,7 +2922,8 @@ TEST_F(SchedulerTest, SetNeedsOneBeginImplFrame) {
// Next vsync, the second requested frame happens (the one requested inside
// the previous frame's begin impl frame step).
EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2);
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
client_->Reset();
@@ -2904,7 +2984,7 @@ TEST_F(SchedulerTest, SynchronousCompositorCommitAndVerifyBeginFrameAcks) {
fake_external_begin_frame_source_->LastAckForObserver(scheduler_.get()));
scheduler_->NotifyReadyToCommit();
- EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+ EXPECT_ACTION("ScheduledActionCommit", client_, 0, 1);
client_->Reset();
scheduler_->NotifyReadyToActivate();
@@ -2913,8 +2993,9 @@ TEST_F(SchedulerTest, SynchronousCompositorCommitAndVerifyBeginFrameAcks) {
// Next vsync.
args = SendNextBeginFrame();
- EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
- EXPECT_ACTION("ScheduledActionInvalidateCompositorFrameSink", client_, 1, 2);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3);
+ EXPECT_ACTION("ScheduledActionInvalidateCompositorFrameSink", client_, 1, 3);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 2, 3);
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
@@ -2938,9 +3019,10 @@ TEST_F(SchedulerTest, SynchronousCompositorCommitAndVerifyBeginFrameAcks) {
// Idle on next vsync.
args = SendNextBeginFrame();
- EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3);
- EXPECT_ACTION("RemoveObserver(this)", client_, 1, 3);
- EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 4);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 4);
+ EXPECT_ACTION("RemoveObserver(this)", client_, 2, 4);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 3, 4);
EXPECT_FALSE(client_->IsInsideBeginImplFrame());
client_->Reset();
@@ -3021,8 +3103,9 @@ TEST_F(SchedulerTest, SynchronousCompositorPrepareTilesOnDraw) {
// Next vsync.
EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
- EXPECT_ACTION("ScheduledActionInvalidateCompositorFrameSink", client_, 1, 2);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3);
+ EXPECT_ACTION("ScheduledActionInvalidateCompositorFrameSink", client_, 1, 3);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 2, 3);
client_->Reset();
// Android onDraw.
@@ -3047,9 +3130,10 @@ TEST_F(SchedulerTest, SynchronousCompositorPrepareTilesOnDraw) {
// Next vsync.
EXPECT_SCOPED(AdvanceFrame());
EXPECT_FALSE(scheduler_->PrepareTilesPending());
- EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3);
- EXPECT_ACTION("RemoveObserver(this)", client_, 1, 3);
- EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 4);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 4);
+ EXPECT_ACTION("RemoveObserver(this)", client_, 2, 4);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 3, 4);
EXPECT_FALSE(scheduler_->begin_frames_expected());
client_->Reset();
}
@@ -3064,8 +3148,9 @@ TEST_F(SchedulerTest, SynchronousCompositorSendBeginMainFrameWhileIdle) {
// Next vsync.
EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
- EXPECT_ACTION("ScheduledActionInvalidateCompositorFrameSink", client_, 1, 2);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3);
+ EXPECT_ACTION("ScheduledActionInvalidateCompositorFrameSink", client_, 1, 3);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 2, 3);
client_->Reset();
// Android onDraw.
@@ -3093,8 +3178,9 @@ TEST_F(SchedulerTest, SynchronousCompositorSendBeginMainFrameWhileIdle) {
// Next vsync.
EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
- EXPECT_ACTION("ScheduledActionInvalidateCompositorFrameSink", client_, 1, 2);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3);
+ EXPECT_ACTION("ScheduledActionInvalidateCompositorFrameSink", client_, 1, 3);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 2, 3);
client_->Reset();
// Android onDraw.
@@ -3229,7 +3315,8 @@ TEST_F(SchedulerTest, ImplSideInvalidationsInDeadline) {
scheduler_->SetNeedsImplSideInvalidation();
client_->Reset();
EXPECT_SCOPED(AdvanceFrame());
- EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2);
// Deadline.
client_->Reset();
@@ -3395,7 +3482,8 @@ TEST_F(SchedulerTest, BeginFrameAckForFinishedImplFrame) {
BeginFrameArgs args = SendNextBeginFrame();
EXPECT_LT(latest_confirmed_sequence_number, args.sequence_number);
- EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2);
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
@@ -3421,7 +3509,8 @@ TEST_F(SchedulerTest, BeginFrameAckForFinishedImplFrame) {
args = SendNextBeginFrame();
EXPECT_LT(latest_confirmed_sequence_number, args.sequence_number);
- EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2);
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
@@ -3456,7 +3545,8 @@ TEST_F(SchedulerTest, BeginFrameAckForSkippedImplFrame) {
client_->Reset();
BeginFrameArgs args = SendNextBeginFrame();
- EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2);
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
@@ -3503,7 +3593,8 @@ TEST_F(SchedulerTest, BeginFrameAckForBeginFrameBeforeLastDeadline) {
client_->Reset();
SendNextBeginFrame();
- EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2);
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
// Until tiles were prepared, further proactive BeginFrames are expected.
EXPECT_TRUE(scheduler_->begin_frames_expected());
@@ -3546,7 +3637,8 @@ TEST_F(SchedulerTest, BeginFrameAckForDroppedBeginFrame) {
// First BeginFrame is handled by StateMachine.
BeginFrameArgs first_args = SendNextBeginFrame();
- EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2);
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
// State machine is no longer interested in BeginFrames, but scheduler is
// still observing the source.
@@ -3627,7 +3719,8 @@ TEST_F(SchedulerTest, BeginFrameAckForFinishedBeginFrameWithNewSourceId) {
source_id, 1, now_src());
fake_external_begin_frame_source_->TestOnBeginFrame(args);
- EXPECT_ACTION("WillBeginImplFrame", client_, 0, 1);
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionBeginMainFrameNotExpectedUntil", client_, 1, 2);
EXPECT_TRUE(client_->IsInsideBeginImplFrame());
EXPECT_TRUE(scheduler_->begin_frames_expected());
client_->Reset();
diff --git a/chromium/cc/surfaces/BUILD.gn b/chromium/cc/surfaces/BUILD.gn
index 3ba5480608b..352d636b6b3 100644
--- a/chromium/cc/surfaces/BUILD.gn
+++ b/chromium/cc/surfaces/BUILD.gn
@@ -45,11 +45,13 @@ cc_component("surfaces") {
"display_client.h",
"display_scheduler.cc",
"display_scheduler.h",
- "framesink_manager.cc",
- "framesink_manager.h",
+ "frame_sink_manager.cc",
+ "frame_sink_manager.h",
+ "frame_sink_manager_client.h",
"local_surface_id_allocator.cc",
"local_surface_id_allocator.h",
- "pending_frame_observer.h",
+ "primary_begin_frame_source.cc",
+ "primary_begin_frame_source.h",
"referenced_surface_tracker.cc",
"referenced_surface_tracker.h",
"sequence_surface_reference_factory.cc",
@@ -58,11 +60,10 @@ cc_component("surfaces") {
"surface.h",
"surface_aggregator.cc",
"surface_aggregator.h",
+ "surface_dependency_deadline.cc",
+ "surface_dependency_deadline.h",
"surface_dependency_tracker.cc",
"surface_dependency_tracker.h",
- "surface_factory.cc",
- "surface_factory.h",
- "surface_factory_client.h",
"surface_hittest.cc",
"surface_hittest.h",
"surface_hittest_delegate.h",
@@ -70,6 +71,7 @@ cc_component("surfaces") {
"surface_manager.h",
"surface_resource_holder.cc",
"surface_resource_holder.h",
+ "surface_resource_holder_client.h",
"surfaces_export.h",
]
diff --git a/chromium/cc/surfaces/compositor_frame_sink_support.cc b/chromium/cc/surfaces/compositor_frame_sink_support.cc
index 84b0a41d9cc..fa42842b86d 100644
--- a/chromium/cc/surfaces/compositor_frame_sink_support.cc
+++ b/chromium/cc/surfaces/compositor_frame_sink_support.cc
@@ -12,6 +12,7 @@
#include "cc/surfaces/compositor_frame_sink_support_client.h"
#include "cc/surfaces/display.h"
#include "cc/surfaces/surface.h"
+#include "cc/surfaces/surface_info.h"
#include "cc/surfaces/surface_manager.h"
#include "cc/surfaces/surface_reference.h"
@@ -27,8 +28,9 @@ std::unique_ptr<CompositorFrameSinkSupport> CompositorFrameSinkSupport::Create(
bool needs_sync_points) {
std::unique_ptr<CompositorFrameSinkSupport> support =
base::WrapUnique(new CompositorFrameSinkSupport(
- client, frame_sink_id, is_root, handles_frame_sink_id_invalidation));
- support->Init(surface_manager, needs_sync_points);
+ client, frame_sink_id, is_root, handles_frame_sink_id_invalidation,
+ needs_sync_points));
+ support->Init(surface_manager);
return support;
}
@@ -43,33 +45,12 @@ CompositorFrameSinkSupport::~CompositorFrameSinkSupport() {
reference_tracker_.current_surface_id().is_valid())
RemoveTopLevelRootReference(reference_tracker_.current_surface_id());
- // SurfaceFactory's destructor will attempt to return resources which will
- // call back into here and access |client_| so we should destroy
- // |surface_factory_|'s resources early on.
- surface_factory_->EvictSurface();
- surface_manager_->UnregisterSurfaceFactoryClient(frame_sink_id_);
+ EvictCurrentSurface();
+ surface_manager_->UnregisterFrameSinkManagerClient(frame_sink_id_);
if (handles_frame_sink_id_invalidation_)
surface_manager_->InvalidateFrameSinkId(frame_sink_id_);
}
-void CompositorFrameSinkSupport::ReferencedSurfacesChanged(
- const LocalSurfaceId& local_surface_id,
- const std::vector<SurfaceId>* active_referenced_surfaces) {
- if (!surface_manager_->using_surface_references())
- return;
-
- SurfaceId last_surface_id = reference_tracker_.current_surface_id();
-
- // Populate list of surface references to add and remove based on reference
- // surfaces in current frame compared with the last frame. The list of
- // surface references includes references from both the pending and active
- // frame if any.
- reference_tracker_.UpdateReferences(local_surface_id,
- active_referenced_surfaces);
-
- UpdateSurfaceReferences(last_surface_id, local_surface_id);
-}
-
void CompositorFrameSinkSupport::ReturnResources(
const ReturnedResourceArray& resources) {
if (resources.empty())
@@ -93,16 +74,10 @@ void CompositorFrameSinkSupport::SetBeginFrameSource(
UpdateNeedsBeginFramesInternal();
}
-void CompositorFrameSinkSupport::WillDrawSurface(
- const LocalSurfaceId& local_surface_id,
- const gfx::Rect& damage_rect) {
- if (client_)
- client_->WillDrawSurface(local_surface_id, damage_rect);
-}
-
-void CompositorFrameSinkSupport::EvictFrame() {
- DCHECK(surface_factory_);
- surface_factory_->EvictSurface();
+void CompositorFrameSinkSupport::EvictCurrentSurface() {
+ if (!current_surface_)
+ return;
+ DestroyCurrentSurface();
}
void CompositorFrameSinkSupport::SetNeedsBeginFrame(bool needs_begin_frame) {
@@ -110,15 +85,11 @@ void CompositorFrameSinkSupport::SetNeedsBeginFrame(bool needs_begin_frame) {
UpdateNeedsBeginFramesInternal();
}
-void CompositorFrameSinkSupport::BeginFrameDidNotSwap(
- const BeginFrameAck& ack) {
+void CompositorFrameSinkSupport::DidNotProduceFrame(const BeginFrameAck& ack) {
// TODO(eseckler): While a pending CompositorFrame exists (see TODO below), we
// should not acknowledge immediately. Instead, we should update the ack that
// will be sent to DisplayScheduler when the pending frame is activated.
- if (ack.sequence_number < BeginFrameArgs::kStartingFrameNumber) {
- DLOG(ERROR) << "Received BeginFrameDidNotSwap with invalid BeginFrameAck.";
- return;
- }
+ DCHECK_GE(ack.sequence_number, BeginFrameArgs::kStartingFrameNumber);
// |has_damage| is not transmitted, but false by default.
DCHECK(!ack.has_damage);
@@ -126,27 +97,77 @@ void CompositorFrameSinkSupport::BeginFrameDidNotSwap(
begin_frame_source_->DidFinishFrame(this, ack);
}
-void CompositorFrameSinkSupport::SubmitCompositorFrame(
+bool CompositorFrameSinkSupport::SubmitCompositorFrame(
const LocalSurfaceId& local_surface_id,
CompositorFrame frame) {
- DCHECK(surface_factory_);
+ TRACE_EVENT0("cc", "CompositorFrameSinkSupport::SubmitCompositorFrame");
+ DCHECK(local_surface_id.is_valid());
+ DCHECK_GE(frame.metadata.begin_frame_ack.sequence_number,
+ BeginFrameArgs::kStartingFrameNumber);
+ DCHECK(!frame.render_pass_list.empty());
+
++ack_pending_count_;
- if (frame.metadata.begin_frame_ack.sequence_number <
- BeginFrameArgs::kStartingFrameNumber) {
- DLOG(ERROR) << "Received CompositorFrame with invalid BeginFrameAck.";
- frame.metadata.begin_frame_ack.source_id = BeginFrameArgs::kManualSourceId;
- frame.metadata.begin_frame_ack.sequence_number =
- BeginFrameArgs::kStartingFrameNumber;
- }
// |has_damage| is not transmitted.
frame.metadata.begin_frame_ack.has_damage = true;
BeginFrameAck ack = frame.metadata.begin_frame_ack;
- surface_factory_->SubmitCompositorFrame(
- local_surface_id, std::move(frame),
+
+ if (!ui::LatencyInfo::Verify(frame.metadata.latency_info,
+ "RenderWidgetHostImpl::OnSwapCompositorFrame")) {
+ std::vector<ui::LatencyInfo>().swap(frame.metadata.latency_info);
+ }
+ for (ui::LatencyInfo& latency : frame.metadata.latency_info) {
+ if (latency.latency_components().size() > 0) {
+ latency.AddLatencyNumber(ui::DISPLAY_COMPOSITOR_RECEIVED_FRAME_COMPONENT,
+ 0, 0);
+ }
+ }
+
+ std::unique_ptr<Surface> surface;
+ bool create_new_surface =
+ (!current_surface_ ||
+ local_surface_id != current_surface_->surface_id().local_surface_id());
+ if (!create_new_surface) {
+ surface = std::move(current_surface_);
+ } else {
+ SurfaceId surface_id(frame_sink_id_, local_surface_id);
+ gfx::Size frame_size = frame.render_pass_list.back()->output_rect.size();
+ float device_scale_factor = frame.metadata.device_scale_factor;
+ SurfaceInfo surface_info(surface_id, device_scale_factor, frame_size);
+
+ if (!surface_info.is_valid()) {
+ TRACE_EVENT_INSTANT0("cc", "Invalid SurfaceInfo",
+ TRACE_EVENT_SCOPE_THREAD);
+ if (current_surface_)
+ DestroyCurrentSurface();
+ ReturnedResourceArray resources;
+ TransferableResource::ReturnResources(frame.resource_list, &resources);
+ ReturnResources(resources);
+ DidReceiveCompositorFrameAck();
+ return true;
+ }
+
+ surface = CreateSurface(surface_info);
+ }
+
+ bool result = surface->QueueFrame(
+ std::move(frame),
base::Bind(&CompositorFrameSinkSupport::DidReceiveCompositorFrameAck,
- weak_factory_.GetWeakPtr()));
+ weak_factory_.GetWeakPtr()),
+ base::BindRepeating(&CompositorFrameSinkSupport::WillDrawSurface,
+ weak_factory_.GetWeakPtr()));
+
+ if (!result) {
+ surface_manager_->DestroySurface(std::move(surface));
+ return false;
+ }
+
+ if (current_surface_) {
+ surface->SetPreviousFrameSurface(current_surface_.get());
+ DestroyCurrentSurface();
+ }
+ current_surface_ = std::move(surface);
// TODO(eseckler): The CompositorFrame submitted below might not be activated
// right away b/c of surface synchronization. We should only send the
@@ -155,6 +176,8 @@ void CompositorFrameSinkSupport::SubmitCompositorFrame(
// See https://crbug.com/703079.
if (begin_frame_source_)
begin_frame_source_->DidFinishFrame(this, ack);
+
+ return true;
}
void CompositorFrameSinkSupport::UpdateSurfaceReferences(
@@ -202,18 +225,39 @@ void CompositorFrameSinkSupport::RemoveTopLevelRootReference(
surface_manager_->RemoveSurfaceReferences({reference});
}
+void CompositorFrameSinkSupport::ReferencedSurfacesChanged(
+ const LocalSurfaceId& local_surface_id,
+ const std::vector<SurfaceId>* active_referenced_surfaces) {
+ if (!surface_manager_->using_surface_references())
+ return;
+
+ SurfaceId last_surface_id = reference_tracker_.current_surface_id();
+
+ // Populate list of surface references to add and remove based on reference
+ // surfaces in current frame compared with the last frame. The list of
+ // surface references includes references from both the pending and active
+ // frame if any.
+ reference_tracker_.UpdateReferences(local_surface_id,
+ active_referenced_surfaces);
+
+ UpdateSurfaceReferences(last_surface_id, local_surface_id);
+}
+
void CompositorFrameSinkSupport::DidReceiveCompositorFrameAck() {
DCHECK_GT(ack_pending_count_, 0);
ack_pending_count_--;
if (!client_)
return;
+
client_->DidReceiveCompositorFrameAck(surface_returned_resources_);
surface_returned_resources_.clear();
}
-void CompositorFrameSinkSupport::ForceReclaimResources() {
- DCHECK(surface_factory_);
- surface_factory_->ClearSurface();
+void CompositorFrameSinkSupport::WillDrawSurface(
+ const LocalSurfaceId& local_surface_id,
+ const gfx::Rect& damage_rect) {
+ if (client_)
+ client_->WillDrawSurface(local_surface_id, damage_rect);
}
void CompositorFrameSinkSupport::ClaimTemporaryReference(
@@ -221,27 +265,41 @@ void CompositorFrameSinkSupport::ClaimTemporaryReference(
surface_manager_->AssignTemporaryReference(surface_id, frame_sink_id_);
}
+void CompositorFrameSinkSupport::ReceiveFromChild(
+ const TransferableResourceArray& resources) {
+ surface_resource_holder_.ReceiveFromChild(resources);
+}
+
+void CompositorFrameSinkSupport::RefResources(
+ const TransferableResourceArray& resources) {
+ surface_resource_holder_.RefResources(resources);
+}
+
+void CompositorFrameSinkSupport::UnrefResources(
+ const ReturnedResourceArray& resources) {
+ surface_resource_holder_.UnrefResources(resources);
+}
+
CompositorFrameSinkSupport::CompositorFrameSinkSupport(
CompositorFrameSinkSupportClient* client,
const FrameSinkId& frame_sink_id,
bool is_root,
- bool handles_frame_sink_id_invalidation)
+ bool handles_frame_sink_id_invalidation,
+ bool needs_sync_points)
: client_(client),
frame_sink_id_(frame_sink_id),
+ surface_resource_holder_(this),
reference_tracker_(frame_sink_id),
is_root_(is_root),
+ needs_sync_points_(needs_sync_points),
handles_frame_sink_id_invalidation_(handles_frame_sink_id_invalidation),
weak_factory_(this) {}
-void CompositorFrameSinkSupport::Init(SurfaceManager* surface_manager,
- bool needs_sync_points) {
+void CompositorFrameSinkSupport::Init(SurfaceManager* surface_manager) {
surface_manager_ = surface_manager;
- surface_factory_ =
- base::MakeUnique<SurfaceFactory>(frame_sink_id_, surface_manager_, this);
if (handles_frame_sink_id_invalidation_)
surface_manager_->RegisterFrameSinkId(frame_sink_id_);
- surface_manager_->RegisterSurfaceFactoryClient(frame_sink_id_, this);
- surface_factory_->set_needs_sync_points(needs_sync_points);
+ surface_manager_->RegisterFrameSinkManagerClient(frame_sink_id_, this);
}
void CompositorFrameSinkSupport::OnBeginFrame(const BeginFrameArgs& args) {
@@ -258,6 +316,30 @@ const BeginFrameArgs& CompositorFrameSinkSupport::LastUsedBeginFrameArgs()
void CompositorFrameSinkSupport::OnBeginFrameSourcePausedChanged(bool paused) {}
+void CompositorFrameSinkSupport::OnSurfaceActivated(Surface* surface) {
+ DCHECK(surface->HasActiveFrame());
+ if (!seen_first_frame_activation_) {
+ seen_first_frame_activation_ = true;
+
+ const CompositorFrame& frame = surface->GetActiveFrame();
+ gfx::Size frame_size = frame.render_pass_list.back()->output_rect.size();
+
+ // SurfaceCreated only applies for the first Surface activation. Thus,
+ // SurfaceFactory stops observing new activations after the first one.
+ surface_manager_->SurfaceCreated(SurfaceInfo(
+ surface->surface_id(), frame.metadata.device_scale_factor, frame_size));
+ }
+ // Fire SurfaceCreated first so that a temporary reference is added before it
+ // is potentially transformed into a real reference by the client.
+ ReferencedSurfacesChanged(surface->surface_id().local_surface_id(),
+ surface->active_referenced_surfaces());
+ if (!surface_manager_->SurfaceModified(surface->surface_id())) {
+ TRACE_EVENT_INSTANT0("cc", "Damage not visible.", TRACE_EVENT_SCOPE_THREAD);
+ surface->RunDrawCallback();
+ }
+ surface_manager_->SurfaceActivated(surface);
+}
+
void CompositorFrameSinkSupport::UpdateNeedsBeginFramesInternal() {
if (!begin_frame_source_)
return;
@@ -272,10 +354,25 @@ void CompositorFrameSinkSupport::UpdateNeedsBeginFramesInternal() {
begin_frame_source_->RemoveObserver(this);
}
+std::unique_ptr<Surface> CompositorFrameSinkSupport::CreateSurface(
+ const SurfaceInfo& surface_info) {
+ seen_first_frame_activation_ = false;
+ return surface_manager_->CreateSurface(weak_factory_.GetWeakPtr(),
+ surface_info);
+}
+
+void CompositorFrameSinkSupport::DestroyCurrentSurface() {
+ surface_manager_->DestroySurface(std::move(current_surface_));
+}
+
void CompositorFrameSinkSupport::RequestCopyOfSurface(
- std::unique_ptr<CopyOutputRequest> request) {
- DCHECK(surface_factory_);
- surface_factory_->RequestCopyOfSurface(std::move(request));
+ std::unique_ptr<CopyOutputRequest> copy_request) {
+ if (!current_surface_)
+ return;
+
+ DCHECK(current_surface_->compositor_frame_sink_support().get() == this);
+ current_surface_->RequestCopyOfOutput(std::move(copy_request));
+ surface_manager_->SurfaceModified(current_surface_->surface_id());
}
} // namespace cc
diff --git a/chromium/cc/surfaces/compositor_frame_sink_support.h b/chromium/cc/surfaces/compositor_frame_sink_support.h
index 977acdf9788..ed2c154a7f8 100644
--- a/chromium/cc/surfaces/compositor_frame_sink_support.h
+++ b/chromium/cc/surfaces/compositor_frame_sink_support.h
@@ -13,20 +13,23 @@
#include "base/memory/weak_ptr.h"
#include "cc/output/compositor_frame.h"
#include "cc/scheduler/begin_frame_source.h"
+#include "cc/surfaces/frame_sink_manager_client.h"
#include "cc/surfaces/referenced_surface_tracker.h"
-#include "cc/surfaces/surface_factory.h"
-#include "cc/surfaces/surface_factory_client.h"
-#include "cc/surfaces/surface_id.h"
+#include "cc/surfaces/surface_info.h"
+#include "cc/surfaces/surface_resource_holder.h"
+#include "cc/surfaces/surface_resource_holder_client.h"
#include "cc/surfaces/surfaces_export.h"
namespace cc {
class CompositorFrameSinkSupportClient;
+class Surface;
class SurfaceManager;
class CC_SURFACES_EXPORT CompositorFrameSinkSupport
- : public SurfaceFactoryClient,
- public BeginFrameObserver {
+ : public BeginFrameObserver,
+ public SurfaceResourceHolderClient,
+ public FrameSinkManagerClient {
public:
static std::unique_ptr<CompositorFrameSinkSupport> Create(
CompositorFrameSinkSupportClient* client,
@@ -40,39 +43,43 @@ class CC_SURFACES_EXPORT CompositorFrameSinkSupport
const FrameSinkId& frame_sink_id() const { return frame_sink_id_; }
- Surface* current_surface_for_testing() {
- return surface_factory_->current_surface_for_testing();
- }
+ Surface* current_surface_for_testing() { return current_surface_.get(); }
+ SurfaceManager* surface_manager() { return surface_manager_; }
+ bool needs_sync_points() { return needs_sync_points_; }
const ReferencedSurfaceTracker& ReferenceTrackerForTesting() const {
return reference_tracker_;
}
- // SurfaceFactoryClient implementation.
- void ReferencedSurfacesChanged(
- const LocalSurfaceId& local_surface_id,
- const std::vector<SurfaceId>* active_referenced_surfaces) override;
+ // SurfaceResourceHolderClient implementation.
void ReturnResources(const ReturnedResourceArray& resources) override;
+
+ // FrameSinkManagerClient implementation.
void SetBeginFrameSource(BeginFrameSource* begin_frame_source) override;
- void WillDrawSurface(const LocalSurfaceId& local_surface_id,
- const gfx::Rect& damage_rect) override;
- void EvictFrame();
+ void EvictCurrentSurface();
void SetNeedsBeginFrame(bool needs_begin_frame);
- void BeginFrameDidNotSwap(const BeginFrameAck& ack);
- void SubmitCompositorFrame(const LocalSurfaceId& local_surface_id,
+ void DidNotProduceFrame(const BeginFrameAck& ack);
+ bool SubmitCompositorFrame(const LocalSurfaceId& local_surface_id,
CompositorFrame frame);
void RequestCopyOfSurface(std::unique_ptr<CopyOutputRequest> request);
- void ForceReclaimResources();
void ClaimTemporaryReference(const SurfaceId& surface_id);
+ // TODO(staraz): Move the following 3 methods to private.
+ void ReceiveFromChild(const TransferableResourceArray& resources);
+ void RefResources(const TransferableResourceArray& resources);
+ void UnrefResources(const ReturnedResourceArray& resources);
+
+ void OnSurfaceActivated(Surface* surface);
+
protected:
CompositorFrameSinkSupport(CompositorFrameSinkSupportClient* client,
const FrameSinkId& frame_sink_id,
bool is_root,
- bool handles_frame_sink_id_invalidation);
+ bool handles_frame_sink_id_invalidation,
+ bool needs_sync_points);
- void Init(SurfaceManager* surface_manager, bool needs_sync_points);
+ void Init(SurfaceManager* surface_manager);
private:
// Update surface references with SurfaceManager for current CompositorFrame
@@ -84,8 +91,13 @@ class CC_SURFACES_EXPORT CompositorFrameSinkSupport
void AddTopLevelRootReference(const SurfaceId& surface_id);
void RemoveTopLevelRootReference(const SurfaceId& surface_id);
+ void ReferencedSurfacesChanged(
+ const LocalSurfaceId& local_surface_id,
+ const std::vector<SurfaceId>* active_referenced_surfaces);
void DidReceiveCompositorFrameAck();
+ void WillDrawSurface(const LocalSurfaceId& local_surface_id,
+ const gfx::Rect& damage_rect);
// BeginFrameObserver implementation.
void OnBeginFrame(const BeginFrameArgs& args) override;
@@ -93,6 +105,8 @@ class CC_SURFACES_EXPORT CompositorFrameSinkSupport
void OnBeginFrameSourcePausedChanged(bool paused) override;
void UpdateNeedsBeginFramesInternal();
+ std::unique_ptr<Surface> CreateSurface(const SurfaceInfo& surface_info);
+ void DestroyCurrentSurface();
CompositorFrameSinkSupportClient* const client_;
@@ -100,7 +114,9 @@ class CC_SURFACES_EXPORT CompositorFrameSinkSupport
const FrameSinkId frame_sink_id_;
- std::unique_ptr<SurfaceFactory> surface_factory_;
+ SurfaceResourceHolder surface_resource_holder_;
+
+ std::unique_ptr<Surface> current_surface_;
// Counts the number of CompositorFrames that have been submitted and have not
// yet received an ACK.
int ack_pending_count_ = 0;
@@ -123,6 +139,8 @@ class CC_SURFACES_EXPORT CompositorFrameSinkSupport
ReferencedSurfaceTracker reference_tracker_;
const bool is_root_;
+ const bool needs_sync_points_;
+ bool seen_first_frame_activation_ = false;
// TODO(staraz): Remove this flag once ui::Compositor no longer needs to call
// RegisterFrameSinkId().
diff --git a/chromium/cc/surfaces/compositor_frame_sink_support_unittest.cc b/chromium/cc/surfaces/compositor_frame_sink_support_unittest.cc
index 6a7a5089ae5..62e2cbe6532 100644
--- a/chromium/cc/surfaces/compositor_frame_sink_support_unittest.cc
+++ b/chromium/cc/surfaces/compositor_frame_sink_support_unittest.cc
@@ -4,15 +4,20 @@
#include "cc/surfaces/compositor_frame_sink_support.h"
-#include "base/debug/stack_trace.h"
#include "base/macros.h"
#include "cc/output/compositor_frame.h"
+#include "cc/output/copy_output_request.h"
+#include "cc/output/copy_output_result.h"
+#include "cc/resources/resource_provider.h"
#include "cc/surfaces/compositor_frame_sink_support_client.h"
#include "cc/surfaces/frame_sink_id.h"
#include "cc/surfaces/surface_id.h"
+#include "cc/surfaces/surface_info.h"
#include "cc/surfaces/surface_manager.h"
#include "cc/test/begin_frame_args_test.h"
+#include "cc/test/compositor_frame_helpers.h"
#include "cc/test/fake_external_begin_frame_source.h"
+#include "cc/test/mock_compositor_frame_sink_support_client.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -27,1229 +32,824 @@ namespace cc {
namespace test {
namespace {
-constexpr FrameSinkId kDisplayFrameSink(2, 0);
-constexpr FrameSinkId kParentFrameSink(3, 0);
-constexpr FrameSinkId kChildFrameSink1(65563, 0);
-constexpr FrameSinkId kChildFrameSink2(65564, 0);
-constexpr FrameSinkId kArbitraryFrameSink(1337, 7331);
+constexpr bool kIsRoot = true;
+constexpr bool kIsChildRoot = false;
+constexpr bool kHandlesFrameSinkIdInvalidation = true;
+constexpr bool kNeedsSyncPoints = true;
+
+constexpr FrameSinkId kArbitraryFrameSinkId(1, 1);
+constexpr FrameSinkId kAnotherArbitraryFrameSinkId(2, 2);
+constexpr FrameSinkId kYetAnotherArbitraryFrameSinkId(3, 3);
+
+const base::UnguessableToken kArbitraryToken = base::UnguessableToken::Create();
+const base::UnguessableToken kArbitrarySourceId1 =
+ base::UnguessableToken::Deserialize(0xdead, 0xbeef);
+const base::UnguessableToken kArbitrarySourceId2 =
+ base::UnguessableToken::Deserialize(0xdead, 0xbee0);
+
+gpu::SyncToken GenTestSyncToken(int id) {
+ gpu::SyncToken token;
+ token.Set(gpu::CommandBufferNamespace::GPU_IO, 0,
+ gpu::CommandBufferId::FromUnsafeValue(id), 1);
+ return token;
+}
-class MockCompositorFrameSinkSupportClient
+class FakeCompositorFrameSinkSupportClient
: public CompositorFrameSinkSupportClient {
public:
- MockCompositorFrameSinkSupportClient() {
- ON_CALL(*this, ReclaimResources(_))
- .WillByDefault(Invoke(
- this,
- &MockCompositorFrameSinkSupportClient::ReclaimResourcesInternal));
- ON_CALL(*this, DidReceiveCompositorFrameAck(_))
- .WillByDefault(Invoke(
- this,
- &MockCompositorFrameSinkSupportClient::ReclaimResourcesInternal));
- }
+ FakeCompositorFrameSinkSupportClient() = default;
+ ~FakeCompositorFrameSinkSupportClient() override = default;
- ReturnedResourceArray& last_returned_resources() {
- return last_returned_resources_;
+ void DidReceiveCompositorFrameAck(
+ const ReturnedResourceArray& resources) override {
+ InsertResources(resources);
}
- // CompositorFrameSinkSupportClient implementation.
- MOCK_METHOD1(DidReceiveCompositorFrameAck,
- void(const ReturnedResourceArray&));
- MOCK_METHOD1(OnBeginFrame, void(const BeginFrameArgs&));
- MOCK_METHOD1(ReclaimResources, void(const ReturnedResourceArray&));
- MOCK_METHOD2(WillDrawSurface, void(const LocalSurfaceId&, const gfx::Rect&));
+ void OnBeginFrame(const BeginFrameArgs& args) override {}
- private:
- void ReclaimResourcesInternal(const ReturnedResourceArray& resources) {
- last_returned_resources_ = resources;
+ void ReclaimResources(const ReturnedResourceArray& resources) override {
+ InsertResources(resources);
}
- ReturnedResourceArray last_returned_resources_;
-};
-
-std::vector<SurfaceId> empty_surface_ids() {
- return std::vector<SurfaceId>();
-}
-
-SurfaceId MakeSurfaceId(const FrameSinkId& frame_sink_id, uint32_t local_id) {
- return SurfaceId(
- frame_sink_id,
- LocalSurfaceId(local_id, base::UnguessableToken::Deserialize(0, 1u)));
-}
-
-CompositorFrame MakeCompositorFrame(std::vector<SurfaceId> embedded_surfaces,
- std::vector<SurfaceId> referenced_surfaces,
- TransferableResourceArray resource_list) {
- CompositorFrame compositor_frame;
- compositor_frame.metadata.begin_frame_ack = BeginFrameAck(0, 1, 1, true);
- compositor_frame.metadata.embedded_surfaces = std::move(embedded_surfaces);
- compositor_frame.metadata.referenced_surfaces =
- std::move(referenced_surfaces);
- compositor_frame.resource_list = std::move(resource_list);
- return compositor_frame;
-}
-
-CompositorFrame MakeCompositorFrame() {
- return MakeCompositorFrame(empty_surface_ids(), empty_surface_ids(),
- TransferableResourceArray());
-}
-
-CompositorFrame MakeCompositorFrame(std::vector<SurfaceId> embedded_surfaces) {
- return MakeCompositorFrame(embedded_surfaces, embedded_surfaces,
- TransferableResourceArray());
-}
+ void WillDrawSurface(const LocalSurfaceId& local_surface_id,
+ const gfx::Rect& damage_rect) override {}
-CompositorFrame MakeCompositorFrame(
- std::vector<SurfaceId> embedded_surfaces,
- std::vector<SurfaceId> referenced_surfaces) {
- return MakeCompositorFrame(std::move(embedded_surfaces),
- std::move(referenced_surfaces),
- TransferableResourceArray());
-}
+ void clear_returned_resources() { returned_resources_.clear(); }
+ const ReturnedResourceArray& returned_resources() {
+ return returned_resources_;
+ }
-CompositorFrame MakeCompositorFrameWithResources(
- std::vector<SurfaceId> embedded_surfaces,
- TransferableResourceArray resource_list) {
- return MakeCompositorFrame(embedded_surfaces, embedded_surfaces,
- std::move(resource_list));
-}
+ private:
+ void InsertResources(const ReturnedResourceArray& resources) {
+ returned_resources_.insert(returned_resources_.end(), resources.begin(),
+ resources.end());
+ }
-TransferableResource MakeResource(ResourceId id,
- ResourceFormat format,
- uint32_t filter,
- const gfx::Size& size) {
- TransferableResource resource;
- resource.id = id;
- resource.format = format;
- resource.filter = filter;
- resource.size = size;
- return resource;
-}
+ ReturnedResourceArray returned_resources_;
-} // namespace
+ DISALLOW_COPY_AND_ASSIGN(FakeCompositorFrameSinkSupportClient);
+};
-class CompositorFrameSinkSupportTest : public testing::Test {
+class CompositorFrameSinkSupportTest : public testing::Test,
+ public SurfaceObserver {
public:
CompositorFrameSinkSupportTest()
- : surface_manager_(SurfaceManager::LifetimeType::REFERENCES) {}
- ~CompositorFrameSinkSupportTest() override {}
-
- CompositorFrameSinkSupport& display_support() { return *supports_[0]; }
- Surface* display_surface() {
- return display_support().current_surface_for_testing();
+ : support_(
+ CompositorFrameSinkSupport::Create(&fake_support_client_,
+ &manager_,
+ kArbitraryFrameSinkId,
+ kIsRoot,
+ kHandlesFrameSinkIdInvalidation,
+ kNeedsSyncPoints)),
+ local_surface_id_(3, kArbitraryToken),
+ frame_sync_token_(GenTestSyncToken(4)),
+ consumer_sync_token_(GenTestSyncToken(5)) {
+ manager_.AddObserver(this);
}
-
- CompositorFrameSinkSupport& parent_support() { return *supports_[1]; }
- Surface* parent_surface() {
- return parent_support().current_surface_for_testing();
- }
- const ReferencedSurfaceTracker& parent_reference_tracker() {
- return parent_support().ReferenceTrackerForTesting();
+ ~CompositorFrameSinkSupportTest() override {
+ manager_.RemoveObserver(this);
+ support_->EvictCurrentSurface();
}
- CompositorFrameSinkSupport& child_support1() { return *supports_[2]; }
- Surface* child_surface1() {
- return child_support1().current_surface_for_testing();
+ const SurfaceId& last_created_surface_id() const {
+ return last_created_surface_id_;
}
- CompositorFrameSinkSupport& child_support2() { return *supports_[3]; }
- Surface* child_surface2() {
- return child_support2().current_surface_for_testing();
+ // SurfaceObserver implementation.
+ void OnSurfaceCreated(const SurfaceInfo& surface_info) override {
+ last_created_surface_id_ = surface_info.id();
+ last_surface_info_ = surface_info;
}
-
- CompositorFrameSinkSupport& support(int index) { return *supports_[index]; }
- Surface* surface(int index) {
- return support(index).current_surface_for_testing();
+ void OnSurfaceDamaged(const SurfaceId& id, bool* changed) override {
+ *changed = true;
}
-
- SurfaceManager& surface_manager() { return surface_manager_; }
-
- // Returns all the references where |surface_id| is the parent.
- const SurfaceManager::SurfaceIdSet& GetChildReferences(
- const SurfaceId& surface_id) {
- return surface_manager().parent_to_child_refs_[surface_id];
- }
-
- // Returns true if there is a temporary reference for |surface_id|.
- bool HasTemporaryReference(const SurfaceId& surface_id) {
- return surface_manager().HasTemporaryReference(surface_id);
+ void OnSurfaceDiscarded(const SurfaceId& surface_id) override {}
+
+ void SubmitCompositorFrameWithResources(ResourceId* resource_ids,
+ size_t num_resource_ids) {
+ CompositorFrame frame = MakeCompositorFrame();
+ for (size_t i = 0u; i < num_resource_ids; ++i) {
+ TransferableResource resource;
+ resource.id = resource_ids[i];
+ resource.mailbox_holder.texture_target = GL_TEXTURE_2D;
+ resource.mailbox_holder.sync_token = frame_sync_token_;
+ frame.resource_list.push_back(resource);
+ }
+ support_->SubmitCompositorFrame(local_surface_id_, std::move(frame));
+ EXPECT_EQ(last_created_surface_id_.local_surface_id(), local_surface_id_);
}
- SurfaceDependencyTracker& dependency_tracker() {
- return *surface_manager_.dependency_tracker();
+ void UnrefResources(ResourceId* ids_to_unref,
+ int* counts_to_unref,
+ size_t num_ids_to_unref) {
+ ReturnedResourceArray unref_array;
+ for (size_t i = 0; i < num_ids_to_unref; ++i) {
+ ReturnedResource resource;
+ resource.sync_token = consumer_sync_token_;
+ resource.id = ids_to_unref[i];
+ resource.count = counts_to_unref[i];
+ unref_array.push_back(resource);
+ }
+ support_->UnrefResources(unref_array);
}
- FakeExternalBeginFrameSource* begin_frame_source() {
- return begin_frame_source_.get();
+ void CheckReturnedResourcesMatchExpected(ResourceId* expected_returned_ids,
+ int* expected_returned_counts,
+ size_t expected_resources,
+ gpu::SyncToken expected_sync_token) {
+ const ReturnedResourceArray& actual_resources =
+ fake_support_client_.returned_resources();
+ ASSERT_EQ(expected_resources, actual_resources.size());
+ for (size_t i = 0; i < expected_resources; ++i) {
+ ReturnedResource resource = actual_resources[i];
+ EXPECT_EQ(expected_sync_token, resource.sync_token);
+ EXPECT_EQ(expected_returned_ids[i], resource.id);
+ EXPECT_EQ(expected_returned_counts[i], resource.count);
+ }
+ fake_support_client_.clear_returned_resources();
}
- // testing::Test:
- void SetUp() override {
- testing::Test::SetUp();
- constexpr bool is_root = true;
- constexpr bool is_child_root = false;
- constexpr bool handles_frame_sink_id_invalidation = true;
- constexpr bool needs_sync_points = true;
- begin_frame_source_ =
- base::MakeUnique<FakeExternalBeginFrameSource>(0.f, false);
- surface_manager_.SetDependencyTracker(
- base::MakeUnique<SurfaceDependencyTracker>(&surface_manager_,
- begin_frame_source_.get()));
- supports_.push_back(CompositorFrameSinkSupport::Create(
- &support_client_, &surface_manager_, kDisplayFrameSink, is_root,
- handles_frame_sink_id_invalidation, needs_sync_points));
- supports_.push_back(CompositorFrameSinkSupport::Create(
- &support_client_, &surface_manager_, kParentFrameSink, is_child_root,
- handles_frame_sink_id_invalidation, needs_sync_points));
- supports_.push_back(CompositorFrameSinkSupport::Create(
- &support_client_, &surface_manager_, kChildFrameSink1, is_child_root,
- handles_frame_sink_id_invalidation, needs_sync_points));
- supports_.push_back(CompositorFrameSinkSupport::Create(
- &support_client_, &surface_manager_, kChildFrameSink2, is_child_root,
- handles_frame_sink_id_invalidation, needs_sync_points));
-
- // Normally, the BeginFrameSource would be registered by the Display. We
- // register it here so that BeginFrames are received by the display support,
- // for use in the PassesOnBeginFrameAcks test. Other supports do not receive
- // BeginFrames, since the frame sink hierarchy is not set up in this test.
- surface_manager_.RegisterBeginFrameSource(begin_frame_source_.get(),
- kDisplayFrameSink);
- }
-
- void TearDown() override {
- surface_manager_.SetDependencyTracker(nullptr);
- surface_manager_.UnregisterBeginFrameSource(begin_frame_source_.get());
-
- // SurfaceDependencyTracker depends on this BeginFrameSource and so it must
- // be destroyed AFTER the dependency tracker is destroyed.
- begin_frame_source_.reset();
-
- supports_.clear();
+ void RefCurrentFrameResources() {
+ Surface* surface = manager_.GetSurfaceForId(
+ SurfaceId(support_->frame_sink_id(), local_surface_id_));
+ support_->RefResources(surface->GetActiveFrame().resource_list);
}
protected:
- testing::NiceMock<MockCompositorFrameSinkSupportClient> support_client_;
-
- private:
- SurfaceManager surface_manager_;
- std::unique_ptr<FakeExternalBeginFrameSource> begin_frame_source_;
- std::vector<std::unique_ptr<CompositorFrameSinkSupport>> supports_;
-
- DISALLOW_COPY_AND_ASSIGN(CompositorFrameSinkSupportTest);
+ SurfaceManager manager_;
+ FakeCompositorFrameSinkSupportClient fake_support_client_;
+ std::unique_ptr<CompositorFrameSinkSupport> support_;
+ LocalSurfaceId local_surface_id_;
+ SurfaceId last_created_surface_id_;
+ SurfaceInfo last_surface_info_;
+
+ // This is the sync token submitted with the frame. It should never be
+ // returned to the client.
+ const gpu::SyncToken frame_sync_token_;
+
+ // This is the sync token returned by the consumer. It should always be
+ // returned to the client.
+ const gpu::SyncToken consumer_sync_token_;
};
-// The display root surface should have a surface reference from the top-level
-// root added/removed when a CompositorFrame is submitted with a new SurfaceId.
-TEST_F(CompositorFrameSinkSupportTest, RootSurfaceReceivesReferences) {
- const SurfaceId display_id_first = MakeSurfaceId(kDisplayFrameSink, 1);
- const SurfaceId display_id_second = MakeSurfaceId(kDisplayFrameSink, 2);
-
- // Submit a CompositorFrame for the first display root surface.
- display_support().SubmitCompositorFrame(display_id_first.local_surface_id(),
- MakeCompositorFrame());
-
- // A surface reference from the top-level root is added and there shouldn't be
- // a temporary reference.
- EXPECT_FALSE(HasTemporaryReference(display_id_first));
- EXPECT_THAT(GetChildReferences(surface_manager().GetRootSurfaceId()),
- UnorderedElementsAre(display_id_first));
-
- // Submit a CompositorFrame for the second display root surface.
- display_support().SubmitCompositorFrame(display_id_second.local_surface_id(),
- MakeCompositorFrame());
-
- // A surface reference from the top-level root to |display_id_second| should
- // be added and the reference to |display_root_first| removed.
- EXPECT_FALSE(HasTemporaryReference(display_id_second));
- EXPECT_THAT(GetChildReferences(surface_manager().GetRootSurfaceId()),
- UnorderedElementsAre(display_id_second));
-
- // Surface |display_id_first| is unreachable and should get deleted.
- EXPECT_EQ(nullptr, surface_manager().GetSurfaceForId(display_id_first));
+// Tests submitting a frame with resources followed by one with no resources
+// with no resource provider action in between.
+TEST_F(CompositorFrameSinkSupportTest, ResourceLifetimeSimple) {
+ ResourceId first_frame_ids[] = {1, 2, 3};
+ SubmitCompositorFrameWithResources(first_frame_ids,
+ arraysize(first_frame_ids));
+
+ // All of the resources submitted in the first frame are still in use at this
+ // time by virtue of being in the pending frame, so none can be returned to
+ // the client yet.
+ EXPECT_EQ(0u, fake_support_client_.returned_resources().size());
+ fake_support_client_.clear_returned_resources();
+
+ // The second frame references no resources of first frame and thus should
+ // make all resources of first frame available to be returned.
+ SubmitCompositorFrameWithResources(NULL, 0);
+
+ ResourceId expected_returned_ids[] = {1, 2, 3};
+ int expected_returned_counts[] = {1, 1, 1};
+ // Resources were never consumed so no sync token should be set.
+ CheckReturnedResourcesMatchExpected(
+ expected_returned_ids, expected_returned_counts,
+ arraysize(expected_returned_counts), gpu::SyncToken());
+
+ ResourceId third_frame_ids[] = {4, 5, 6};
+ SubmitCompositorFrameWithResources(third_frame_ids,
+ arraysize(third_frame_ids));
+
+ // All of the resources submitted in the third frame are still in use at this
+ // time by virtue of being in the pending frame, so none can be returned to
+ // the client yet.
+ EXPECT_EQ(0u, fake_support_client_.returned_resources().size());
+ fake_support_client_.clear_returned_resources();
+
+ // The forth frame references no resources of third frame and thus should
+ // make all resources of third frame available to be returned.
+ ResourceId forth_frame_ids[] = {7, 8, 9};
+ SubmitCompositorFrameWithResources(forth_frame_ids,
+ arraysize(forth_frame_ids));
+
+ ResourceId forth_expected_returned_ids[] = {4, 5, 6};
+ int forth_expected_returned_counts[] = {1, 1, 1};
+ // Resources were never consumed so no sync token should be set.
+ CheckReturnedResourcesMatchExpected(
+ forth_expected_returned_ids, forth_expected_returned_counts,
+ arraysize(forth_expected_returned_counts), gpu::SyncToken());
}
-// The parent Surface is blocked on |child_id1| and |child_id2|.
-TEST_F(CompositorFrameSinkSupportTest, DisplayCompositorLockingBlockedOnTwo) {
- const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
- const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
- const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1);
-
- parent_support().SubmitCompositorFrame(
- parent_id.local_surface_id(),
- MakeCompositorFrame({child_id1, child_id2}));
-
- // parent_support is blocked on |child_id1| and |child_id2|.
- EXPECT_TRUE(dependency_tracker().has_deadline());
- EXPECT_FALSE(parent_surface()->HasActiveFrame());
- EXPECT_TRUE(parent_surface()->HasPendingFrame());
- EXPECT_THAT(parent_surface()->blocking_surfaces(),
- UnorderedElementsAre(child_id1, child_id2));
-
- // Submit a CompositorFrame without any dependencies to |child_id1|.
- // parent_support should now only be blocked on |child_id2|.
- child_support1().SubmitCompositorFrame(
- child_id1.local_surface_id(), MakeCompositorFrame(empty_surface_ids()));
-
- EXPECT_TRUE(dependency_tracker().has_deadline());
- EXPECT_FALSE(parent_surface()->HasActiveFrame());
- EXPECT_TRUE(parent_surface()->HasPendingFrame());
- EXPECT_THAT(parent_surface()->blocking_surfaces(),
- UnorderedElementsAre(child_id2));
-
- // Submit a CompositorFrame without any dependencies to |child_id2|.
- // parent_support should be activated.
- child_support2().SubmitCompositorFrame(
- child_id2.local_surface_id(), MakeCompositorFrame(empty_surface_ids()));
-
- EXPECT_FALSE(dependency_tracker().has_deadline());
- EXPECT_TRUE(parent_surface()->HasActiveFrame());
- EXPECT_FALSE(parent_surface()->HasPendingFrame());
- EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty());
+// Tests submitting a frame with resources followed by one with no resources
+// with the resource provider holding everything alive.
+TEST_F(CompositorFrameSinkSupportTest,
+ ResourceLifetimeSimpleWithProviderHoldingAlive) {
+ ResourceId first_frame_ids[] = {1, 2, 3};
+ SubmitCompositorFrameWithResources(first_frame_ids,
+ arraysize(first_frame_ids));
+
+ // All of the resources submitted in the first frame are still in use at this
+ // time by virtue of being in the pending frame, so none can be returned to
+ // the client yet.
+ EXPECT_EQ(0u, fake_support_client_.returned_resources().size());
+ fake_support_client_.clear_returned_resources();
+
+ // Hold on to everything.
+ RefCurrentFrameResources();
+
+ // The second frame references no resources and thus should make all resources
+ // available to be returned as soon as the resource provider releases them.
+ SubmitCompositorFrameWithResources(NULL, 0);
+
+ EXPECT_EQ(0u, fake_support_client_.returned_resources().size());
+ fake_support_client_.clear_returned_resources();
+
+ int release_counts[] = {1, 1, 1};
+ UnrefResources(first_frame_ids, release_counts, arraysize(first_frame_ids));
+
+ // None is returned to the client since DidReceiveCompositorAck is not
+ // invoked.
+ EXPECT_EQ(0u, fake_support_client_.returned_resources().size());
+
+ // Submitting an empty frame causes previous resources referenced by the
+ // previous frame to be returned to client.
+ SubmitCompositorFrameWithResources(nullptr, 0);
+ ResourceId expected_returned_ids[] = {1, 2, 3};
+ int expected_returned_counts[] = {1, 1, 1};
+ CheckReturnedResourcesMatchExpected(
+ expected_returned_ids, expected_returned_counts,
+ arraysize(expected_returned_counts), consumer_sync_token_);
}
-// The parent Surface is blocked on |child_id2| which is blocked on |child_id3|.
-TEST_F(CompositorFrameSinkSupportTest, DisplayCompositorLockingBlockedChain) {
- const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
- const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
- const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1);
-
- parent_support().SubmitCompositorFrame(parent_id.local_surface_id(),
- MakeCompositorFrame({child_id1}));
-
- // parent_support is blocked on |child_id1|.
- EXPECT_TRUE(dependency_tracker().has_deadline());
- EXPECT_FALSE(parent_surface()->HasActiveFrame());
- EXPECT_TRUE(parent_surface()->HasPendingFrame());
- EXPECT_THAT(parent_surface()->blocking_surfaces(),
- UnorderedElementsAre(child_id1));
-
- child_support1().SubmitCompositorFrame(child_id1.local_surface_id(),
- MakeCompositorFrame({child_id2}));
-
- // child_support1 should now be blocked on |child_id2|.
- EXPECT_TRUE(dependency_tracker().has_deadline());
- EXPECT_FALSE(child_surface1()->HasActiveFrame());
- EXPECT_TRUE(child_surface1()->HasPendingFrame());
- EXPECT_THAT(child_surface1()->blocking_surfaces(),
- UnorderedElementsAre(child_id2));
-
- // The parent should still be blocked on |child_id1| because it's pending.
- EXPECT_THAT(parent_surface()->blocking_surfaces(),
- UnorderedElementsAre(child_id1));
-
- // Submit a CompositorFrame without any dependencies to |child_id2|.
- // parent_support should be activated.
- child_support2().SubmitCompositorFrame(
- child_id2.local_surface_id(), MakeCompositorFrame(empty_surface_ids()));
-
- EXPECT_FALSE(dependency_tracker().has_deadline());
-
- // child_surface1 should now be active.
- EXPECT_TRUE(child_surface1()->HasActiveFrame());
- EXPECT_FALSE(child_surface1()->HasPendingFrame());
- EXPECT_THAT(child_surface1()->blocking_surfaces(), IsEmpty());
-
- // parent_surface should now be active.
- EXPECT_TRUE(parent_surface()->HasActiveFrame());
- EXPECT_FALSE(parent_surface()->HasPendingFrame());
- EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty());
+// Tests referencing a resource, unref'ing it to zero, then using it again
+// before returning it to the client.
+TEST_F(CompositorFrameSinkSupportTest, ResourceReusedBeforeReturn) {
+ ResourceId first_frame_ids[] = {7};
+ SubmitCompositorFrameWithResources(first_frame_ids,
+ arraysize(first_frame_ids));
+
+ // This removes all references to resource id 7.
+ SubmitCompositorFrameWithResources(NULL, 0);
+
+ // This references id 7 again.
+ SubmitCompositorFrameWithResources(first_frame_ids,
+ arraysize(first_frame_ids));
+
+ // This removes it again.
+ SubmitCompositorFrameWithResources(NULL, 0);
+
+ // Now it should be returned.
+ // We don't care how many entries are in the returned array for 7, so long as
+ // the total returned count matches the submitted count.
+ const ReturnedResourceArray& returned =
+ fake_support_client_.returned_resources();
+ size_t return_count = 0;
+ for (size_t i = 0; i < returned.size(); ++i) {
+ EXPECT_EQ(7u, returned[i].id);
+ return_count += returned[i].count;
+ }
+ EXPECT_EQ(2u, return_count);
}
-// parent_surface and child_surface1 are blocked on |child_id2|.
-TEST_F(CompositorFrameSinkSupportTest,
- DisplayCompositorLockingTwoBlockedOnOne) {
- const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
- const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
- const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1);
-
- parent_support().SubmitCompositorFrame(parent_id.local_surface_id(),
- MakeCompositorFrame({child_id2}));
-
- // parent_support is blocked on |child_id2|.
- EXPECT_TRUE(dependency_tracker().has_deadline());
- EXPECT_FALSE(parent_surface()->HasActiveFrame());
- EXPECT_TRUE(parent_surface()->HasPendingFrame());
- EXPECT_THAT(parent_surface()->blocking_surfaces(),
- UnorderedElementsAre(child_id2));
-
- // child_support1 should now be blocked on |child_id2|.
- child_support1().SubmitCompositorFrame(child_id1.local_surface_id(),
- MakeCompositorFrame({child_id2}));
-
- EXPECT_TRUE(dependency_tracker().has_deadline());
- EXPECT_FALSE(child_surface1()->HasActiveFrame());
- EXPECT_TRUE(child_surface1()->HasPendingFrame());
- EXPECT_THAT(child_surface1()->blocking_surfaces(),
- UnorderedElementsAre(child_id2));
-
- // The parent should still be blocked on |child_id2|.
- EXPECT_THAT(parent_surface()->blocking_surfaces(),
- UnorderedElementsAre(child_id2));
-
- // Submit a CompositorFrame without any dependencies to |child_id2|.
- // parent_support should be activated.
- child_support2().SubmitCompositorFrame(
- child_id2.local_surface_id(), MakeCompositorFrame(empty_surface_ids()));
-
- EXPECT_FALSE(dependency_tracker().has_deadline());
-
- // child_surface1 should now be active.
- EXPECT_TRUE(child_surface1()->HasActiveFrame());
- EXPECT_FALSE(child_surface1()->HasPendingFrame());
- EXPECT_THAT(child_surface1()->blocking_surfaces(), IsEmpty());
-
- // parent_surface should now be active.
- EXPECT_TRUE(parent_surface()->HasActiveFrame());
- EXPECT_FALSE(parent_surface()->HasPendingFrame());
- EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty());
+// Tests having resources referenced multiple times, as if referenced by
+// multiple providers.
+TEST_F(CompositorFrameSinkSupportTest, ResourceRefMultipleTimes) {
+ ResourceId first_frame_ids[] = {3, 4};
+ SubmitCompositorFrameWithResources(first_frame_ids,
+ arraysize(first_frame_ids));
+
+ // Ref resources from the first frame twice.
+ RefCurrentFrameResources();
+ RefCurrentFrameResources();
+
+ ResourceId second_frame_ids[] = {4, 5};
+ SubmitCompositorFrameWithResources(second_frame_ids,
+ arraysize(second_frame_ids));
+
+ // Ref resources from the second frame 3 times.
+ RefCurrentFrameResources();
+ RefCurrentFrameResources();
+ RefCurrentFrameResources();
+
+ // Submit a frame with no resources to remove all current frame refs from
+ // submitted resources.
+ SubmitCompositorFrameWithResources(NULL, 0);
+
+ EXPECT_EQ(0u, fake_support_client_.returned_resources().size());
+ fake_support_client_.clear_returned_resources();
+
+ // Expected current refs:
+ // 3 -> 2
+ // 4 -> 2 + 3 = 5
+ // 5 -> 3
+ {
+ SCOPED_TRACE("unref all 3");
+ ResourceId ids_to_unref[] = {3, 4, 5};
+ int counts[] = {1, 1, 1};
+ UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref));
+
+ EXPECT_EQ(0u, fake_support_client_.returned_resources().size());
+ fake_support_client_.clear_returned_resources();
+
+ UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref));
+ SubmitCompositorFrameWithResources(nullptr, 0);
+ ResourceId expected_returned_ids[] = {3};
+ int expected_returned_counts[] = {1};
+ CheckReturnedResourcesMatchExpected(
+ expected_returned_ids, expected_returned_counts,
+ arraysize(expected_returned_counts), consumer_sync_token_);
+ }
+
+ // Expected refs remaining:
+ // 4 -> 3
+ // 5 -> 1
+ {
+ SCOPED_TRACE("unref 4 and 5");
+ ResourceId ids_to_unref[] = {4, 5};
+ int counts[] = {1, 1};
+ UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref));
+ SubmitCompositorFrameWithResources(nullptr, 0);
+
+ ResourceId expected_returned_ids[] = {5};
+ int expected_returned_counts[] = {1};
+ CheckReturnedResourcesMatchExpected(
+ expected_returned_ids, expected_returned_counts,
+ arraysize(expected_returned_counts), consumer_sync_token_);
+ }
+
+ // Now, just 2 refs remaining on resource 4. Unref both at once and make sure
+ // the returned count is correct.
+ {
+ SCOPED_TRACE("unref only 4");
+ ResourceId ids_to_unref[] = {4};
+ int counts[] = {2};
+ UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref));
+ SubmitCompositorFrameWithResources(nullptr, 0);
+
+ ResourceId expected_returned_ids[] = {4};
+ int expected_returned_counts[] = {2};
+ CheckReturnedResourcesMatchExpected(
+ expected_returned_ids, expected_returned_counts,
+ arraysize(expected_returned_counts), consumer_sync_token_);
+ }
}
-// parent_surface is blocked on |child_id1|, and child_surface2 is blocked on
-// |child_id2| until the deadline hits.
-TEST_F(CompositorFrameSinkSupportTest, DisplayCompositorLockingDeadlineHits) {
- const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
- const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
- const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1);
-
- parent_support().SubmitCompositorFrame(parent_id.local_surface_id(),
- MakeCompositorFrame({child_id1}));
-
- // parent_support is blocked on |child_id1|.
- EXPECT_TRUE(dependency_tracker().has_deadline());
- EXPECT_FALSE(parent_surface()->HasActiveFrame());
- EXPECT_TRUE(parent_surface()->HasPendingFrame());
- EXPECT_THAT(parent_surface()->blocking_surfaces(),
- UnorderedElementsAre(child_id1));
-
- child_support1().SubmitCompositorFrame(child_id1.local_surface_id(),
- MakeCompositorFrame({child_id2}));
-
- // child_support1 should now be blocked on |child_id2|.
- EXPECT_TRUE(dependency_tracker().has_deadline());
- EXPECT_FALSE(child_surface1()->HasActiveFrame());
- EXPECT_TRUE(child_surface1()->HasPendingFrame());
- EXPECT_THAT(child_surface1()->blocking_surfaces(),
- UnorderedElementsAre(child_id2));
-
- // The parent should still be blocked on |child_id1| because it's pending.
- EXPECT_THAT(parent_surface()->blocking_surfaces(),
- UnorderedElementsAre(child_id1));
-
- BeginFrameArgs args =
- CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1);
-
- for (int i = 0; i < 3; ++i) {
- begin_frame_source()->TestOnBeginFrame(args);
- // There is still a looming deadline! Eeek!
- EXPECT_TRUE(dependency_tracker().has_deadline());
-
- // parent_support is still blocked on |child_id1|.
- EXPECT_FALSE(parent_surface()->HasActiveFrame());
- EXPECT_TRUE(parent_surface()->HasPendingFrame());
- EXPECT_THAT(parent_surface()->blocking_surfaces(),
- UnorderedElementsAre(child_id1));
-
- // child_support1 is still blocked on |child_id2|.
- EXPECT_FALSE(child_surface1()->HasActiveFrame());
- EXPECT_TRUE(child_surface1()->HasPendingFrame());
- EXPECT_THAT(child_surface1()->blocking_surfaces(),
- UnorderedElementsAre(child_id2));
+TEST_F(CompositorFrameSinkSupportTest, ResourceLifetime) {
+ ResourceId first_frame_ids[] = {1, 2, 3};
+ SubmitCompositorFrameWithResources(first_frame_ids,
+ arraysize(first_frame_ids));
+
+ // All of the resources submitted in the first frame are still in use at this
+ // time by virtue of being in the pending frame, so none can be returned to
+ // the client yet.
+ EXPECT_EQ(0u, fake_support_client_.returned_resources().size());
+ fake_support_client_.clear_returned_resources();
+
+ // The second frame references some of the same resources, but some different
+ // ones. We expect to receive back resource 1 with a count of 1 since it was
+ // only referenced by the first frame.
+ ResourceId second_frame_ids[] = {2, 3, 4};
+ SubmitCompositorFrameWithResources(second_frame_ids,
+ arraysize(second_frame_ids));
+ {
+ SCOPED_TRACE("second frame");
+ ResourceId expected_returned_ids[] = {1};
+ int expected_returned_counts[] = {1};
+ CheckReturnedResourcesMatchExpected(
+ expected_returned_ids, expected_returned_counts,
+ arraysize(expected_returned_counts), gpu::SyncToken());
}
- begin_frame_source()->TestOnBeginFrame(args);
+ // The third frame references a disjoint set of resources, so we expect to
+ // receive back all resources from the first and second frames. Resource IDs 2
+ // and 3 will have counts of 2, since they were used in both frames, and
+ // resource ID 4 will have a count of 1.
+ ResourceId third_frame_ids[] = {10, 11, 12, 13};
+ SubmitCompositorFrameWithResources(third_frame_ids,
+ arraysize(third_frame_ids));
+
+ {
+ SCOPED_TRACE("third frame");
+ ResourceId expected_returned_ids[] = {2, 3, 4};
+ int expected_returned_counts[] = {2, 2, 1};
+ CheckReturnedResourcesMatchExpected(
+ expected_returned_ids, expected_returned_counts,
+ arraysize(expected_returned_counts), gpu::SyncToken());
+ }
- // The deadline has passed.
- EXPECT_FALSE(dependency_tracker().has_deadline());
+ // Simulate a ResourceProvider taking a ref on all of the resources.
+ RefCurrentFrameResources();
- // parent_surface has been activated.
- EXPECT_TRUE(parent_surface()->HasActiveFrame());
- EXPECT_FALSE(parent_surface()->HasPendingFrame());
- EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty());
+ ResourceId fourth_frame_ids[] = {12, 13};
+ SubmitCompositorFrameWithResources(fourth_frame_ids,
+ arraysize(fourth_frame_ids));
- // child_surface1 has been activated.
- EXPECT_TRUE(child_surface1()->HasActiveFrame());
- EXPECT_FALSE(child_surface1()->HasPendingFrame());
- EXPECT_THAT(child_surface1()->blocking_surfaces(), IsEmpty());
-}
+ EXPECT_EQ(0u, fake_support_client_.returned_resources().size());
-// Verifies that the deadline does not reset if we submit CompositorFrames
-// to new Surfaces with unresolved dependencies.
-TEST_F(CompositorFrameSinkSupportTest,
- DisplayCompositorLockingFramesSubmittedAfterDeadlineSet) {
- const SurfaceId arbitrary_id = MakeSurfaceId(kArbitraryFrameSink, 1);
- BeginFrameArgs args =
- CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1);
- for (int i = 0; i < 3; ++i) {
- LocalSurfaceId local_surface_id(1, base::UnguessableToken::Create());
- support(i).SubmitCompositorFrame(local_surface_id,
- MakeCompositorFrame({arbitrary_id}));
- // The deadline has been set.
- EXPECT_TRUE(dependency_tracker().has_deadline());
-
- // support(i) should be blocked on arbitrary_id.
- EXPECT_FALSE(surface(i)->HasActiveFrame());
- EXPECT_TRUE(surface(i)->HasPendingFrame());
- EXPECT_THAT(surface(i)->blocking_surfaces(),
- UnorderedElementsAre(arbitrary_id));
-
- // Issue a BeginFrame to get closer to the deadline.
- begin_frame_source()->TestOnBeginFrame(args);
+ RefCurrentFrameResources();
+
+ // All resources are still being used by the external reference, so none can
+ // be returned to the client.
+ EXPECT_EQ(0u, fake_support_client_.returned_resources().size());
+
+ // Release resources associated with the first RefCurrentFrameResources() call
+ // first.
+ {
+ ResourceId ids_to_unref[] = {10, 11, 12, 13};
+ int counts[] = {1, 1, 1, 1};
+ UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref));
}
- // The deadline hits and all the Surfaces should activate.
- begin_frame_source()->TestOnBeginFrame(args);
- for (int i = 0; i < 3; ++i) {
- EXPECT_TRUE(surface(i)->HasActiveFrame());
- EXPECT_FALSE(surface(i)->HasPendingFrame());
- EXPECT_THAT(surface(i)->blocking_surfaces(), IsEmpty());
+ // Nothing is returned to the client yet since DidReceiveCompositorFrameAck
+ // is not invoked.
+ {
+ SCOPED_TRACE("fourth frame, first unref");
+ CheckReturnedResourcesMatchExpected(nullptr, nullptr, 0,
+ consumer_sync_token_);
}
-}
-// This test verifies at the Surface activates once a CompositorFrame is
-// submitted that has no unresolved dependencies.
-TEST_F(CompositorFrameSinkSupportTest,
- DisplayCompositorLockingNewFrameOverridesOldDependencies) {
- const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
- const SurfaceId arbitrary_id = MakeSurfaceId(kArbitraryFrameSink, 1);
-
- // Submit a CompositorFrame that depends on |arbitrary_id|.
- parent_support().SubmitCompositorFrame(parent_id.local_surface_id(),
- MakeCompositorFrame({arbitrary_id}));
-
- // Verify that the CompositorFrame is blocked on |arbitrary_id|.
- EXPECT_FALSE(parent_surface()->HasActiveFrame());
- EXPECT_TRUE(parent_surface()->HasPendingFrame());
- EXPECT_THAT(parent_surface()->blocking_surfaces(),
- UnorderedElementsAre(arbitrary_id));
-
- // Submit a CompositorFrame that has no dependencies.
- parent_support().SubmitCompositorFrame(
- parent_id.local_surface_id(), MakeCompositorFrame(empty_surface_ids()));
-
- // Verify that the CompositorFrame has been activated.
- EXPECT_TRUE(parent_surface()->HasActiveFrame());
- EXPECT_FALSE(parent_surface()->HasPendingFrame());
- EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty());
-}
+ {
+ ResourceId ids_to_unref[] = {12, 13};
+ int counts[] = {1, 1};
+ UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref));
+ }
-// This test verifies that a pending CompositorFrame does not affect surface
-// references. A new surface from a child will continue to exist as a temporary
-// reference until the parent's frame activates.
-TEST_F(CompositorFrameSinkSupportTest,
- OnlyActiveFramesAffectSurfaceReferences) {
- const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
- const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
- const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1);
-
- // child_support1 submits a CompositorFrame without any dependencies.
- child_support1().SubmitCompositorFrame(child_id1.local_surface_id(),
- MakeCompositorFrame());
-
- // Verify that the child surface is not blocked.
- EXPECT_TRUE(child_surface1()->HasActiveFrame());
- EXPECT_FALSE(child_surface1()->HasPendingFrame());
- EXPECT_THAT(child_surface1()->blocking_surfaces(), IsEmpty());
-
- // Verify that there's a temporary reference for |child_id1|.
- EXPECT_TRUE(HasTemporaryReference(child_id1));
-
- // parent_support submits a CompositorFrame that depends on |child_id1|
- // (which is already active) and |child_id2|. Thus, the parent should not
- // activate immediately.
- parent_support().SubmitCompositorFrame(
- parent_id.local_surface_id(),
- MakeCompositorFrame({child_id1, child_id2}));
- EXPECT_FALSE(parent_surface()->HasActiveFrame());
- EXPECT_TRUE(parent_surface()->HasPendingFrame());
- EXPECT_THAT(parent_surface()->blocking_surfaces(),
- UnorderedElementsAre(child_id2));
- EXPECT_THAT(GetChildReferences(parent_id), IsEmpty());
-
- // Verify that there's a temporary reference for |child_id1| that still
- // exists.
- EXPECT_TRUE(HasTemporaryReference(child_id1));
-
- // child_support2 submits a CompositorFrame without any dependencies.
- child_support2().SubmitCompositorFrame(child_id2.local_surface_id(),
- MakeCompositorFrame());
-
- // Verify that the child surface is not blocked.
- EXPECT_TRUE(child_surface1()->HasActiveFrame());
- EXPECT_FALSE(child_surface1()->HasPendingFrame());
- EXPECT_THAT(child_surface1()->blocking_surfaces(), IsEmpty());
-
- // Verify that the parent surface's CompositorFrame has activated and that the
- // temporary reference has been replaced by a permanent one.
- EXPECT_TRUE(parent_surface()->HasActiveFrame());
- EXPECT_FALSE(parent_surface()->HasPendingFrame());
- EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty());
- EXPECT_FALSE(HasTemporaryReference(child_id1));
- EXPECT_THAT(GetChildReferences(parent_id),
- UnorderedElementsAre(child_id1, child_id2));
+ // Resources 12 and 13 are still in use by the current frame, so they
+ // shouldn't be available to be returned.
+ EXPECT_EQ(0u, fake_support_client_.returned_resources().size());
+
+ // If we submit an empty frame, however, they should become available.
+ // Resources that were previously unref'd also return at this point.
+ SubmitCompositorFrameWithResources(NULL, 0u);
+
+ {
+ SCOPED_TRACE("fourth frame, second unref");
+ ResourceId expected_returned_ids[] = {10, 11, 12, 13};
+ int expected_returned_counts[] = {1, 1, 2, 2};
+ CheckReturnedResourcesMatchExpected(
+ expected_returned_ids, expected_returned_counts,
+ arraysize(expected_returned_counts), consumer_sync_token_);
+ }
}
-// This test verifies that we do not double count returned resources when a
-// CompositorFrame starts out as pending, then becomes active, and then is
-// replaced with another active CompositorFrame.
-TEST_F(CompositorFrameSinkSupportTest,
- DisplayCompositorLockingResourcesOnlyReturnedOnce) {
- const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
- const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 1);
-
- // The parent submits a CompositorFrame that depends on |child_id| before the
- // child submits a CompositorFrame. The CompositorFrame also has resources in
- // its resource list.
- TransferableResource resource =
- MakeResource(1337 /* id */, ALPHA_8 /* format */, 1234 /* filter */,
- gfx::Size(1234, 5678));
- TransferableResourceArray resource_list = {resource};
- parent_support().SubmitCompositorFrame(
- parent_id.local_surface_id(),
- MakeCompositorFrameWithResources({child_id}, resource_list));
-
- // Verify that the CompositorFrame is blocked on |child_id|.
- EXPECT_FALSE(parent_surface()->HasActiveFrame());
- EXPECT_TRUE(parent_surface()->HasPendingFrame());
- EXPECT_THAT(parent_surface()->blocking_surfaces(),
- UnorderedElementsAre(child_id));
-
- child_support1().SubmitCompositorFrame(
- child_id.local_surface_id(), MakeCompositorFrame(empty_surface_ids()));
-
- // Verify that the child CompositorFrame activates immediately.
- EXPECT_TRUE(child_surface1()->HasActiveFrame());
- EXPECT_FALSE(child_surface1()->HasPendingFrame());
- EXPECT_THAT(child_surface1()->blocking_surfaces(), IsEmpty());
-
- // Verify that the parent has activated.
- EXPECT_TRUE(parent_surface()->HasActiveFrame());
- EXPECT_FALSE(parent_surface()->HasPendingFrame());
- EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty());
-
- // The parent submits a CompositorFrame without any dependencies. That frame
- // should activate immediately, replacing the earlier frame. The resource from
- // the earlier frame should be returned to the client.
- parent_support().SubmitCompositorFrame(
- parent_id.local_surface_id(), MakeCompositorFrame({empty_surface_ids()}));
- EXPECT_TRUE(parent_surface()->HasActiveFrame());
- EXPECT_FALSE(parent_surface()->HasPendingFrame());
- EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty());
- ReturnedResource returned_resource = resource.ToReturnedResource();
- EXPECT_THAT(support_client_.last_returned_resources(),
- UnorderedElementsAre(returned_resource));
+TEST_F(CompositorFrameSinkSupportTest, AddDuringEviction) {
+ MockCompositorFrameSinkSupportClient mock_client;
+ std::unique_ptr<CompositorFrameSinkSupport> support =
+ CompositorFrameSinkSupport::Create(
+ &mock_client, &manager_, kAnotherArbitraryFrameSinkId, kIsRoot,
+ kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ LocalSurfaceId local_surface_id(6, kArbitraryToken);
+ support->SubmitCompositorFrame(local_surface_id, MakeCompositorFrame());
+
+ EXPECT_CALL(mock_client, DidReceiveCompositorFrameAck(_))
+ .WillOnce(testing::InvokeWithoutArgs([&support, &mock_client]() {
+ LocalSurfaceId new_id(7, base::UnguessableToken::Create());
+ support->SubmitCompositorFrame(new_id, MakeCompositorFrame());
+ }))
+ .WillRepeatedly(testing::Return());
+ support->EvictCurrentSurface();
}
-// The parent Surface is blocked on |child_id2| which is blocked on |child_id3|.
-// child_support1 evicts its blocked Surface. The parent surface should
-// activate.
-TEST_F(CompositorFrameSinkSupportTest, EvictSurfaceWithPendingFrame) {
- const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
- const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
- const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1);
-
- // Submit a CompositorFrame that depends on |child_id1|.
- parent_support().SubmitCompositorFrame(parent_id1.local_surface_id(),
- MakeCompositorFrame({child_id1}));
-
- // Verify that the CompositorFrame is blocked on |child_id1|.
- EXPECT_FALSE(parent_surface()->HasActiveFrame());
- EXPECT_TRUE(parent_surface()->HasPendingFrame());
- EXPECT_THAT(parent_surface()->blocking_surfaces(),
- UnorderedElementsAre(child_id1));
-
- // Submit a CompositorFrame that depends on |child_id2|.
- child_support1().SubmitCompositorFrame(child_id1.local_surface_id(),
- MakeCompositorFrame({child_id2}));
-
- // Verify that the CompositorFrame is blocked on |child_id2|.
- EXPECT_FALSE(child_surface1()->HasActiveFrame());
- EXPECT_TRUE(child_surface1()->HasPendingFrame());
- EXPECT_THAT(child_surface1()->blocking_surfaces(),
- UnorderedElementsAre(child_id2));
-
- // Evict child_support1's current Surface.
- // TODO(fsamuel): EvictFrame => EvictCurrentSurface.
- child_support1().EvictFrame();
-
- // The parent Surface should immediately activate.
- EXPECT_TRUE(parent_surface()->HasActiveFrame());
- EXPECT_FALSE(parent_surface()->HasPendingFrame());
- EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty());
- EXPECT_FALSE(dependency_tracker().has_deadline());
-}
+// Tests doing an EvictCurrentSurface before shutting down the factory.
+TEST_F(CompositorFrameSinkSupportTest, EvictCurrentSurface) {
+ MockCompositorFrameSinkSupportClient mock_client;
+ std::unique_ptr<CompositorFrameSinkSupport> support =
+ CompositorFrameSinkSupport::Create(
+ &mock_client, &manager_, kAnotherArbitraryFrameSinkId, kIsRoot,
+ kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ LocalSurfaceId local_surface_id(7, kArbitraryToken);
+ SurfaceId id(kAnotherArbitraryFrameSinkId, local_surface_id);
-// This test verifies that if a surface has both a pending and active
-// CompositorFrame and the pending CompositorFrame activates, replacing the
-// existing active CompositorFrame, then the surface reference hierarchy will be
-// updated allowing garbage collection of surfaces that are no longer
-// referenced.
-TEST_F(CompositorFrameSinkSupportTest, DropStaleReferencesAfterActivation) {
- const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
- const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
- const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1);
-
- // The parent submits a CompositorFrame that depends on |child_id1| before the
- // child submits a CompositorFrame.
- parent_support().SubmitCompositorFrame(parent_id.local_surface_id(),
- MakeCompositorFrame({child_id1}));
-
- // Verify that the CompositorFrame is blocked on |child_id|.
- EXPECT_FALSE(parent_surface()->HasActiveFrame());
- EXPECT_TRUE(parent_surface()->HasPendingFrame());
- EXPECT_THAT(parent_surface()->blocking_surfaces(),
- UnorderedElementsAre(child_id1));
-
- // Verify that no references are added while the CompositorFrame is pending.
- EXPECT_THAT(GetChildReferences(parent_id), IsEmpty());
-
- child_support1().SubmitCompositorFrame(
- child_id1.local_surface_id(), MakeCompositorFrame(empty_surface_ids()));
-
- // Verify that the child CompositorFrame activates immediately.
- EXPECT_TRUE(child_surface1()->HasActiveFrame());
- EXPECT_FALSE(child_surface1()->HasPendingFrame());
- EXPECT_THAT(child_surface1()->blocking_surfaces(), IsEmpty());
-
- // Verify that the parent Surface has activated.
- EXPECT_TRUE(parent_surface()->HasActiveFrame());
- EXPECT_FALSE(parent_surface()->HasPendingFrame());
- EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty());
-
- // Verify that there is no temporary reference for the child and that
- // the reference from the parent to the child still exists.
- EXPECT_FALSE(HasTemporaryReference(child_id1));
- EXPECT_THAT(GetChildReferences(parent_id), UnorderedElementsAre(child_id1));
-
- // The parent submits another CompositorFrame that depends on |child_id2|.
- parent_support().SubmitCompositorFrame(parent_id.local_surface_id(),
- MakeCompositorFrame({child_id2}));
-
- // The parent surface should now have both a pending and activate
- // CompositorFrame. Verify that the set of child references from
- // |parent_id| are only from the active CompositorFrame.
- EXPECT_TRUE(parent_surface()->HasActiveFrame());
- EXPECT_TRUE(parent_surface()->HasPendingFrame());
- EXPECT_THAT(parent_surface()->blocking_surfaces(),
- UnorderedElementsAre(child_id2));
- EXPECT_THAT(GetChildReferences(parent_id), UnorderedElementsAre(child_id1));
-
- child_support2().SubmitCompositorFrame(
- child_id2.local_surface_id(), MakeCompositorFrame(empty_surface_ids()));
-
- // Verify that the parent Surface has activated and no longer has a pending
- // CompositorFrame. Also verify that |child_id1| is no longer a child
- // reference of |parent_id|.
- EXPECT_TRUE(parent_surface()->HasActiveFrame());
- EXPECT_FALSE(parent_surface()->HasPendingFrame());
- EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty());
- EXPECT_THAT(GetChildReferences(parent_id), UnorderedElementsAre(child_id2));
+ TransferableResource resource;
+ resource.id = 1;
+ resource.mailbox_holder.texture_target = GL_TEXTURE_2D;
+ CompositorFrame frame = MakeCompositorFrame();
+ frame.resource_list.push_back(resource);
+ support->SubmitCompositorFrame(local_surface_id, std::move(frame));
+ EXPECT_EQ(last_created_surface_id().local_surface_id(), local_surface_id);
+ local_surface_id_ = LocalSurfaceId();
+
+ ReturnedResourceArray returned_resources = {resource.ToReturnedResource()};
+ EXPECT_TRUE(manager_.GetSurfaceForId(id));
+ EXPECT_CALL(mock_client, DidReceiveCompositorFrameAck(returned_resources))
+ .Times(1);
+ support->EvictCurrentSurface();
+ EXPECT_FALSE(manager_.GetSurfaceForId(id));
}
-// Checks whether the latency info are moved to the new surface from the old
-// one when LocalSurfaceId changes. No frame has unresolved dependencies.
+// Tests doing an EvictCurrentSurface which has unregistered dependency.
TEST_F(CompositorFrameSinkSupportTest,
- LatencyInfoCarriedOverOnResize_NoUnresolvedDependencies) {
- const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
- const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2);
- const ui::LatencyComponentType latency_type1 =
- ui::BROWSER_SNAPSHOT_FRAME_NUMBER_COMPONENT;
- const int64_t latency_id1 = 234;
- const int64_t latency_sequence_number1 = 5645432;
- const ui::LatencyComponentType latency_type2 = ui::TAB_SHOW_COMPONENT;
- const int64_t latency_id2 = 31434351;
- const int64_t latency_sequence_number2 = 663788;
-
- // Submit a frame with latency info
- ui::LatencyInfo info;
- info.AddLatencyNumber(latency_type1, latency_id1, latency_sequence_number1);
+ EvictCurrentSurfaceDependencyUnRegistered) {
+ MockCompositorFrameSinkSupportClient mock_client;
+ std::unique_ptr<CompositorFrameSinkSupport> support =
+ CompositorFrameSinkSupport::Create(
+ &mock_client, &manager_, kAnotherArbitraryFrameSinkId, kIsRoot,
+ kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ LocalSurfaceId local_surface_id(7, kArbitraryToken);
+ TransferableResource resource;
+ resource.id = 1;
+ resource.mailbox_holder.texture_target = GL_TEXTURE_2D;
CompositorFrame frame = MakeCompositorFrame();
- frame.metadata.latency_info.push_back(info);
-
- parent_support().SubmitCompositorFrame(parent_id1.local_surface_id(),
- std::move(frame));
-
- // Verify that the old surface has an active frame and no pending frame.
- Surface* old_surface = surface_manager().GetSurfaceForId(parent_id1);
- ASSERT_NE(nullptr, old_surface);
- EXPECT_TRUE(old_surface->HasActiveFrame());
- EXPECT_FALSE(old_surface->HasPendingFrame());
-
- // Submit another frame with some other latency info and a different
- // LocalSurfaceId.
- ui::LatencyInfo info2;
- info2.AddLatencyNumber(latency_type2, latency_id2, latency_sequence_number2);
-
- CompositorFrame frame2 = MakeCompositorFrame();
- frame2.metadata.latency_info.push_back(info2);
-
- parent_support().SubmitCompositorFrame(parent_id2.local_surface_id(),
- std::move(frame2));
-
- // Verify that the new surface has an active frame and no pending frames.
- Surface* surface = surface_manager().GetSurfaceForId(parent_id2);
- ASSERT_NE(nullptr, surface);
- EXPECT_TRUE(surface->HasActiveFrame());
- EXPECT_FALSE(surface->HasPendingFrame());
-
- // Verify that the new surface has both latency info elements.
- std::vector<ui::LatencyInfo> info_list;
- surface->TakeLatencyInfo(&info_list);
- EXPECT_EQ(2u, info_list.size());
-
- ui::LatencyInfo aggregated_latency_info = info_list[0];
- aggregated_latency_info.AddNewLatencyFrom(info_list[1]);
- EXPECT_EQ(2u, aggregated_latency_info.latency_components().size());
-
- ui::LatencyInfo::LatencyComponent comp1;
- EXPECT_TRUE(
- aggregated_latency_info.FindLatency(latency_type1, latency_id1, &comp1));
- EXPECT_EQ(latency_sequence_number1, comp1.sequence_number);
+ frame.resource_list.push_back(resource);
+ support->SubmitCompositorFrame(local_surface_id, std::move(frame));
+ EXPECT_EQ(last_created_surface_id().local_surface_id(), local_surface_id);
+ local_surface_id_ = LocalSurfaceId();
+
+ SurfaceId surface_id(kAnotherArbitraryFrameSinkId, local_surface_id);
+ Surface* surface = manager_.GetSurfaceForId(surface_id);
+ surface->AddDestructionDependency(
+ SurfaceSequence(kYetAnotherArbitraryFrameSinkId, 4));
+
+ ReturnedResourceArray returned_resource = {resource.ToReturnedResource()};
+
+ EXPECT_TRUE(manager_.GetSurfaceForId(surface_id));
+ EXPECT_CALL(mock_client, DidReceiveCompositorFrameAck(returned_resource))
+ .Times(1);
+ support->EvictCurrentSurface();
+ EXPECT_FALSE(manager_.GetSurfaceForId(surface_id));
}
-// Checks whether the latency info are moved to the new surface from the old
-// one when LocalSurfaceId changes. Old surface has unresolved dependencies.
+// Tests doing an EvictCurrentSurface which has registered dependency.
TEST_F(CompositorFrameSinkSupportTest,
- LatencyInfoCarriedOverOnResize_OldSurfaceHasPendingAndActiveFrame) {
- const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
- const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2);
- const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 1);
-
- const ui::LatencyComponentType latency_type1 =
- ui::BROWSER_SNAPSHOT_FRAME_NUMBER_COMPONENT;
- const int64_t latency_id1 = 234;
- const int64_t latency_sequence_number1 = 5645432;
- const ui::LatencyComponentType latency_type2 = ui::TAB_SHOW_COMPONENT;
- const int64_t latency_id2 = 31434351;
- const int64_t latency_sequence_number2 = 663788;
-
- // Submit a frame with no unresolved dependecy.
- ui::LatencyInfo info;
- info.AddLatencyNumber(latency_type1, latency_id1, latency_sequence_number1);
+ EvictCurrentSurfaceDependencyRegistered) {
+ MockCompositorFrameSinkSupportClient mock_client;
+ std::unique_ptr<CompositorFrameSinkSupport> support =
+ CompositorFrameSinkSupport::Create(
+ &mock_client, &manager_, kAnotherArbitraryFrameSinkId, kIsRoot,
+ kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ LocalSurfaceId local_surface_id(7, kArbitraryToken);
+ TransferableResource resource;
+ resource.id = 1;
+ resource.mailbox_holder.texture_target = GL_TEXTURE_2D;
CompositorFrame frame = MakeCompositorFrame();
- frame.metadata.latency_info.push_back(info);
+ frame.resource_list.push_back(resource);
+ uint32_t execute_count = 0;
+ support->SubmitCompositorFrame(local_surface_id, std::move(frame));
+ EXPECT_EQ(last_created_surface_id().local_surface_id(), local_surface_id);
+ local_surface_id_ = LocalSurfaceId();
- parent_support().SubmitCompositorFrame(parent_id1.local_surface_id(),
- std::move(frame));
+ manager_.RegisterFrameSinkId(kYetAnotherArbitraryFrameSinkId);
- // Submit a frame with unresolved dependencies.
- ui::LatencyInfo info2;
- info2.AddLatencyNumber(latency_type2, latency_id2, latency_sequence_number2);
+ SurfaceId surface_id(kAnotherArbitraryFrameSinkId, local_surface_id);
+ Surface* surface = manager_.GetSurfaceForId(surface_id);
+ surface->AddDestructionDependency(
+ SurfaceSequence(kYetAnotherArbitraryFrameSinkId, 4));
- CompositorFrame frame2 = MakeCompositorFrame({child_id});
- frame2.metadata.latency_info.push_back(info2);
+ ReturnedResourceArray returned_resources;
+ EXPECT_TRUE(manager_.GetSurfaceForId(surface_id));
+ support->EvictCurrentSurface();
+ EXPECT_TRUE(manager_.GetSurfaceForId(surface_id));
+ EXPECT_EQ(0u, execute_count);
+
+ returned_resources.push_back(resource.ToReturnedResource());
+ EXPECT_CALL(mock_client, DidReceiveCompositorFrameAck(returned_resources))
+ .Times(1);
+ manager_.SatisfySequence(SurfaceSequence(kYetAnotherArbitraryFrameSinkId, 4));
+ EXPECT_FALSE(manager_.GetSurfaceForId(surface_id));
+}
- parent_support().SubmitCompositorFrame(parent_id1.local_surface_id(),
- std::move(frame2));
+TEST_F(CompositorFrameSinkSupportTest, DestroySequence) {
+ LocalSurfaceId local_surface_id2(5, kArbitraryToken);
+ std::unique_ptr<CompositorFrameSinkSupport> support2 =
+ CompositorFrameSinkSupport::Create(
+ &fake_support_client_, &manager_, kYetAnotherArbitraryFrameSinkId,
+ kIsChildRoot, kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ SurfaceId id2(kYetAnotherArbitraryFrameSinkId, local_surface_id2);
+ support2->SubmitCompositorFrame(local_surface_id2, MakeCompositorFrame());
+
+ // Check that waiting before the sequence is satisfied works.
+ manager_.GetSurfaceForId(id2)->AddDestructionDependency(
+ SurfaceSequence(kYetAnotherArbitraryFrameSinkId, 4));
+ support2->EvictCurrentSurface();
+
+ DCHECK(manager_.GetSurfaceForId(id2));
+ manager_.SatisfySequence(SurfaceSequence(kYetAnotherArbitraryFrameSinkId, 4));
+ manager_.SatisfySequence(SurfaceSequence(kYetAnotherArbitraryFrameSinkId, 6));
+ DCHECK(!manager_.GetSurfaceForId(id2));
+
+ // Check that waiting after the sequence is satisfied works.
+ support2->SubmitCompositorFrame(local_surface_id2, MakeCompositorFrame());
+ DCHECK(manager_.GetSurfaceForId(id2));
+ manager_.GetSurfaceForId(id2)->AddDestructionDependency(
+ SurfaceSequence(kAnotherArbitraryFrameSinkId, 6));
+ support2->EvictCurrentSurface();
+ DCHECK(!manager_.GetSurfaceForId(id2));
+}
- // Verify that the old surface has both an active and a pending frame.
- Surface* old_surface = surface_manager().GetSurfaceForId(parent_id1);
- ASSERT_NE(nullptr, old_surface);
- EXPECT_TRUE(old_surface->HasActiveFrame());
- EXPECT_TRUE(old_surface->HasPendingFrame());
+// Tests that Surface ID namespace invalidation correctly allows
+// Sequences to be ignored.
+TEST_F(CompositorFrameSinkSupportTest, InvalidFrameSinkId) {
+ FrameSinkId frame_sink_id(1234, 5678);
- // Submit a frame with a new local surface id.
- parent_support().SubmitCompositorFrame(parent_id2.local_surface_id(),
- MakeCompositorFrame());
+ LocalSurfaceId local_surface_id(5, kArbitraryToken);
+ SurfaceId id(support_->frame_sink_id(), local_surface_id);
+ support_->SubmitCompositorFrame(local_surface_id, MakeCompositorFrame());
- // Verify that the new surface has an active frame only.
- Surface* surface = surface_manager().GetSurfaceForId(parent_id2);
- ASSERT_NE(nullptr, surface);
- EXPECT_TRUE(surface->HasActiveFrame());
- EXPECT_FALSE(surface->HasPendingFrame());
+ manager_.RegisterFrameSinkId(frame_sink_id);
+ manager_.GetSurfaceForId(id)->AddDestructionDependency(
+ SurfaceSequence(frame_sink_id, 4));
- // Verify that the new surface has latency info from both active and pending
- // frame of the old surface.
- std::vector<ui::LatencyInfo> info_list;
- surface->TakeLatencyInfo(&info_list);
- EXPECT_EQ(2u, info_list.size());
+ support_->EvictCurrentSurface();
- ui::LatencyInfo aggregated_latency_info = info_list[0];
- aggregated_latency_info.AddNewLatencyFrom(info_list[1]);
- EXPECT_EQ(2u, aggregated_latency_info.latency_components().size());
+ // Verify the dependency has prevented the surface from getting destroyed.
+ EXPECT_TRUE(manager_.GetSurfaceForId(id));
- ui::LatencyInfo::LatencyComponent comp1;
- EXPECT_TRUE(
- aggregated_latency_info.FindLatency(latency_type1, latency_id1, &comp1));
- EXPECT_EQ(latency_sequence_number1, comp1.sequence_number);
+ manager_.InvalidateFrameSinkId(frame_sink_id);
+
+ // Verify that the invalidated namespace caused the unsatisfied sequence
+ // to be ignored.
+ EXPECT_FALSE(manager_.GetSurfaceForId(id));
}
-// Checks whether the latency info are moved to the new surface from the old
-// one when LocalSurfaceId changes. The new surface has unresolved dependencies.
-TEST_F(CompositorFrameSinkSupportTest,
- LatencyInfoCarriedOverOnResize_NewSurfaceHasPendingFrame) {
- const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
- const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2);
- const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 1);
-
- const ui::LatencyComponentType latency_type1 =
- ui::BROWSER_SNAPSHOT_FRAME_NUMBER_COMPONENT;
- const int64_t latency_id1 = 234;
- const int64_t latency_sequence_number1 = 5645432;
- const ui::LatencyComponentType latency_type2 = ui::TAB_SHOW_COMPONENT;
- const int64_t latency_id2 = 31434351;
- const int64_t latency_sequence_number2 = 663788;
-
- // Submit a frame with no unresolved dependencies.
- ui::LatencyInfo info;
- info.AddLatencyNumber(latency_type1, latency_id1, latency_sequence_number1);
+TEST_F(CompositorFrameSinkSupportTest, DestroyCycle) {
+ LocalSurfaceId local_surface_id2(5, kArbitraryToken);
+ SurfaceId id2(kYetAnotherArbitraryFrameSinkId, local_surface_id2);
+ std::unique_ptr<CompositorFrameSinkSupport> support2 =
+ CompositorFrameSinkSupport::Create(
+ &fake_support_client_, &manager_, kYetAnotherArbitraryFrameSinkId,
+ kIsChildRoot, kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ manager_.RegisterFrameSinkId(kAnotherArbitraryFrameSinkId);
+ // Give id2 a frame that references local_surface_id_.
+ {
+ CompositorFrame frame = MakeCompositorFrame();
+ frame.metadata.referenced_surfaces.push_back(
+ SurfaceId(support_->frame_sink_id(), local_surface_id_));
+ support2->SubmitCompositorFrame(local_surface_id2, std::move(frame));
+ EXPECT_EQ(last_created_surface_id().local_surface_id(), local_surface_id2);
+ }
+ manager_.GetSurfaceForId(id2)->AddDestructionDependency(
+ SurfaceSequence(kAnotherArbitraryFrameSinkId, 4));
+ support2->EvictCurrentSurface();
+ // Give local_surface_id_ a frame that references id2.
+ {
+ CompositorFrame frame = MakeCompositorFrame();
+ frame.metadata.referenced_surfaces.push_back(id2);
+ support_->SubmitCompositorFrame(local_surface_id_, std::move(frame));
+ }
+ support_->EvictCurrentSurface();
+ EXPECT_TRUE(manager_.GetSurfaceForId(id2));
+ // local_surface_id_ should be retained by reference from id2.
+ EXPECT_TRUE(manager_.GetSurfaceForId(
+ SurfaceId(support_->frame_sink_id(), local_surface_id_)));
+
+ // Satisfy last destruction dependency for id2.
+ manager_.SatisfySequence(SurfaceSequence(kAnotherArbitraryFrameSinkId, 4));
+
+ // id2 and local_surface_id_ are in a reference cycle that has no surface
+ // sequences holding on to it, so they should be destroyed.
+ EXPECT_TRUE(!manager_.GetSurfaceForId(id2));
+ EXPECT_TRUE(!manager_.GetSurfaceForId(
+ SurfaceId(support_->frame_sink_id(), local_surface_id_)));
+
+ local_surface_id_ = LocalSurfaceId();
+}
- CompositorFrame frame = MakeCompositorFrame();
- frame.metadata.latency_info.push_back(info);
-
- parent_support().SubmitCompositorFrame(parent_id1.local_surface_id(),
- std::move(frame));
-
- // Verify that the old surface has an active frame only.
- Surface* old_surface = surface_manager().GetSurfaceForId(parent_id1);
- ASSERT_NE(nullptr, old_surface);
- EXPECT_TRUE(old_surface->HasActiveFrame());
- EXPECT_FALSE(old_surface->HasPendingFrame());
-
- // Submit a frame with a new local surface id and with unresolved
- // dependencies.
- ui::LatencyInfo info2;
- info2.AddLatencyNumber(latency_type2, latency_id2, latency_sequence_number2);
-
- CompositorFrame frame2 = MakeCompositorFrame({child_id});
- frame2.metadata.latency_info.push_back(info2);
-
- parent_support().SubmitCompositorFrame(parent_id2.local_surface_id(),
- std::move(frame2));
-
- // Verify that the new surface has a pending frame and no active frame.
- Surface* surface = surface_manager().GetSurfaceForId(parent_id2);
- ASSERT_NE(nullptr, surface);
- EXPECT_TRUE(surface->HasPendingFrame());
- EXPECT_FALSE(surface->HasActiveFrame());
-
- // Resolve the dependencies. The frame in parent's surface must become active.
- child_support1().SubmitCompositorFrame(child_id.local_surface_id(),
- MakeCompositorFrame());
- EXPECT_FALSE(surface->HasPendingFrame());
- EXPECT_TRUE(surface->HasActiveFrame());
-
- // Both latency info elements must exist in the now-activated frame of the
- // new surface.
- std::vector<ui::LatencyInfo> info_list;
- surface->TakeLatencyInfo(&info_list);
- EXPECT_EQ(2u, info_list.size());
-
- ui::LatencyInfo aggregated_latency_info = info_list[0];
- aggregated_latency_info.AddNewLatencyFrom(info_list[1]);
- EXPECT_EQ(2u, aggregated_latency_info.latency_components().size());
-
- ui::LatencyInfo::LatencyComponent comp1;
- EXPECT_TRUE(
- aggregated_latency_info.FindLatency(latency_type1, latency_id1, &comp1));
- EXPECT_EQ(latency_sequence_number1, comp1.sequence_number);
+void CopyRequestTestCallback(bool* called,
+ std::unique_ptr<CopyOutputResult> result) {
+ *called = true;
}
-TEST_F(CompositorFrameSinkSupportTest, PassesOnBeginFrameAcks) {
- const SurfaceId display_id = MakeSurfaceId(kDisplayFrameSink, 1);
+TEST_F(CompositorFrameSinkSupportTest, DuplicateCopyRequest) {
+ {
+ CompositorFrame frame = MakeCompositorFrame();
+ frame.metadata.referenced_surfaces.push_back(
+ SurfaceId(support_->frame_sink_id(), local_surface_id_));
+ support_->SubmitCompositorFrame(local_surface_id_, std::move(frame));
+ EXPECT_EQ(last_created_surface_id().local_surface_id(), local_surface_id_);
+ }
- // Request BeginFrames.
- display_support().SetNeedsBeginFrame(true);
+ bool called1 = false;
+ std::unique_ptr<CopyOutputRequest> request;
+ request = CopyOutputRequest::CreateRequest(
+ base::Bind(&CopyRequestTestCallback, &called1));
+ request->set_source(kArbitrarySourceId1);
+
+ support_->RequestCopyOfSurface(std::move(request));
+ EXPECT_FALSE(called1);
+
+ bool called2 = false;
+ request = CopyOutputRequest::CreateRequest(
+ base::Bind(&CopyRequestTestCallback, &called2));
+ request->set_source(kArbitrarySourceId2);
+
+ support_->RequestCopyOfSurface(std::move(request));
+ // Callbacks have different sources so neither should be called.
+ EXPECT_FALSE(called1);
+ EXPECT_FALSE(called2);
+
+ bool called3 = false;
+ request = CopyOutputRequest::CreateRequest(
+ base::Bind(&CopyRequestTestCallback, &called3));
+ request->set_source(kArbitrarySourceId1);
+
+ support_->RequestCopyOfSurface(std::move(request));
+ // Two callbacks are from source1, so the first should be called.
+ EXPECT_TRUE(called1);
+ EXPECT_FALSE(called2);
+ EXPECT_FALSE(called3);
+
+ support_->EvictCurrentSurface();
+ local_surface_id_ = LocalSurfaceId();
+ EXPECT_TRUE(called1);
+ EXPECT_TRUE(called2);
+ EXPECT_TRUE(called3);
+}
- // Issue a BeginFrame.
- BeginFrameArgs args =
- CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1);
- begin_frame_source()->TestOnBeginFrame(args);
+// Check whether the SurfaceInfo object is created and populated correctly
+// after the frame submission.
+TEST_F(CompositorFrameSinkSupportTest, SurfaceInfo) {
+ CompositorFrame frame = MakeCompositorFrame();
- // Check that the support forwards a BeginFrameDidNotSwap ack to the
- // BeginFrameSource.
- BeginFrameAck ack(0, 1, 1, false);
- display_support().BeginFrameDidNotSwap(ack);
- EXPECT_EQ(ack, begin_frame_source()->LastAckForObserver(&display_support()));
+ auto render_pass = RenderPass::Create();
+ render_pass->SetNew(1, gfx::Rect(5, 6), gfx::Rect(), gfx::Transform());
+ frame.render_pass_list.push_back(std::move(render_pass));
- // Issue another BeginFrame.
- args = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 2);
- begin_frame_source()->TestOnBeginFrame(args);
+ render_pass = RenderPass::Create();
+ render_pass->SetNew(2, gfx::Rect(7, 8), gfx::Rect(), gfx::Transform());
+ frame.render_pass_list.push_back(std::move(render_pass));
- // Check that the support forwards the BeginFrameAck attached
- // to a CompositorFrame to the BeginFrameSource.
- BeginFrameAck ack2(0, 2, 2, true);
- CompositorFrame frame = MakeCompositorFrame();
- frame.metadata.begin_frame_ack = ack2;
- display_support().SubmitCompositorFrame(display_id.local_surface_id(),
- std::move(frame));
- EXPECT_EQ(ack2, begin_frame_source()->LastAckForObserver(&display_support()));
-}
+ frame.metadata.device_scale_factor = 2.5f;
-// Checks that resources and ack are sent together if possible.
-TEST_F(CompositorFrameSinkSupportTest, ReturnResourcesWithAck) {
- const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
- TransferableResource resource;
- resource.id = 1234;
- parent_support().SubmitCompositorFrame(
- parent_id.local_surface_id(),
- MakeCompositorFrameWithResources(empty_surface_ids(), {resource}));
- ReturnedResourceArray returned_resources;
- TransferableResource::ReturnResources({resource}, &returned_resources);
- EXPECT_CALL(support_client_, ReclaimResources(_)).Times(0);
- EXPECT_CALL(support_client_,
- DidReceiveCompositorFrameAck(Eq(returned_resources)));
- parent_support().SubmitCompositorFrame(parent_id.local_surface_id(),
- MakeCompositorFrame());
+ support_->SubmitCompositorFrame(local_surface_id_, std::move(frame));
+ SurfaceId expected_surface_id(support_->frame_sink_id(), local_surface_id_);
+ EXPECT_EQ(expected_surface_id, last_surface_info_.id());
+ EXPECT_EQ(2.5f, last_surface_info_.device_scale_factor());
+ EXPECT_EQ(gfx::Size(7, 8), last_surface_info_.size_in_pixels());
}
-// Verifies that if a surface is marked destroyed and a new frame arrives for
-// it, it will be recovered.
-TEST_F(CompositorFrameSinkSupportTest, SurfaceResurrection) {
- const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
- const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 3);
-
- // Add a reference from the parent to the child.
- parent_support().SubmitCompositorFrame(parent_id.local_surface_id(),
- MakeCompositorFrame({child_id}));
-
- // Create the child surface by submitting a frame to it.
- EXPECT_EQ(nullptr, surface_manager().GetSurfaceForId(child_id));
- child_support1().SubmitCompositorFrame(child_id.local_surface_id(),
- MakeCompositorFrame());
-
- // Verify that the child surface is created.
- Surface* surface = surface_manager().GetSurfaceForId(child_id);
- EXPECT_NE(nullptr, surface);
-
- // Attempt to destroy the child surface. The surface must still exist since
- // the parent needs it but it will be marked as destroyed.
- child_support1().EvictFrame();
- surface = surface_manager().GetSurfaceForId(child_id);
- EXPECT_NE(nullptr, surface);
- EXPECT_TRUE(surface->destroyed());
-
- // Child submits another frame to the same local surface id that is marked
- // destroyed.
- child_support1().SubmitCompositorFrame(child_id.local_surface_id(),
- MakeCompositorFrame());
-
- // Verify that the surface that was marked destroyed is recovered and is being
- // used again.
- Surface* surface2 = surface_manager().GetSurfaceForId(child_id);
- EXPECT_EQ(surface, surface2);
- EXPECT_FALSE(surface2->destroyed());
+// Check that if a CompositorFrame is received with size zero, we don't create
+// a Surface for it.
+TEST_F(CompositorFrameSinkSupportTest, ZeroFrameSize) {
+ SurfaceId id(support_->frame_sink_id(), local_surface_id_);
+ CompositorFrame frame = MakeEmptyCompositorFrame();
+ frame.render_pass_list.push_back(RenderPass::Create());
+ EXPECT_TRUE(
+ support_->SubmitCompositorFrame(local_surface_id_, std::move(frame)));
+ EXPECT_FALSE(manager_.GetSurfaceForId(id));
}
-// Verifies that if a LocalSurfaceId belonged to a surface that doesn't exist
-// anymore, it can still be reused for new surfaces.
-TEST_F(CompositorFrameSinkSupportTest, LocalSurfaceIdIsReusable) {
- const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
- const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 3);
-
- // Add a reference from parent.
- parent_support().SubmitCompositorFrame(parent_id.local_surface_id(),
- MakeCompositorFrame({child_id}));
-
- // Submit the first frame. Creates the surface.
- child_support1().SubmitCompositorFrame(child_id.local_surface_id(),
- MakeCompositorFrame());
- EXPECT_NE(nullptr, surface_manager().GetSurfaceForId(child_id));
-
- // Remove the reference from parant. This allows us to destroy the surface.
- parent_support().SubmitCompositorFrame(parent_id.local_surface_id(),
- MakeCompositorFrame());
-
- // Destroy the surface.
- child_support1().EvictFrame();
- EXPECT_EQ(nullptr, surface_manager().GetSurfaceForId(child_id));
-
- // Submit another frame with the same local surface id. This should work fine
- // and a new surface must be created.
- child_support1().SubmitCompositorFrame(child_id.local_surface_id(),
- MakeCompositorFrame());
- EXPECT_NE(nullptr, surface_manager().GetSurfaceForId(child_id));
+// Check that if a CompositorFrame is received with device scale factor of 0, we
+// don't create a Surface for it.
+TEST_F(CompositorFrameSinkSupportTest, ZeroDeviceScaleFactor) {
+ SurfaceId id(support_->frame_sink_id(), local_surface_id_);
+ CompositorFrame frame = MakeCompositorFrame();
+ frame.metadata.device_scale_factor = 0.f;
+ EXPECT_TRUE(
+ support_->SubmitCompositorFrame(local_surface_id_, std::move(frame)));
+ EXPECT_FALSE(manager_.GetSurfaceForId(id));
}
-// This test verifies that a crash does not occur if garbage collection is
-// triggered during surface dependency resolution. This test triggers garbage
-// collection during surface resolution, by causing an activation to remove
-// a surface subtree from the root. Both the old subtree and the new
-// activated subtree refer to the same dependency. The old subtree was activated
-// by deadline, and the new subtree was activated by a dependency finally
-// resolving.
-TEST_F(CompositorFrameSinkSupportTest, DependencyTrackingGarbageCollection) {
- const SurfaceId display_id = MakeSurfaceId(kDisplayFrameSink, 1);
- const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
- const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2);
- const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 1);
-
- parent_support().SubmitCompositorFrame(parent_id1.local_surface_id(),
- MakeCompositorFrame({child_id}));
- display_support().SubmitCompositorFrame(display_id.local_surface_id(),
- MakeCompositorFrame({parent_id1}));
-
- EXPECT_TRUE(dependency_tracker().has_deadline());
-
- BeginFrameArgs args =
- CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1);
-
- // Advance BeginFrames to trigger a deadline.
- for (int i = 0; i < 3; ++i) {
- begin_frame_source()->TestOnBeginFrame(args);
- EXPECT_TRUE(dependency_tracker().has_deadline());
- }
- begin_frame_source()->TestOnBeginFrame(args);
- EXPECT_FALSE(dependency_tracker().has_deadline());
-
- EXPECT_TRUE(display_surface()->HasActiveFrame());
- EXPECT_FALSE(display_surface()->HasPendingFrame());
- EXPECT_TRUE(parent_surface()->HasActiveFrame());
- EXPECT_FALSE(parent_surface()->HasPendingFrame());
-
- parent_support().SubmitCompositorFrame(parent_id2.local_surface_id(),
- MakeCompositorFrame({child_id}));
- display_support().SubmitCompositorFrame(display_id.local_surface_id(),
- MakeCompositorFrame({parent_id2}));
-
- // The display surface now has two CompositorFrames. One that is pending,
- // indirectly blocked on child_id and one that is active, also indirectly
- // referring to child_id, but activated due to the deadline above.
- EXPECT_TRUE(display_surface()->HasActiveFrame());
- EXPECT_TRUE(display_surface()->HasPendingFrame());
-
- // Submitting a CompositorFrame will trigger garbage collection of the
- // |parent_id1| subtree. This should not crash.
- child_support1().SubmitCompositorFrame(
- child_id.local_surface_id(), MakeCompositorFrame(empty_surface_ids()));
-}
+// Check that if the size of a CompositorFrame doesn't match the size of the
+// Surface it's being submitted to, we skip the frame.
+TEST_F(CompositorFrameSinkSupportTest, FrameSizeMismatch) {
+ SurfaceId id(support_->frame_sink_id(), local_surface_id_);
-// This test verifies that a crash does not occur if garbage collection is
-// triggered when a deadline forces frame activation. This test triggers garbage
-// collection during deadline activation by causing the activation of a display
-// frame to replace a previously activated display frame that was referring to
-// a now-unreachable surface subtree. That subtree gets garbage collected during
-// deadline activation. SurfaceDependencyTracker is also tracking a surface
-// from that subtree due to an unresolved dependency. This test verifies that
-// this dependency resolution does not crash.
-TEST_F(CompositorFrameSinkSupportTest, GarbageCollectionOnDeadline) {
- const SurfaceId display_id = MakeSurfaceId(kDisplayFrameSink, 1);
- const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
- const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2);
- const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 1);
-
- display_support().SubmitCompositorFrame(display_id.local_surface_id(),
- MakeCompositorFrame({parent_id1}));
-
- EXPECT_TRUE(display_surface()->HasPendingFrame());
- EXPECT_TRUE(dependency_tracker().has_deadline());
- EXPECT_FALSE(display_surface()->HasActiveFrame());
-
- // Advance BeginFrames to trigger a deadline. This activates the
- // CompositorFrame submitted above.
- BeginFrameArgs args =
- CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1);
- for (int i = 0; i < 3; ++i) {
- begin_frame_source()->TestOnBeginFrame(args);
- EXPECT_TRUE(dependency_tracker().has_deadline());
- }
- begin_frame_source()->TestOnBeginFrame(args);
- EXPECT_FALSE(dependency_tracker().has_deadline());
- EXPECT_FALSE(display_surface()->HasPendingFrame());
- EXPECT_TRUE(display_surface()->HasActiveFrame());
-
- // |parent_id1| is blocked on |child_id|, but |display_id|'s CompositorFrame
- // has activated due to a deadline. |parent_id1| will be tracked by the
- // SurfaceDependencyTracker.
- parent_support().SubmitCompositorFrame(parent_id1.local_surface_id(),
- MakeCompositorFrame({child_id}));
-
- // By submitting a display CompositorFrame, and replacing the parent's
- // CompositorFrame with another surface ID, parent_id1 becomes unreachable and
- // a candidate for garbage collection.
- display_support().SubmitCompositorFrame(display_id.local_surface_id(),
- MakeCompositorFrame({parent_id2}));
-
- // Now |parent_id1| is only kept alive by the active |display_id| frame.
- parent_support().SubmitCompositorFrame(parent_id2.local_surface_id(),
- MakeCompositorFrame({child_id}));
-
- // SurfaceDependencyTracker should now be tracking |display_id|, |parent_id1|
- // and |parent_id2|. By activating the pending |display_id| frame by deadline,
- // |parent_id1| becomes unreachable and is garbage collected while
- // SurfaceDependencyTracker is in the process of activating surfaces. This
- // should not cause a crash or use-after-free.
- for (int i = 0; i < 3; ++i) {
- begin_frame_source()->TestOnBeginFrame(args);
- EXPECT_TRUE(dependency_tracker().has_deadline());
- }
- begin_frame_source()->TestOnBeginFrame(args);
- EXPECT_FALSE(dependency_tracker().has_deadline());
+ // Submit a frame with size (5,5).
+ CompositorFrame frame = MakeEmptyCompositorFrame();
+ auto pass = RenderPass::Create();
+ pass->SetNew(1, gfx::Rect(5, 5), gfx::Rect(), gfx::Transform());
+ frame.render_pass_list.push_back(std::move(pass));
+ EXPECT_TRUE(
+ support_->SubmitCompositorFrame(local_surface_id_, std::move(frame)));
+ EXPECT_TRUE(manager_.GetSurfaceForId(id));
+
+ // Submit a frame with size (5,4). This frame should be rejected and the
+ // surface should be destroyed.
+ frame = MakeEmptyCompositorFrame();
+ pass = RenderPass::Create();
+ pass->SetNew(1, gfx::Rect(5, 4), gfx::Rect(), gfx::Transform());
+ frame.render_pass_list.push_back(std::move(pass));
+ EXPECT_FALSE(
+ support_->SubmitCompositorFrame(local_surface_id_, std::move(frame)));
+ EXPECT_FALSE(manager_.GetSurfaceForId(id));
}
-// This test verifies that a CompositorFrame will only blocked on embedded
-// surfaces but not on other retained surface IDs in the CompositorFrame.
-TEST_F(CompositorFrameSinkSupportTest, OnlyBlockOnEmbeddedSurfaces) {
- const SurfaceId display_id = MakeSurfaceId(kDisplayFrameSink, 1);
- const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
- const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2);
-
- display_support().SubmitCompositorFrame(
- display_id.local_surface_id(),
- MakeCompositorFrame({parent_id1}, {parent_id1, parent_id2}));
-
- EXPECT_TRUE(display_surface()->HasPendingFrame());
- EXPECT_FALSE(display_surface()->HasActiveFrame());
- EXPECT_TRUE(dependency_tracker().has_deadline());
-
- // Verify that the display CompositorFrame will only block on |parent_id1| but
- // not |parent_id2|.
- EXPECT_THAT(display_surface()->blocking_surfaces(),
- UnorderedElementsAre(parent_id1));
- // Verify that the display surface holds no references while its
- // CompositorFrame is pending.
- EXPECT_THAT(GetChildReferences(display_id), IsEmpty());
-
- // Submitting a CompositorFrame with |parent_id1| should unblock the display
- // CompositorFrame.
- parent_support().SubmitCompositorFrame(parent_id1.local_surface_id(),
- MakeCompositorFrame());
-
- EXPECT_FALSE(dependency_tracker().has_deadline());
- EXPECT_FALSE(display_surface()->HasPendingFrame());
- EXPECT_TRUE(display_surface()->HasActiveFrame());
- EXPECT_THAT(display_surface()->blocking_surfaces(), IsEmpty());
-
- // Only a reference to |parent_id1| is added because |parent_id2| does not
- // exist.
- EXPECT_THAT(GetChildReferences(display_id), UnorderedElementsAre(parent_id1));
-}
+// Check that if the device scale factor of a CompositorFrame doesn't match the
+// device scale factor of the Surface it's being submitted to, the frame is
+// rejected and the surface is destroyed.
+TEST_F(CompositorFrameSinkSupportTest, DeviceScaleFactorMismatch) {
+ SurfaceId id(support_->frame_sink_id(), local_surface_id_);
-// This test verifies that a late arriving CompositorFrame activates immediately
-// and does not trigger a new deadline.
-TEST_F(CompositorFrameSinkSupportTest, LateArrivingDependency) {
- const SurfaceId display_id = MakeSurfaceId(kDisplayFrameSink, 1);
- const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
- const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
-
- display_support().SubmitCompositorFrame(display_id.local_surface_id(),
- MakeCompositorFrame({parent_id1}));
-
- EXPECT_TRUE(display_surface()->HasPendingFrame());
- EXPECT_FALSE(display_surface()->HasActiveFrame());
- EXPECT_TRUE(dependency_tracker().has_deadline());
-
- // Advance BeginFrames to trigger a deadline. This activates the
- // CompositorFrame submitted above.
- BeginFrameArgs args =
- CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1);
- for (int i = 0; i < 3; ++i) {
- begin_frame_source()->TestOnBeginFrame(args);
- EXPECT_TRUE(dependency_tracker().has_deadline());
- }
- begin_frame_source()->TestOnBeginFrame(args);
- EXPECT_FALSE(dependency_tracker().has_deadline());
- EXPECT_FALSE(display_surface()->HasPendingFrame());
- EXPECT_TRUE(display_surface()->HasActiveFrame());
-
- // A late arriving CompositorFrame should activate immediately without
- // scheduling a deadline and without waiting for dependencies to resolve.
- parent_support().SubmitCompositorFrame(parent_id1.local_surface_id(),
- MakeCompositorFrame({child_id1}));
- EXPECT_FALSE(dependency_tracker().has_deadline());
- EXPECT_FALSE(parent_surface()->HasPendingFrame());
- EXPECT_TRUE(parent_surface()->HasActiveFrame());
+ // Submit a frame with device scale factor of 0.5.
+ CompositorFrame frame = MakeCompositorFrame();
+ frame.metadata.device_scale_factor = 0.5f;
+ EXPECT_TRUE(
+ support_->SubmitCompositorFrame(local_surface_id_, std::move(frame)));
+ EXPECT_TRUE(manager_.GetSurfaceForId(id));
+
+ // Submit a frame with device scale factor of 0.4. This frame should be
+ // rejected and the surface should be destroyed.
+ frame = MakeCompositorFrame();
+ frame.metadata.device_scale_factor = 0.4f;
+ EXPECT_FALSE(
+ support_->SubmitCompositorFrame(local_surface_id_, std::move(frame)));
+ EXPECT_FALSE(manager_.GetSurfaceForId(id));
}
+} // namespace
+
} // namespace test
+
} // namespace cc
diff --git a/chromium/cc/surfaces/direct_compositor_frame_sink.cc b/chromium/cc/surfaces/direct_compositor_frame_sink.cc
index 13b6c6299b0..da704c512f9 100644
--- a/chromium/cc/surfaces/direct_compositor_frame_sink.cc
+++ b/chromium/cc/surfaces/direct_compositor_frame_sink.cc
@@ -31,7 +31,7 @@ DirectCompositorFrameSink::DirectCompositorFrameSink(
surface_manager_(surface_manager),
display_(display) {
DCHECK(thread_checker_.CalledOnValidThread());
- capabilities_.can_force_reclaim_resources = true;
+ capabilities_.must_always_swap = true;
// Display and DirectCompositorFrameSink share a GL context, so sync
// points aren't needed when passing resources between them.
capabilities_.delegated_sync_points_required = false;
@@ -47,7 +47,7 @@ DirectCompositorFrameSink::DirectCompositorFrameSink(
surface_manager_(surface_manager),
display_(display) {
DCHECK(thread_checker_.CalledOnValidThread());
- capabilities_.can_force_reclaim_resources = true;
+ capabilities_.must_always_swap = true;
}
DirectCompositorFrameSink::~DirectCompositorFrameSink() {
@@ -99,19 +99,23 @@ void DirectCompositorFrameSink::SubmitCompositorFrame(CompositorFrame frame) {
frame.metadata.begin_frame_ack.sequence_number);
gfx::Size frame_size = frame.render_pass_list.back()->output_rect.size();
- if (frame_size.IsEmpty() || frame_size != last_swap_frame_size_) {
- delegated_local_surface_id_ = local_surface_id_allocator_.GenerateId();
+ if (!local_surface_id_.is_valid() || frame_size != last_swap_frame_size_ ||
+ frame.metadata.device_scale_factor != device_scale_factor_) {
+ local_surface_id_ = local_surface_id_allocator_.GenerateId();
last_swap_frame_size_ = frame_size;
+ device_scale_factor_ = frame.metadata.device_scale_factor;
+ display_->SetLocalSurfaceId(local_surface_id_, device_scale_factor_);
}
- display_->SetLocalSurfaceId(delegated_local_surface_id_,
- frame.metadata.device_scale_factor);
- support_->SubmitCompositorFrame(delegated_local_surface_id_,
- std::move(frame));
+ bool result =
+ support_->SubmitCompositorFrame(local_surface_id_, std::move(frame));
+ DCHECK(result);
}
-void DirectCompositorFrameSink::ForceReclaimResources() {
- support_->ForceReclaimResources();
+void DirectCompositorFrameSink::DidNotProduceFrame(const BeginFrameAck& ack) {
+ DCHECK(!ack.has_damage);
+ DCHECK_LE(BeginFrameArgs::kStartingFrameNumber, ack.sequence_number);
+ support_->DidNotProduceFrame(ack);
}
void DirectCompositorFrameSink::DisplayOutputSurfaceLost() {
@@ -156,10 +160,4 @@ void DirectCompositorFrameSink::OnNeedsBeginFrames(bool needs_begin_frame) {
support_->SetNeedsBeginFrame(needs_begin_frame);
}
-void DirectCompositorFrameSink::OnDidFinishFrame(const BeginFrameAck& ack) {
- // If there was damage, SubmitCompositorFrame includes the ack.
- if (!ack.has_damage)
- support_->BeginFrameDidNotSwap(ack);
-}
-
} // namespace cc
diff --git a/chromium/cc/surfaces/direct_compositor_frame_sink.h b/chromium/cc/surfaces/direct_compositor_frame_sink.h
index 5aa021b448d..24480cb27ef 100644
--- a/chromium/cc/surfaces/direct_compositor_frame_sink.h
+++ b/chromium/cc/surfaces/direct_compositor_frame_sink.h
@@ -13,8 +13,6 @@
#include "cc/surfaces/compositor_frame_sink_support_client.h"
#include "cc/surfaces/display_client.h"
#include "cc/surfaces/local_surface_id_allocator.h"
-#include "cc/surfaces/surface_factory.h"
-#include "cc/surfaces/surface_factory_client.h"
#include "cc/surfaces/surfaces_export.h"
namespace cc {
@@ -51,7 +49,7 @@ class CC_SURFACES_EXPORT DirectCompositorFrameSink
bool BindToClient(CompositorFrameSinkClient* client) override;
void DetachFromClient() override;
void SubmitCompositorFrame(CompositorFrame frame) override;
- void ForceReclaimResources() override;
+ void DidNotProduceFrame(const BeginFrameAck& ack) override;
// DisplayClient implementation.
void DisplayOutputSurfaceLost() override;
@@ -73,17 +71,17 @@ class CC_SURFACES_EXPORT DirectCompositorFrameSink
// ExternalBeginFrameSourceClient implementation:
void OnNeedsBeginFrames(bool needs_begin_frame) override;
- void OnDidFinishFrame(const BeginFrameAck& ack) override;
// This class is only meant to be used on a single thread.
base::ThreadChecker thread_checker_;
const FrameSinkId frame_sink_id_;
- LocalSurfaceId delegated_local_surface_id_;
+ LocalSurfaceId local_surface_id_;
SurfaceManager* surface_manager_;
LocalSurfaceIdAllocator local_surface_id_allocator_;
Display* display_;
gfx::Size last_swap_frame_size_;
+ float device_scale_factor_ = 1.f;
bool is_lost_ = false;
std::unique_ptr<ExternalBeginFrameSource> begin_frame_source_;
diff --git a/chromium/cc/surfaces/direct_compositor_frame_sink_unittest.cc b/chromium/cc/surfaces/direct_compositor_frame_sink_unittest.cc
index 5f1b8b885a0..9fefc2967b6 100644
--- a/chromium/cc/surfaces/direct_compositor_frame_sink_unittest.cc
+++ b/chromium/cc/surfaces/direct_compositor_frame_sink_unittest.cc
@@ -17,6 +17,7 @@
#include "cc/surfaces/local_surface_id_allocator.h"
#include "cc/surfaces/surface_manager.h"
#include "cc/test/begin_frame_args_test.h"
+#include "cc/test/compositor_frame_helpers.h"
#include "cc/test/fake_compositor_frame_sink_client.h"
#include "cc/test/fake_output_surface.h"
#include "cc/test/ordered_simple_task_runner.h"
@@ -108,7 +109,7 @@ class DirectCompositorFrameSinkTest : public testing::Test {
std::unique_ptr<RenderPass> render_pass(RenderPass::Create());
render_pass->SetNew(1, display_rect_, damage_rect, gfx::Transform());
- CompositorFrame frame;
+ CompositorFrame frame = test::MakeEmptyCompositorFrame();
frame.metadata.begin_frame_ack = BeginFrameAck(0, 1, 1, true);
frame.render_pass_list.push_back(std::move(render_pass));
@@ -171,19 +172,6 @@ TEST_F(DirectCompositorFrameSinkTest, SuspendedDoesNotTriggerSwapBuffers) {
EXPECT_EQ(2u, display_output_surface_->num_sent_frames());
}
-TEST_F(DirectCompositorFrameSinkTest,
- LockingResourcesDoesNotIndirectlyCauseDamage) {
- compositor_frame_sink_->ForceReclaimResources();
- EXPECT_EQ(1u, display_output_surface_->num_sent_frames());
- task_runner_->RunPendingTasks();
- EXPECT_EQ(1u, display_output_surface_->num_sent_frames());
-
- SwapBuffersWithDamage(gfx::Rect());
- EXPECT_EQ(1u, display_output_surface_->num_sent_frames());
- task_runner_->RunUntilIdle();
- EXPECT_EQ(1u, display_output_surface_->num_sent_frames());
-}
-
class TestBeginFrameObserver : public BeginFrameObserverBase {
public:
const BeginFrameAck& ack() const { return ack_; }
@@ -215,6 +203,7 @@ TEST_F(DirectCompositorFrameSinkTest, AcknowledgesBeginFramesWithoutDamage) {
observer.ack().sequence_number);
compositor_frame_sink_client_.begin_frame_source()->DidFinishFrame(
&observer, observer.ack());
+ compositor_frame_sink_->DidNotProduceFrame(observer.ack());
compositor_frame_sink_client_.begin_frame_source()->RemoveObserver(&observer);
// Verify that the frame sink acknowledged the last BeginFrame.
diff --git a/chromium/cc/surfaces/display.cc b/chromium/cc/surfaces/display.cc
index 2b982d4694b..846897b2180 100644
--- a/chromium/cc/surfaces/display.cc
+++ b/chromium/cc/surfaces/display.cc
@@ -71,7 +71,7 @@ Display::~Display() {
for (const auto& id_entry : aggregator_->previous_contained_surfaces()) {
Surface* surface = surface_manager_->GetSurfaceForId(id_entry.first);
if (surface)
- surface->RunDrawCallbacks();
+ surface->RunDrawCallback();
}
}
}
@@ -194,9 +194,9 @@ void Display::InitializeRenderer() {
if (output_surface_->context_provider()) {
DCHECK(texture_mailbox_deleter_);
- renderer_ = base::MakeUnique<GLRenderer>(
- &settings_, output_surface_.get(), resource_provider_.get(),
- texture_mailbox_deleter_.get(), settings_.highp_threshold_min);
+ renderer_ = base::MakeUnique<GLRenderer>(&settings_, output_surface_.get(),
+ resource_provider_.get(),
+ texture_mailbox_deleter_.get());
} else if (output_surface_->vulkan_context_provider()) {
#if defined(ENABLE_VULKAN)
DCHECK(texture_mailbox_deleter_);
@@ -269,7 +269,7 @@ bool Display::DrawAndSwap() {
for (const auto& id_entry : aggregator_->previous_contained_surfaces()) {
Surface* surface = surface_manager_->GetSurfaceForId(id_entry.first);
if (surface)
- surface->RunDrawCallbacks();
+ surface->RunDrawCallback();
}
frame.metadata.latency_info.insert(frame.metadata.latency_info.end(),
@@ -283,19 +283,17 @@ bool Display::DrawAndSwap() {
gfx::Size surface_size;
bool have_damage = false;
- if (!frame.render_pass_list.empty()) {
- RenderPass& last_render_pass = *frame.render_pass_list.back();
- if (last_render_pass.output_rect.size() != current_surface_size_ &&
- last_render_pass.damage_rect == last_render_pass.output_rect &&
- !current_surface_size_.IsEmpty()) {
- // Resize the output rect to the current surface size so that we won't
- // skip the draw and so that the GL swap won't stretch the output.
- last_render_pass.output_rect.set_size(current_surface_size_);
- last_render_pass.damage_rect = last_render_pass.output_rect;
- }
- surface_size = last_render_pass.output_rect.size();
- have_damage = !last_render_pass.damage_rect.size().IsEmpty();
+ RenderPass& last_render_pass = *frame.render_pass_list.back();
+ if (last_render_pass.output_rect.size() != current_surface_size_ &&
+ last_render_pass.damage_rect == last_render_pass.output_rect &&
+ !current_surface_size_.IsEmpty()) {
+ // Resize the output rect to the current surface size so that we won't
+ // skip the draw and so that the GL swap won't stretch the output.
+ last_render_pass.output_rect.set_size(current_surface_size_);
+ last_render_pass.damage_rect = last_render_pass.output_rect;
}
+ surface_size = last_render_pass.output_rect.size();
+ have_damage = !last_render_pass.damage_rect.size().IsEmpty();
bool size_matches = surface_size == current_surface_size_;
if (!size_matches)
@@ -414,6 +412,11 @@ void Display::OnSurfaceDamaged(const SurfaceId& surface_id, bool* changed) {
void Display::OnSurfaceCreated(const SurfaceInfo& surface_info) {}
+void Display::OnSurfaceDiscarded(const SurfaceId& surface_id) {
+ if (aggregator_)
+ aggregator_->ReleaseResources(surface_id);
+}
+
const SurfaceId& Display::CurrentSurfaceId() {
return current_surface_id_;
}
diff --git a/chromium/cc/surfaces/display.h b/chromium/cc/surfaces/display.h
index 7718ffe32ea..df0f717061c 100644
--- a/chromium/cc/surfaces/display.h
+++ b/chromium/cc/surfaces/display.h
@@ -88,6 +88,7 @@ class CC_SURFACES_EXPORT Display : public DisplaySchedulerClient,
// SurfaceObserver implementation.
void OnSurfaceDamaged(const SurfaceId& surface, bool* changed) override;
void OnSurfaceCreated(const SurfaceInfo& surface_info) override;
+ void OnSurfaceDiscarded(const SurfaceId& surface_id) override;
bool has_scheduler() const { return !!scheduler_; }
DirectRenderer* renderer_for_testing() const { return renderer_.get(); }
@@ -109,8 +110,8 @@ class CC_SURFACES_EXPORT Display : public DisplaySchedulerClient,
SurfaceId current_surface_id_;
gfx::Size current_surface_size_;
float device_scale_factor_ = 1.f;
- gfx::ColorSpace blending_color_space_;
- gfx::ColorSpace device_color_space_;
+ gfx::ColorSpace blending_color_space_ = gfx::ColorSpace::CreateSRGB();
+ gfx::ColorSpace device_color_space_ = gfx::ColorSpace::CreateSRGB();
bool visible_ = false;
bool swapped_since_resize_ = false;
bool output_is_secure_ = false;
diff --git a/chromium/cc/surfaces/display_unittest.cc b/chromium/cc/surfaces/display_unittest.cc
index 603d0682001..2966adddb06 100644
--- a/chromium/cc/surfaces/display_unittest.cc
+++ b/chromium/cc/surfaces/display_unittest.cc
@@ -21,6 +21,7 @@
#include "cc/surfaces/local_surface_id_allocator.h"
#include "cc/surfaces/surface.h"
#include "cc/surfaces/surface_manager.h"
+#include "cc/test/compositor_frame_helpers.h"
#include "cc/test/fake_output_surface.h"
#include "cc/test/scheduler_test_common.h"
#include "cc/test/test_shared_bitmap_manager.h"
@@ -91,7 +92,7 @@ class DisplayTest : public testing::Test {
true /* needs_sync_points */)),
task_runner_(new base::NullTaskRunner) {}
- ~DisplayTest() override { support_->EvictFrame(); }
+ ~DisplayTest() override { support_->EvictCurrentSurface(); }
void SetUpDisplay(const RendererSettings& settings,
std::unique_ptr<TestWebGraphicsContext3D> context) {
@@ -125,7 +126,7 @@ class DisplayTest : public testing::Test {
protected:
void SubmitCompositorFrame(RenderPassList* pass_list,
const LocalSurfaceId& local_surface_id) {
- CompositorFrame frame;
+ CompositorFrame frame = test::MakeCompositorFrame();
pass_list->swap(frame.render_pass_list);
support_->SubmitCompositorFrame(local_surface_id, std::move(frame));
@@ -206,7 +207,6 @@ TEST_F(DisplayTest, DisplayDamaged) {
EXPECT_EQ(gfx::Size(100, 100),
software_output_device_->viewport_pixel_size());
EXPECT_EQ(gfx::Rect(0, 0, 100, 100), software_output_device_->damage_rect());
-
{
// Only damaged portion should be swapped.
pass = RenderPass::Create();
@@ -260,6 +260,9 @@ TEST_F(DisplayTest, DisplayDamaged) {
pass->damage_rect = gfx::Rect(10, 10, 10, 10);
pass->id = 1;
+ local_surface_id = id_allocator_.GenerateId();
+ display_->SetLocalSurfaceId(local_surface_id, 1.f);
+
pass_list.push_back(std::move(pass));
scheduler_->ResetDamageForTest();
SubmitCompositorFrame(&pass_list, local_surface_id);
@@ -280,6 +283,9 @@ TEST_F(DisplayTest, DisplayDamaged) {
pass->damage_rect = gfx::Rect(10, 10, 0, 0);
pass->id = 1;
+ local_surface_id = id_allocator_.GenerateId();
+ display_->SetLocalSurfaceId(local_surface_id, 1.f);
+
pass_list.push_back(std::move(pass));
scheduler_->ResetDamageForTest();
SubmitCompositorFrame(&pass_list, local_surface_id);
@@ -330,7 +336,7 @@ TEST_F(DisplayTest, DisplayDamaged) {
pass_list.push_back(std::move(pass));
scheduler_->ResetDamageForTest();
- CompositorFrame frame;
+ CompositorFrame frame = test::MakeCompositorFrame();
pass_list.swap(frame.render_pass_list);
frame.metadata.latency_info.push_back(ui::LatencyInfo());
@@ -347,6 +353,8 @@ TEST_F(DisplayTest, DisplayDamaged) {
// Resize should cause a swap if no frame was swapped at the previous size.
{
+ local_surface_id = id_allocator_.GenerateId();
+ display_->SetLocalSurfaceId(local_surface_id, 1.f);
scheduler_->swapped = false;
display_->Resize(gfx::Size(200, 200));
EXPECT_FALSE(scheduler_->swapped);
@@ -360,7 +368,7 @@ TEST_F(DisplayTest, DisplayDamaged) {
pass_list.push_back(std::move(pass));
scheduler_->ResetDamageForTest();
- CompositorFrame frame;
+ CompositorFrame frame = test::MakeCompositorFrame();
pass_list.swap(frame.render_pass_list);
support_->SubmitCompositorFrame(local_surface_id, std::move(frame));
@@ -378,6 +386,8 @@ TEST_F(DisplayTest, DisplayDamaged) {
}
{
+ local_surface_id = id_allocator_.GenerateId();
+ display_->SetLocalSurfaceId(local_surface_id, 1.0f);
// Surface that's damaged completely should be resized and swapped.
pass = RenderPass::Create();
pass->output_rect = gfx::Rect(0, 0, 99, 99);
@@ -409,7 +419,8 @@ class MockedContext : public TestWebGraphicsContext3D {
};
TEST_F(DisplayTest, Finish) {
- LocalSurfaceId local_surface_id(id_allocator_.GenerateId());
+ LocalSurfaceId local_surface_id1(id_allocator_.GenerateId());
+ LocalSurfaceId local_surface_id2(id_allocator_.GenerateId());
RendererSettings settings;
settings.partial_swap_enabled = true;
@@ -424,7 +435,7 @@ TEST_F(DisplayTest, Finish) {
StubDisplayClient client;
display_->Initialize(&client, &manager_);
- display_->SetLocalSurfaceId(local_surface_id, 1.f);
+ display_->SetLocalSurfaceId(local_surface_id1, 1.f);
display_->Resize(gfx::Size(100, 100));
@@ -436,7 +447,7 @@ TEST_F(DisplayTest, Finish) {
pass->id = 1;
pass_list.push_back(std::move(pass));
- SubmitCompositorFrame(&pass_list, local_surface_id);
+ SubmitCompositorFrame(&pass_list, local_surface_id1);
}
display_->DrawAndSwap();
@@ -450,6 +461,7 @@ TEST_F(DisplayTest, Finish) {
// Another resize without a swap doesn't need to finish.
EXPECT_CALL(*context_ptr, shallowFinishCHROMIUM()).Times(0);
+ display_->SetLocalSurfaceId(local_surface_id2, 1.f);
display_->Resize(gfx::Size(200, 200));
testing::Mock::VerifyAndClearExpectations(context_ptr);
@@ -462,7 +474,7 @@ TEST_F(DisplayTest, Finish) {
pass->id = 1;
pass_list.push_back(std::move(pass));
- SubmitCompositorFrame(&pass_list, local_surface_id);
+ SubmitCompositorFrame(&pass_list, local_surface_id2);
}
display_->DrawAndSwap();
diff --git a/chromium/cc/surfaces/framesink_manager.cc b/chromium/cc/surfaces/frame_sink_manager.cc
index d8fad7e3bbe..22f1d172dfc 100644
--- a/chromium/cc/surfaces/framesink_manager.cc
+++ b/chromium/cc/surfaces/frame_sink_manager.cc
@@ -2,13 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "cc/surfaces/framesink_manager.h"
+#include "cc/surfaces/frame_sink_manager.h"
#include <stddef.h>
#include <stdint.h>
#include "base/logging.h"
-#include "cc/surfaces/surface_factory_client.h"
+#include "cc/surfaces/frame_sink_manager_client.h"
+#include "cc/surfaces/primary_begin_frame_source.h"
#if DCHECK_IS_ON()
#include <sstream>
@@ -16,20 +17,18 @@
namespace cc {
-FrameSinkManager::FrameSinkSourceMapping::FrameSinkSourceMapping()
- : source(nullptr) {}
+FrameSinkManager::FrameSinkSourceMapping::FrameSinkSourceMapping() = default;
FrameSinkManager::FrameSinkSourceMapping::FrameSinkSourceMapping(
const FrameSinkSourceMapping& other) = default;
-FrameSinkManager::FrameSinkSourceMapping::~FrameSinkSourceMapping() {
-}
+FrameSinkManager::FrameSinkSourceMapping::~FrameSinkSourceMapping() = default;
-FrameSinkManager::FrameSinkManager() {}
+FrameSinkManager::FrameSinkManager() = default;
FrameSinkManager::~FrameSinkManager() {
- // All surface factory clients should be unregistered prior to SurfaceManager
- // destruction.
+ // All CompositorFrameSinks should be unregistered prior to
+ // SurfaceManager destruction.
DCHECK_EQ(clients_.size(), 0u);
DCHECK_EQ(registered_sources_.size(), 0u);
}
@@ -43,9 +42,9 @@ void FrameSinkManager::InvalidateFrameSinkId(const FrameSinkId& frame_sink_id) {
valid_frame_sink_ids_.erase(frame_sink_id);
}
-void FrameSinkManager::RegisterSurfaceFactoryClient(
+void FrameSinkManager::RegisterFrameSinkManagerClient(
const FrameSinkId& frame_sink_id,
- SurfaceFactoryClient* client) {
+ FrameSinkManagerClient* client) {
DCHECK(client);
DCHECK_EQ(valid_frame_sink_ids_.count(frame_sink_id), 1u);
@@ -58,7 +57,7 @@ void FrameSinkManager::RegisterSurfaceFactoryClient(
}
}
-void FrameSinkManager::UnregisterSurfaceFactoryClient(
+void FrameSinkManager::UnregisterFrameSinkManagerClient(
const FrameSinkId& frame_sink_id) {
DCHECK_EQ(valid_frame_sink_ids_.count(frame_sink_id), 1u);
auto client_iter = clients_.find(frame_sink_id);
@@ -83,6 +82,8 @@ void FrameSinkManager::RegisterBeginFrameSource(
registered_sources_[source] = frame_sink_id;
RecursivelyAttachBeginFrameSource(frame_sink_id, source);
+
+ primary_source_.OnBeginFrameSourceAdded(source);
}
void FrameSinkManager::UnregisterBeginFrameSource(BeginFrameSource* source) {
@@ -92,6 +93,8 @@ void FrameSinkManager::UnregisterBeginFrameSource(BeginFrameSource* source) {
FrameSinkId frame_sink_id = registered_sources_[source];
registered_sources_.erase(source);
+ primary_source_.OnBeginFrameSourceRemoved(source);
+
if (frame_sink_source_map_.count(frame_sink_id) == 0u)
return;
@@ -104,6 +107,10 @@ void FrameSinkManager::UnregisterBeginFrameSource(BeginFrameSource* source) {
RecursivelyAttachBeginFrameSource(source_iter.second, source_iter.first);
}
+BeginFrameSource* FrameSinkManager::GetPrimaryBeginFrameSource() {
+ return &primary_source_;
+}
+
void FrameSinkManager::RecursivelyAttachBeginFrameSource(
const FrameSinkId& frame_sink_id,
BeginFrameSource* source) {
@@ -207,7 +214,7 @@ void FrameSinkManager::UnregisterFrameSinkHierarchy(
}
DCHECK(found_child);
- // The SurfaceFactoryClient and hierarchy can be registered/unregistered
+ // The CompositorFrameSinkSupport and hierarchy can be registered/unregistered
// in either order, so empty frame_sink_source_map entries need to be
// checked when removing either clients or relationships.
if (!iter->second.has_children() && !clients_.count(parent_frame_sink_id) &&
diff --git a/chromium/cc/surfaces/framesink_manager.h b/chromium/cc/surfaces/frame_sink_manager.h
index 087126c1fb2..11c0f97668d 100644
--- a/chromium/cc/surfaces/framesink_manager.h
+++ b/chromium/cc/surfaces/frame_sink_manager.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_SURFACES_FRAMESINK_MANAGER_H_
-#define CC_SURFACES_FRAMESINK_MANAGER_H_
+#ifndef CC_SURFACES_FRAME_SINK_MANAGER_H_
+#define CC_SURFACES_FRAME_SINK_MANAGER_H_
#include <stdint.h>
@@ -14,14 +14,15 @@
#include "base/logging.h"
#include "base/macros.h"
#include "cc/surfaces/frame_sink_id.h"
+#include "cc/surfaces/primary_begin_frame_source.h"
#include "cc/surfaces/surfaces_export.h"
namespace cc {
class BeginFrameSource;
-class SurfaceFactoryClient;
+class FrameSinkManagerClient;
namespace test {
-class CompositorFrameSinkSupportTest;
+class SurfaceSynchronizationTest;
}
class CC_SURFACES_EXPORT FrameSinkManager {
@@ -35,20 +36,20 @@ class CC_SURFACES_EXPORT FrameSinkManager {
// possibly because a renderer process has crashed.
void InvalidateFrameSinkId(const FrameSinkId& frame_sink_id);
- // SurfaceFactoryClient, hierarchy, and BeginFrameSource can be registered
- // and unregistered in any order with respect to each other.
+ // CompositorFrameSinkSupport, hierarchy, and BeginFrameSource can be
+ // registered and unregistered in any order with respect to each other.
//
// This happens in practice, e.g. the relationship to between ui::Compositor /
// DelegatedFrameHost is known before ui::Compositor has a surface/client).
// However, DelegatedFrameHost can register itself as a client before its
// relationship with the ui::Compositor is known.
- // Associates a SurfaceFactoryClient with the frame_sink_id it uses.
- // SurfaceFactoryClient and framesink allocators have a 1:1 mapping.
+ // Associates a FrameSinkManagerClient with the frame_sink_id it uses.
+ // FrameSinkManagerClient and framesink allocators have a 1:1 mapping.
// Caller guarantees the client is alive between register/unregister.
- void RegisterSurfaceFactoryClient(const FrameSinkId& frame_sink_id,
- SurfaceFactoryClient* client);
- void UnregisterSurfaceFactoryClient(const FrameSinkId& frame_sink_id);
+ void RegisterFrameSinkManagerClient(const FrameSinkId& frame_sink_id,
+ FrameSinkManagerClient* client);
+ void UnregisterFrameSinkManagerClient(const FrameSinkId& frame_sink_id);
// Associates a |source| with a particular framesink. That framesink and
// any children of that framesink with valid clients can potentially use
@@ -57,6 +58,10 @@ class CC_SURFACES_EXPORT FrameSinkManager {
const FrameSinkId& frame_sink_id);
void UnregisterBeginFrameSource(BeginFrameSource* source);
+ // Returns a stable BeginFrameSource that forwards BeginFrames from the first
+ // available BeginFrameSource.
+ BeginFrameSource* GetPrimaryBeginFrameSource();
+
// Register a relationship between two framesinks. This relationship means
// that surfaces from the child framesik will be displayed in the parent.
// Children are allowed to use any begin frame source that their parent can
@@ -68,12 +73,12 @@ class CC_SURFACES_EXPORT FrameSinkManager {
// Export list of valid frame_sink_ids for SatisfyDestructionDeps in surface
// may be removed later when References replace Sequences
- std::unordered_set<FrameSinkId, FrameSinkIdHash>* GetValidFrameSinkIds(){
+ std::unordered_set<FrameSinkId, FrameSinkIdHash>* GetValidFrameSinkIds() {
return &valid_frame_sink_ids_;
}
private:
- friend class test::CompositorFrameSinkSupportTest;
+ friend class test::SurfaceSynchronizationTest;
void RecursivelyAttachBeginFrameSource(const FrameSinkId& frame_sink_id,
BeginFrameSource* source);
@@ -90,33 +95,36 @@ class CC_SURFACES_EXPORT FrameSinkManager {
// considered satisfied.
std::unordered_set<FrameSinkId, FrameSinkIdHash> valid_frame_sink_ids_;
- // Begin frame source routing. Both BeginFrameSource and SurfaceFactoryClient
- // pointers guaranteed alive by callers until unregistered.
+ // Begin frame source routing. Both BeginFrameSource and
+ // CompositorFrameSinkSupport pointers guaranteed alive by callers until
+ // unregistered.
struct FrameSinkSourceMapping {
FrameSinkSourceMapping();
FrameSinkSourceMapping(const FrameSinkSourceMapping& other);
~FrameSinkSourceMapping();
bool has_children() const { return !children.empty(); }
// The currently assigned begin frame source for this client.
- BeginFrameSource* source;
+ BeginFrameSource* source = nullptr;
// This represents a dag of parent -> children mapping.
std::vector<FrameSinkId> children;
};
- std::unordered_map<FrameSinkId, SurfaceFactoryClient*, FrameSinkIdHash>
+ std::unordered_map<FrameSinkId, FrameSinkManagerClient*, FrameSinkIdHash>
clients_;
std::unordered_map<FrameSinkId, FrameSinkSourceMapping, FrameSinkIdHash>
frame_sink_source_map_;
- // Set of which sources are registered to which frmesinks. Any child
+ // Set of BeginFrameSource along with associated FrameSinkIds. Any child
// that is implicitly using this framesink must be reachable by the
// parent in the dag.
std::unordered_map<BeginFrameSource*, FrameSinkId> registered_sources_;
+ PrimaryBeginFrameSource primary_source_;
+
DISALLOW_COPY_AND_ASSIGN(FrameSinkManager);
};
} // namespace cc
-#endif // CC_SURFACES_FRAMESINK_MANAGER_H_
+#endif // CC_SURFACES_FRAME_SINK_MANAGER_H_
diff --git a/chromium/cc/surfaces/frame_sink_manager_client.h b/chromium/cc/surfaces/frame_sink_manager_client.h
new file mode 100644
index 00000000000..83784b9b9ec
--- /dev/null
+++ b/chromium/cc/surfaces/frame_sink_manager_client.h
@@ -0,0 +1,22 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#ifndef CC_SURFACES_FRAME_SINK_MANAGER_CLIENT_H_
+#define CC_SURFACES_FRAME_SINK_MANAGER_CLIENT_H_
+
+#include "cc/scheduler/begin_frame_source.h"
+#include "cc/surfaces/surfaces_export.h"
+
+namespace cc {
+
+class CC_SURFACES_EXPORT FrameSinkManagerClient {
+ public:
+ virtual ~FrameSinkManagerClient() = default;
+
+ // This allows the FrameSinkManager to pass a BeginFrameSource to use.
+ virtual void SetBeginFrameSource(BeginFrameSource* begin_frame_source) = 0;
+};
+
+} // namespace cc
+
+#endif // CC_SURFACES_FRAME_SINK_MANAGER_CLIENT_H_
diff --git a/chromium/cc/surfaces/pending_frame_observer.h b/chromium/cc/surfaces/pending_frame_observer.h
deleted file mode 100644
index ec7acab2e2a..00000000000
--- a/chromium/cc/surfaces/pending_frame_observer.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_SURFACES_PENDING_FRAME_OBSERVER_H_
-#define CC_SURFACES_PENDING_FRAME_OBSERVER_H_
-
-#include "base/containers/flat_set.h"
-#include "cc/surfaces/surface_id.h"
-#include "cc/surfaces/surfaces_export.h"
-
-namespace cc {
-
-using SurfaceDependencies = base::flat_set<SurfaceId>;
-
-class Surface;
-
-// Clients that wish to observe when the state of a pending CompostiorFrame
-// changes should implement this class.
-class CC_SURFACES_EXPORT PendingFrameObserver {
- public:
- // Called when a CompositorFrame within |surface| has activated.
- virtual void OnSurfaceActivated(Surface* surface) = 0;
-
- // Called when the dependencies of a pending CompositorFrame within |surface|
- // have changed.
- virtual void OnSurfaceDependenciesChanged(
- Surface* surface,
- const SurfaceDependencies& added_dependencies,
- const SurfaceDependencies& removed_dependencies) = 0;
-
- // Called when |surface| is being destroyed.
- virtual void OnSurfaceDiscarded(Surface* surface) = 0;
-
- protected:
- virtual ~PendingFrameObserver() = default;
-};
-
-} // namespace cc
-
-#endif // CC_SURFACES_PENDING_FRAME_OBSERVER_H_
diff --git a/chromium/cc/surfaces/primary_begin_frame_source.cc b/chromium/cc/surfaces/primary_begin_frame_source.cc
new file mode 100644
index 00000000000..588dbfae67e
--- /dev/null
+++ b/chromium/cc/surfaces/primary_begin_frame_source.cc
@@ -0,0 +1,87 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/surfaces/primary_begin_frame_source.h"
+
+namespace cc {
+
+PrimaryBeginFrameSource::PrimaryBeginFrameSource()
+ : begin_frame_source_(this) {}
+
+PrimaryBeginFrameSource::~PrimaryBeginFrameSource() = default;
+
+void PrimaryBeginFrameSource::OnBeginFrameSourceAdded(
+ BeginFrameSource* begin_frame_source) {
+ sources_.insert(begin_frame_source);
+
+ if (current_begin_frame_source_)
+ return;
+
+ current_begin_frame_source_ = begin_frame_source;
+ if (needs_begin_frames_ && current_begin_frame_source_)
+ current_begin_frame_source_->AddObserver(this);
+}
+
+void PrimaryBeginFrameSource::OnBeginFrameSourceRemoved(
+ BeginFrameSource* begin_frame_source) {
+ sources_.erase(begin_frame_source);
+ if (current_begin_frame_source_ != begin_frame_source)
+ return;
+
+ if (needs_begin_frames_)
+ current_begin_frame_source_->RemoveObserver(this);
+
+ if (!sources_.empty())
+ current_begin_frame_source_ = *sources_.begin();
+ else
+ current_begin_frame_source_ = nullptr;
+
+ if (needs_begin_frames_ && current_begin_frame_source_)
+ current_begin_frame_source_->AddObserver(this);
+}
+
+void PrimaryBeginFrameSource::OnBeginFrame(const BeginFrameArgs& args) {
+ begin_frame_source_.OnBeginFrame(args);
+ last_begin_frame_args_ = args;
+}
+
+const BeginFrameArgs& PrimaryBeginFrameSource::LastUsedBeginFrameArgs() const {
+ return last_begin_frame_args_;
+}
+
+void PrimaryBeginFrameSource::OnBeginFrameSourcePausedChanged(bool paused) {}
+
+void PrimaryBeginFrameSource::DidFinishFrame(BeginFrameObserver* obs,
+ const BeginFrameAck& ack) {
+ begin_frame_source_.DidFinishFrame(obs, ack);
+}
+
+void PrimaryBeginFrameSource::AddObserver(BeginFrameObserver* obs) {
+ begin_frame_source_.AddObserver(obs);
+}
+
+void PrimaryBeginFrameSource::RemoveObserver(BeginFrameObserver* obs) {
+ begin_frame_source_.RemoveObserver(obs);
+}
+
+bool PrimaryBeginFrameSource::IsThrottled() const {
+ return begin_frame_source_.IsThrottled();
+}
+
+void PrimaryBeginFrameSource::OnNeedsBeginFrames(bool needs_begin_frames) {
+ if (needs_begin_frames_ == needs_begin_frames)
+ return;
+
+ needs_begin_frames_ = needs_begin_frames;
+
+ if (!current_begin_frame_source_)
+ return;
+
+ if (needs_begin_frames_)
+ current_begin_frame_source_->AddObserver(this);
+ else
+ current_begin_frame_source_->RemoveObserver(this);
+}
+
+} // namespace cc
diff --git a/chromium/cc/surfaces/primary_begin_frame_source.h b/chromium/cc/surfaces/primary_begin_frame_source.h
new file mode 100644
index 00000000000..e881a297271
--- /dev/null
+++ b/chromium/cc/surfaces/primary_begin_frame_source.h
@@ -0,0 +1,56 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_SURFACES_PRIMARY_BEGIN_FRAME_SOURCE_H_
+#define CC_SURFACES_PRIMARY_BEGIN_FRAME_SOURCE_H_
+
+#include "cc/scheduler/begin_frame_source.h"
+
+namespace cc {
+
+// PrimaryBeginFrameSource echos the first BeginFrameSource in the system.
+// If the first source goes away then it will echo the new first
+// BeginFrameSource.
+class PrimaryBeginFrameSource : public BeginFrameSource,
+ public BeginFrameObserver,
+ public ExternalBeginFrameSourceClient {
+ public:
+ PrimaryBeginFrameSource();
+ ~PrimaryBeginFrameSource() override;
+
+ void OnBeginFrameSourceAdded(BeginFrameSource* begin_frame_source);
+ void OnBeginFrameSourceRemoved(BeginFrameSource* begin_frame_source);
+
+ // BeginFrameObserver implementation.
+ void OnBeginFrame(const BeginFrameArgs& args) override;
+ const BeginFrameArgs& LastUsedBeginFrameArgs() const override;
+ void OnBeginFrameSourcePausedChanged(bool paused) override;
+
+ // BeginFrameSource implementation.
+ void DidFinishFrame(BeginFrameObserver* obs,
+ const BeginFrameAck& ack) override;
+ void AddObserver(BeginFrameObserver* obs) override;
+ void RemoveObserver(BeginFrameObserver* obs) override;
+ bool IsThrottled() const override;
+
+ // ExternalBeginFrameSourceClient implementation.
+ void OnNeedsBeginFrames(bool needs_begin_frames) override;
+
+ private:
+ ExternalBeginFrameSource begin_frame_source_;
+ BeginFrameSource* current_begin_frame_source_ = nullptr;
+
+ // The last begin frame args generated by the begin frame source.
+ BeginFrameArgs last_begin_frame_args_;
+
+ bool needs_begin_frames_ = false;
+
+ base::flat_set<BeginFrameSource*> sources_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrimaryBeginFrameSource);
+};
+
+} // namespace cc
+
+#endif // CC_SURFACES_PRIMARY_BEGIN_FRAME_SOURCE_H_
diff --git a/chromium/cc/surfaces/referenced_surface_tracker.cc b/chromium/cc/surfaces/referenced_surface_tracker.cc
index 5e440d88286..1922a77d937 100644
--- a/chromium/cc/surfaces/referenced_surface_tracker.cc
+++ b/chromium/cc/surfaces/referenced_surface_tracker.cc
@@ -36,49 +36,36 @@ void ReferencedSurfaceTracker::UpdateReferences(
referenced_surfaces_.clear();
}
- std::unordered_set<SurfaceId, SurfaceIdHash> referenced_surface_set;
+ base::flat_set<SurfaceId> new_referenced_surfaces;
if (active_referenced_surfaces) {
- referenced_surface_set.insert(active_referenced_surfaces->begin(),
- active_referenced_surfaces->end());
+ new_referenced_surfaces = base::flat_set<SurfaceId>(
+ active_referenced_surfaces->begin(), active_referenced_surfaces->end(),
+ base::KEEP_FIRST_OF_DUPES);
}
+ FindReferenceDiff(new_referenced_surfaces);
- ProcessNewReferences(referenced_surface_set);
+ if (!references_to_add_.empty() || !references_to_remove_.empty())
+ swap(referenced_surfaces_, new_referenced_surfaces);
}
-void ReferencedSurfaceTracker::ProcessNewReferences(
- const std::unordered_set<SurfaceId, SurfaceIdHash>&
- new_referenced_surfaces) {
- // Removed references for each SurfaceId in |referenced_surfaces_| if they
- // aren't referenced anymore. Removing from a set invalidates iterators, so
- // create a new vector then remove everything in it.
- std::vector<SurfaceId> not_referenced;
+void ReferencedSurfaceTracker::FindReferenceDiff(
+ const base::flat_set<SurfaceId>& new_referenced_surfaces) {
+ // Find SurfaceIds in |referenced_surfaces_| that aren't referenced anymore.
for (const SurfaceId& surface_id : referenced_surfaces_) {
- if (new_referenced_surfaces.count(surface_id) == 0)
- not_referenced.push_back(surface_id);
+ if (new_referenced_surfaces.count(surface_id) == 0) {
+ references_to_remove_.push_back(
+ SurfaceReference(current_surface_id_, surface_id));
+ }
}
- for (const SurfaceId& surface_id : not_referenced)
- RemoveSurfaceReference(surface_id);
- // Add references for each SurfaceId in |new_referenced_surfaces| if they
- // aren't already referenced.
+ // Find SurfaceIds in |new_referenced_surfaces| that aren't already
+ // referenced.
for (const SurfaceId& surface_id : new_referenced_surfaces) {
- if (referenced_surfaces_.count(surface_id) == 0)
- AddSurfaceReference(surface_id);
+ if (referenced_surfaces_.count(surface_id) == 0) {
+ references_to_add_.push_back(
+ SurfaceReference(current_surface_id_, surface_id));
+ }
}
}
-void ReferencedSurfaceTracker::AddSurfaceReference(
- const SurfaceId& surface_id) {
- references_to_add_.push_back(
- SurfaceReference(current_surface_id_, surface_id));
- referenced_surfaces_.insert(surface_id);
-}
-
-void ReferencedSurfaceTracker::RemoveSurfaceReference(
- const SurfaceId& surface_id) {
- references_to_remove_.push_back(
- SurfaceReference(current_surface_id_, surface_id));
- referenced_surfaces_.erase(surface_id);
-}
-
} // namespace cc
diff --git a/chromium/cc/surfaces/referenced_surface_tracker.h b/chromium/cc/surfaces/referenced_surface_tracker.h
index bfb3f3c7f99..ffe989845d3 100644
--- a/chromium/cc/surfaces/referenced_surface_tracker.h
+++ b/chromium/cc/surfaces/referenced_surface_tracker.h
@@ -5,9 +5,9 @@
#ifndef CC_SURFACES_REFERENCED_SURFACE_TRACKER_H_
#define CC_SURFACES_REFERENCED_SURFACE_TRACKER_H_
-#include <unordered_set>
#include <vector>
+#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "cc/surfaces/frame_sink_id.h"
#include "cc/surfaces/surface_id.h"
@@ -44,24 +44,18 @@ class CC_SURFACES_EXPORT ReferencedSurfaceTracker {
const std::vector<SurfaceId>* active_referenced_surfaces);
private:
- // Updates |referenced_surfaces_| based on a |new_referenced_surfaces| from a
- // CompositorFrame. Populates |references_to_add_| and |references_to_remove_|
- // based on the difference between the sets.
- void ProcessNewReferences(const std::unordered_set<SurfaceId, SurfaceIdHash>&
- new_referenced_surfaces);
-
- // Adds reference from |current_surface_id_| to |surface_id|.
- void AddSurfaceReference(const SurfaceId& surface_id);
-
- // Removes reference from |current_surface_id_| to |surface_id|.
- void RemoveSurfaceReference(const SurfaceId& surface_id);
+ // Finds the difference between original |referenced_surfaces_| and new
+ // |new_referenced_surfaces|. Populates |references_to_add_| and
+ // |references_to_remove_| based on the difference between the sets.
+ void FindReferenceDiff(
+ const base::flat_set<SurfaceId>& new_referenced_surfaces);
// The id of the client surface that is embedding other surfaces.
SurfaceId current_surface_id_;
- // TODO(samans): Use the same SurfaceId set that SurfaceManager holds.
+ // TODO(kylechar): Use the same SurfaceId set that SurfaceManager holds.
// Set of surfaces referenced by the last submitted CompositorFrame.
- std::unordered_set<SurfaceId, SurfaceIdHash> referenced_surfaces_;
+ base::flat_set<SurfaceId> referenced_surfaces_;
// References to surfaces that should be added for the next CompositorFrame.
std::vector<SurfaceReference> references_to_add_;
diff --git a/chromium/cc/surfaces/surface.cc b/chromium/cc/surfaces/surface.cc
index a161eee5a0c..9653f6005dc 100644
--- a/chromium/cc/surfaces/surface.cc
+++ b/chromium/cc/surfaces/surface.cc
@@ -12,10 +12,10 @@
#include "base/stl_util.h"
#include "cc/output/compositor_frame.h"
#include "cc/output/copy_output_request.h"
+#include "cc/surfaces/compositor_frame_sink_support.h"
#include "cc/surfaces/local_surface_id_allocator.h"
-#include "cc/surfaces/pending_frame_observer.h"
-#include "cc/surfaces/surface_factory.h"
#include "cc/surfaces/surface_manager.h"
+#include "cc/surfaces/surface_resource_holder_client.h"
namespace cc {
@@ -23,84 +23,123 @@ namespace cc {
// completely damaged the first time they're drawn from.
static const int kFrameIndexStart = 2;
-Surface::Surface(const SurfaceId& id, base::WeakPtr<SurfaceFactory> factory)
- : surface_id_(id),
- previous_frame_surface_id_(id),
- factory_(factory),
+Surface::Surface(
+ const SurfaceInfo& surface_info,
+ base::WeakPtr<CompositorFrameSinkSupport> compositor_frame_sink_support)
+ : surface_info_(surface_info),
+ previous_frame_surface_id_(surface_info.id()),
+ compositor_frame_sink_support_(std::move(compositor_frame_sink_support)),
+ surface_manager_(compositor_frame_sink_support_->surface_manager()),
frame_index_(kFrameIndexStart),
destroyed_(false) {}
Surface::~Surface() {
ClearCopyRequests();
- if (factory_) {
- if (pending_frame_)
- UnrefFrameResources(*pending_frame_);
- if (active_frame_)
- UnrefFrameResources(*active_frame_);
- }
- if (!draw_callback_.is_null())
- draw_callback_.Run();
+ surface_manager_->SurfaceDiscarded(this);
- for (auto& observer : observers_)
- observer.OnSurfaceDiscarded(this);
- observers_.Clear();
+ UnrefFrameResourcesAndRunDrawCallback(std::move(pending_frame_data_));
+ UnrefFrameResourcesAndRunDrawCallback(std::move(active_frame_data_));
}
void Surface::SetPreviousFrameSurface(Surface* surface) {
- DCHECK(surface);
+ DCHECK(surface && (HasActiveFrame() || HasPendingFrame()));
frame_index_ = surface->frame_index() + 1;
previous_frame_surface_id_ = surface->surface_id();
- CompositorFrame& frame = active_frame_ ? *active_frame_ : *pending_frame_;
+ CompositorFrame& frame = active_frame_data_ ? active_frame_data_->frame
+ : pending_frame_data_->frame;
surface->TakeLatencyInfo(&frame.metadata.latency_info);
surface->TakeLatencyInfoFromPendingFrame(&frame.metadata.latency_info);
}
-void Surface::QueueFrame(CompositorFrame frame, const DrawCallback& callback) {
+void Surface::Close() {
+ closed_ = true;
+}
+
+bool Surface::QueueFrame(CompositorFrame frame,
+ const base::Closure& callback,
+ const WillDrawCallback& will_draw_callback) {
+ gfx::Size frame_size = frame.render_pass_list.back()->output_rect.size();
+ float device_scale_factor = frame.metadata.device_scale_factor;
+
+ if (frame_size != surface_info_.size_in_pixels() ||
+ device_scale_factor != surface_info_.device_scale_factor()) {
+ TRACE_EVENT_INSTANT0("cc", "Surface invariants violation",
+ TRACE_EVENT_SCOPE_THREAD);
+ return false;
+ }
+
+ if (closed_) {
+ if (compositor_frame_sink_support_) {
+ ReturnedResourceArray resources;
+ TransferableResource::ReturnResources(frame.resource_list, &resources);
+ compositor_frame_sink_support_->ReturnResources(resources);
+ }
+ callback.Run();
+ return true;
+ }
+
TakeLatencyInfoFromPendingFrame(&frame.metadata.latency_info);
- base::Optional<CompositorFrame> previous_pending_frame =
- std::move(pending_frame_);
- pending_frame_.reset();
+ base::Optional<FrameData> previous_pending_frame_data =
+ std::move(pending_frame_data_);
+ pending_frame_data_.reset();
- UpdateBlockingSurfaces(previous_pending_frame, frame);
+ UpdateBlockingSurfaces(previous_pending_frame_data.has_value(), frame);
// Receive and track the resources referenced from the CompositorFrame
// regardless of whether it's pending or active.
- factory_->ReceiveFromChild(frame.resource_list);
-
- if (!blocking_surfaces_.empty()) {
- pending_frame_ = std::move(frame);
+ compositor_frame_sink_support_->ReceiveFromChild(frame.resource_list);
+
+ bool is_pending_frame = !blocking_surfaces_.empty();
+
+ if (is_pending_frame) {
+ // Reject CompositorFrames submitted to surfaces referenced from this
+ // CompositorFrame as fallbacks. This saves some CPU cycles to allow
+ // children to catch up to the parent.
+ base::flat_set<FrameSinkId> frame_sink_ids_for_dependencies;
+ for (const SurfaceId& surface_id : frame.metadata.activation_dependencies)
+ frame_sink_ids_for_dependencies.insert(surface_id.frame_sink_id());
+ for (const SurfaceId& surface_id : frame.metadata.referenced_surfaces) {
+ // A surface ID in |referenced_surfaces| that has a corresponding surface
+ // ID in |activation_dependencies| with the same frame sink ID is said to
+ // be a fallback surface that can be used in place of the primary surface
+ // if the deadline passes before the dependency becomes available.
+ bool is_fallback_surface =
+ frame_sink_ids_for_dependencies.count(surface_id.frame_sink_id()) > 0;
+ if (is_fallback_surface) {
+ Surface* surface = surface_manager_->GetSurfaceForId(surface_id);
+ // A misbehaving client may report a non-existent surface ID as a
+ // |referenced_surface|. In that case, |surface| would be nullptr, and
+ // there is nothing to do here.
+ if (surface)
+ surface->Close();
+ }
+ }
+ pending_frame_data_ =
+ FrameData(std::move(frame), callback, will_draw_callback);
// Ask the surface manager to inform |this| when its dependencies are
// resolved.
- factory_->manager()->RequestSurfaceResolution(this);
+ surface_manager_->RequestSurfaceResolution(this);
} else {
// If there are no blockers, then immediately activate the frame.
- ActivateFrame(std::move(frame));
+ ActivateFrame(FrameData(std::move(frame), callback, will_draw_callback));
}
// Returns resources for the previous pending frame.
- if (previous_pending_frame)
- UnrefFrameResources(*previous_pending_frame);
+ UnrefFrameResourcesAndRunDrawCallback(std::move(previous_pending_frame_data));
- if (!draw_callback_.is_null())
- draw_callback_.Run();
- draw_callback_ = callback;
-}
-
-void Surface::EvictFrame() {
- QueueFrame(CompositorFrame(), DrawCallback());
- active_frame_.reset();
+ return true;
}
void Surface::RequestCopyOfOutput(
std::unique_ptr<CopyOutputRequest> copy_request) {
- if (!active_frame_ || active_frame_->render_pass_list.empty()) {
+ if (!active_frame_data_) {
copy_request->SendEmptyResult();
return;
}
std::vector<std::unique_ptr<CopyOutputRequest>>& copy_requests =
- active_frame_->render_pass_list.back()->copy_requests;
+ active_frame_data_->frame.render_pass_list.back()->copy_requests;
if (copy_request->has_source()) {
const base::UnguessableToken& source = copy_request->source();
@@ -129,17 +168,9 @@ void Surface::NotifySurfaceIdAvailable(const SurfaceId& surface_id) {
ActivatePendingFrame();
}
-void Surface::AddObserver(PendingFrameObserver* observer) {
- observers_.AddObserver(observer);
-}
-
-void Surface::RemoveObserver(PendingFrameObserver* observer) {
- observers_.RemoveObserver(observer);
-}
-
void Surface::ActivatePendingFrameForDeadline() {
- if (!pending_frame_ ||
- !pending_frame_->metadata.can_activate_before_dependencies) {
+ if (!pending_frame_data_ ||
+ !pending_frame_data_->frame.metadata.can_activate_before_dependencies) {
return;
}
@@ -149,63 +180,73 @@ void Surface::ActivatePendingFrameForDeadline() {
ActivatePendingFrame();
}
+Surface::FrameData::FrameData(CompositorFrame&& frame,
+ const base::Closure& draw_callback,
+ const WillDrawCallback& will_draw_callback)
+ : frame(std::move(frame)),
+ draw_callback(draw_callback),
+ will_draw_callback(will_draw_callback) {}
+
+Surface::FrameData::FrameData(FrameData&& other) = default;
+
+Surface::FrameData& Surface::FrameData::operator=(FrameData&& other) = default;
+
+Surface::FrameData::~FrameData() = default;
+
void Surface::ActivatePendingFrame() {
- DCHECK(pending_frame_);
- ActivateFrame(std::move(pending_frame_.value()));
- pending_frame_.reset();
+ DCHECK(pending_frame_data_);
+ FrameData frame_data = std::move(*pending_frame_data_);
+ pending_frame_data_.reset();
+ ActivateFrame(std::move(frame_data));
}
// A frame is activated if all its Surface ID dependences are active or a
// deadline has hit and the frame was forcibly activated by the display
// compositor.
-void Surface::ActivateFrame(CompositorFrame frame) {
- DCHECK(factory_);
+void Surface::ActivateFrame(FrameData frame_data) {
+ DCHECK(compositor_frame_sink_support_);
// Save root pass copy requests.
std::vector<std::unique_ptr<CopyOutputRequest>> old_copy_requests;
- if (active_frame_ && !active_frame_->render_pass_list.empty()) {
+ if (active_frame_data_) {
std::swap(old_copy_requests,
- active_frame_->render_pass_list.back()->copy_requests);
+ active_frame_data_->frame.render_pass_list.back()->copy_requests);
}
ClearCopyRequests();
- TakeLatencyInfo(&frame.metadata.latency_info);
+ TakeLatencyInfo(&frame_data.frame.metadata.latency_info);
- base::Optional<CompositorFrame> previous_frame = std::move(active_frame_);
- active_frame_ = std::move(frame);
+ base::Optional<FrameData> previous_frame_data = std::move(active_frame_data_);
+
+ active_frame_data_ = std::move(frame_data);
for (auto& copy_request : old_copy_requests)
RequestCopyOfOutput(std::move(copy_request));
- // Empty frames shouldn't be drawn and shouldn't contribute damage, so don't
- // increment frame index for them.
- if (!active_frame_->render_pass_list.empty())
- ++frame_index_;
+ ++frame_index_;
previous_frame_surface_id_ = surface_id();
- if (previous_frame)
- UnrefFrameResources(*previous_frame);
+ UnrefFrameResourcesAndRunDrawCallback(std::move(previous_frame_data));
- for (auto& observer : observers_)
- observer.OnSurfaceActivated(this);
+ compositor_frame_sink_support_->OnSurfaceActivated(this);
}
-void Surface::UpdateBlockingSurfaces(
- const base::Optional<CompositorFrame>& previous_pending_frame,
- const CompositorFrame& current_frame) {
+void Surface::UpdateBlockingSurfaces(bool has_previous_pending_frame,
+ const CompositorFrame& current_frame) {
// If there is no SurfaceDependencyTracker installed then the |current_frame|
// does not block on anything.
- if (!factory_->manager()->dependency_tracker()) {
+ if (!surface_manager_->dependency_tracker()) {
blocking_surfaces_.clear();
return;
}
base::flat_set<SurfaceId> new_blocking_surfaces;
- for (const SurfaceId& surface_id : current_frame.metadata.embedded_surfaces) {
- Surface* surface = factory_->manager()->GetSurfaceForId(surface_id);
+ for (const SurfaceId& surface_id :
+ current_frame.metadata.activation_dependencies) {
+ Surface* surface = surface_manager_->GetSurfaceForId(surface_id);
// If a referenced surface does not have a corresponding active frame in the
// display compositor, then it blocks this frame.
if (!surface || !surface->HasActiveFrame())
@@ -215,14 +256,14 @@ void Surface::UpdateBlockingSurfaces(
// If this Surface has a previous pending frame, then we must determine the
// changes in dependencies so that we can update the SurfaceDependencyTracker
// map.
- if (previous_pending_frame.has_value()) {
- SurfaceDependencies removed_dependencies;
+ if (has_previous_pending_frame) {
+ base::flat_set<SurfaceId> removed_dependencies;
for (const SurfaceId& surface_id : blocking_surfaces_) {
if (!new_blocking_surfaces.count(surface_id))
removed_dependencies.insert(surface_id);
}
- SurfaceDependencies added_dependencies;
+ base::flat_set<SurfaceId> added_dependencies;
for (const SurfaceId& surface_id : new_blocking_surfaces) {
if (!blocking_surfaces_.count(surface_id))
added_dependencies.insert(surface_id);
@@ -230,10 +271,8 @@ void Surface::UpdateBlockingSurfaces(
// If there is a change in the dependency set, then inform observers.
if (!added_dependencies.empty() || !removed_dependencies.empty()) {
- for (auto& observer : observers_) {
- observer.OnSurfaceDependenciesChanged(this, added_dependencies,
- removed_dependencies);
- }
+ surface_manager_->SurfaceDependenciesChanged(this, added_dependencies,
+ removed_dependencies);
}
}
@@ -243,10 +282,10 @@ void Surface::UpdateBlockingSurfaces(
void Surface::TakeCopyOutputRequests(
std::multimap<int, std::unique_ptr<CopyOutputRequest>>* copy_requests) {
DCHECK(copy_requests->empty());
- if (!active_frame_)
+ if (!active_frame_data_)
return;
- for (const auto& render_pass : active_frame_->render_pass_list) {
+ for (const auto& render_pass : active_frame_data_->frame.render_pass_list) {
for (auto& request : render_pass->copy_requests) {
copy_requests->insert(
std::make_pair(render_pass->id, std::move(request)));
@@ -256,29 +295,37 @@ void Surface::TakeCopyOutputRequests(
}
const CompositorFrame& Surface::GetActiveFrame() const {
- DCHECK(active_frame_);
- return active_frame_.value();
+ DCHECK(active_frame_data_);
+ return active_frame_data_->frame;
}
const CompositorFrame& Surface::GetPendingFrame() {
- DCHECK(pending_frame_);
- return pending_frame_.value();
+ DCHECK(pending_frame_data_);
+ return pending_frame_data_->frame;
}
void Surface::TakeLatencyInfo(std::vector<ui::LatencyInfo>* latency_info) {
- if (!active_frame_)
+ if (!active_frame_data_)
return;
- TakeLatencyInfoFromFrame(&active_frame_.value(), latency_info);
+ TakeLatencyInfoFromFrame(&active_frame_data_->frame, latency_info);
}
-void Surface::RunDrawCallbacks() {
- if (!draw_callback_.is_null()) {
- DrawCallback callback = draw_callback_;
- draw_callback_ = DrawCallback();
+void Surface::RunDrawCallback() {
+ if (active_frame_data_ && !active_frame_data_->draw_callback.is_null()) {
+ base::Closure callback = active_frame_data_->draw_callback;
+ active_frame_data_->draw_callback = base::Closure();
callback.Run();
}
}
+void Surface::RunWillDrawCallback(const gfx::Rect& damage_rect) {
+ if (!active_frame_data_ || active_frame_data_->will_draw_callback.is_null())
+ return;
+
+ active_frame_data_->will_draw_callback.Run(surface_id().local_surface_id(),
+ damage_rect);
+}
+
void Surface::AddDestructionDependency(SurfaceSequence sequence) {
destruction_dependencies_.push_back(sequence);
}
@@ -293,18 +340,26 @@ void Surface::SatisfyDestructionDependencies(
});
}
-void Surface::UnrefFrameResources(const CompositorFrame& frame) {
+void Surface::UnrefFrameResourcesAndRunDrawCallback(
+ base::Optional<FrameData> frame_data) {
+ if (!frame_data || !compositor_frame_sink_support_)
+ return;
+
ReturnedResourceArray resources;
- TransferableResource::ReturnResources(frame.resource_list, &resources);
+ TransferableResource::ReturnResources(frame_data->frame.resource_list,
+ &resources);
// No point in returning same sync token to sender.
for (auto& resource : resources)
resource.sync_token.Clear();
- factory_->UnrefResources(resources);
+ compositor_frame_sink_support_->UnrefResources(resources);
+
+ if (!frame_data->draw_callback.is_null())
+ frame_data->draw_callback.Run();
}
void Surface::ClearCopyRequests() {
- if (active_frame_) {
- for (const auto& render_pass : active_frame_->render_pass_list) {
+ if (active_frame_data_) {
+ for (const auto& render_pass : active_frame_data_->frame.render_pass_list) {
for (const auto& copy_request : render_pass->copy_requests)
copy_request->SendEmptyResult();
}
@@ -313,9 +368,9 @@ void Surface::ClearCopyRequests() {
void Surface::TakeLatencyInfoFromPendingFrame(
std::vector<ui::LatencyInfo>* latency_info) {
- if (!pending_frame_)
+ if (!pending_frame_data_)
return;
- TakeLatencyInfoFromFrame(&pending_frame_.value(), latency_info);
+ TakeLatencyInfoFromFrame(&pending_frame_data_->frame, latency_info);
}
// static
diff --git a/chromium/cc/surfaces/surface.h b/chromium/cc/surfaces/surface.h
index 6cd9bbf70db..56e1403b6b3 100644
--- a/chromium/cc/surfaces/surface.h
+++ b/chromium/cc/surfaces/surface.h
@@ -19,10 +19,9 @@
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "cc/output/copy_output_request.h"
+#include "cc/surfaces/compositor_frame_sink_support.h"
#include "cc/surfaces/frame_sink_id.h"
-#include "cc/surfaces/pending_frame_observer.h"
-#include "cc/surfaces/surface_factory.h"
-#include "cc/surfaces/surface_id.h"
+#include "cc/surfaces/surface_info.h"
#include "cc/surfaces/surface_sequence.h"
#include "cc/surfaces/surfaces_export.h"
#include "ui/gfx/geometry/size.h"
@@ -33,35 +32,40 @@ class LatencyInfo;
namespace cc {
-class BeginFrameSource;
class CompositorFrame;
class CopyOutputRequest;
-class SurfaceFactory;
class CC_SURFACES_EXPORT Surface {
public:
- using DrawCallback = SurfaceFactory::DrawCallback;
+ using WillDrawCallback =
+ base::RepeatingCallback<void(const LocalSurfaceId&, const gfx::Rect&)>;
- Surface(const SurfaceId& id, base::WeakPtr<SurfaceFactory> factory);
+ Surface(
+ const SurfaceInfo& surface_info,
+ base::WeakPtr<CompositorFrameSinkSupport> compositor_frame_sink_support);
~Surface();
- const SurfaceId& surface_id() const { return surface_id_; }
+ const SurfaceId& surface_id() const { return surface_info_.id(); }
const SurfaceId& previous_frame_surface_id() const {
return previous_frame_surface_id_;
}
void SetPreviousFrameSurface(Surface* surface);
- void QueueFrame(CompositorFrame frame, const DrawCallback& draw_callback);
- void EvictFrame();
+ // Returns false if |frame| is invalid.
+ // |draw_callback| is called once to notify the client that the previously
+ // submitted CompositorFrame is processed and that another frame can be
+ // submitted.
+ // |will_draw_callback| is called when |surface| is scheduled for a draw and
+ // there is visible damage.
+ bool QueueFrame(CompositorFrame frame,
+ const base::Closure& draw_callback,
+ const WillDrawCallback& will_draw_callback);
void RequestCopyOfOutput(std::unique_ptr<CopyOutputRequest> copy_request);
// Notifies the Surface that a blocking SurfaceId now has an active frame.
void NotifySurfaceIdAvailable(const SurfaceId& surface_id);
- void AddObserver(PendingFrameObserver* observer);
- void RemoveObserver(PendingFrameObserver* observer);
-
// Called if a deadline has been hit and this surface is not yet active but
// it's marked as respecting deadlines.
void ActivatePendingFrameForDeadline();
@@ -84,9 +88,12 @@ class CC_SURFACES_EXPORT Surface {
int frame_index() const { return frame_index_; }
void TakeLatencyInfo(std::vector<ui::LatencyInfo>* latency_info);
- void RunDrawCallbacks();
+ void RunDrawCallback();
+ void RunWillDrawCallback(const gfx::Rect& damage_rect);
- base::WeakPtr<SurfaceFactory> factory() { return factory_; }
+ base::WeakPtr<CompositorFrameSinkSupport> compositor_frame_sink_support() {
+ return compositor_frame_sink_support_;
+ }
// Add a SurfaceSequence that must be satisfied before the Surface is
// destroyed.
@@ -102,29 +109,46 @@ class CC_SURFACES_EXPORT Surface {
}
const std::vector<SurfaceId>* active_referenced_surfaces() const {
- return active_frame_ ? &active_frame_->metadata.referenced_surfaces
- : nullptr;
+ return active_frame_data_
+ ? &active_frame_data_->frame.metadata.referenced_surfaces
+ : nullptr;
}
- const SurfaceDependencies& blocking_surfaces() const {
+ const base::flat_set<SurfaceId>& blocking_surfaces() const {
return blocking_surfaces_;
}
- bool HasActiveFrame() const { return active_frame_.has_value(); }
- bool HasPendingFrame() const { return pending_frame_.has_value(); }
+ bool HasActiveFrame() const { return active_frame_data_.has_value(); }
+ bool HasPendingFrame() const { return pending_frame_data_.has_value(); }
bool destroyed() const { return destroyed_; }
void set_destroyed(bool destroyed) { destroyed_ = destroyed; }
private:
+ struct FrameData {
+ FrameData(CompositorFrame&& frame,
+ const base::Closure& draw_callback,
+ const WillDrawCallback& will_draw_callback);
+ FrameData(FrameData&& other);
+ ~FrameData();
+ FrameData& operator=(FrameData&& other);
+ CompositorFrame frame;
+ base::Closure draw_callback;
+ WillDrawCallback will_draw_callback;
+ };
+
+ // Called to prevent additional CompositorFrames from being accepted into this
+ // surface. Once a Surface is closed, it cannot accept CompositorFrames again.
+ void Close();
+
void ActivatePendingFrame();
// Called when all of the surface's dependencies have been resolved.
- void ActivateFrame(CompositorFrame frame);
- void UpdateBlockingSurfaces(
- const base::Optional<CompositorFrame>& previous_pending_frame,
- const CompositorFrame& current_frame);
+ void ActivateFrame(FrameData frame_data);
+ void UpdateBlockingSurfaces(bool has_previous_pending_frame,
+ const CompositorFrame& current_frame);
- void UnrefFrameResources(const CompositorFrame& frame_data);
+ void UnrefFrameResourcesAndRunDrawCallback(
+ base::Optional<FrameData> frame_data);
void ClearCopyRequests();
void TakeLatencyInfoFromPendingFrame(
@@ -133,24 +157,19 @@ class CC_SURFACES_EXPORT Surface {
CompositorFrame* frame,
std::vector<ui::LatencyInfo>* latency_info);
- SurfaceId surface_id_;
+ SurfaceInfo surface_info_;
SurfaceId previous_frame_surface_id_;
- base::WeakPtr<SurfaceFactory> factory_;
- // TODO(jamesr): Support multiple frames in flight.
- base::Optional<CompositorFrame> pending_frame_;
- base::Optional<CompositorFrame> active_frame_;
+ base::WeakPtr<CompositorFrameSinkSupport> compositor_frame_sink_support_;
+ SurfaceManager* const surface_manager_;
+
+ base::Optional<FrameData> pending_frame_data_;
+ base::Optional<FrameData> active_frame_data_;
int frame_index_;
+ bool closed_ = false;
bool destroyed_;
std::vector<SurfaceSequence> destruction_dependencies_;
- // This surface may have multiple BeginFrameSources if it is
- // on multiple Displays.
- std::set<BeginFrameSource*> begin_frame_sources_;
-
- SurfaceDependencies blocking_surfaces_;
- base::ObserverList<PendingFrameObserver, true> observers_;
-
- DrawCallback draw_callback_;
+ base::flat_set<SurfaceId> blocking_surfaces_;
DISALLOW_COPY_AND_ASSIGN(Surface);
};
diff --git a/chromium/cc/surfaces/surface_aggregator.cc b/chromium/cc/surfaces/surface_aggregator.cc
index db1366da53c..f0e73f8a06a 100644
--- a/chromium/cc/surfaces/surface_aggregator.cc
+++ b/chromium/cc/surfaces/surface_aggregator.cc
@@ -25,8 +25,8 @@
#include "cc/quads/surface_draw_quad.h"
#include "cc/quads/texture_draw_quad.h"
#include "cc/resources/resource_provider.h"
+#include "cc/surfaces/compositor_frame_sink_support.h"
#include "cc/surfaces/surface.h"
-#include "cc/surfaces/surface_factory.h"
#include "cc/surfaces/surface_manager.h"
#include "cc/trees/blocking_task_runner.h"
@@ -121,11 +121,12 @@ SurfaceAggregator::ClipData SurfaceAggregator::CalculateClipRect(
return out_clip;
}
-static void UnrefHelper(base::WeakPtr<SurfaceFactory> surface_factory,
- const ReturnedResourceArray& resources,
- BlockingTaskRunner* main_thread_task_runner) {
- if (surface_factory)
- surface_factory->UnrefResources(resources);
+static void UnrefHelper(
+ base::WeakPtr<CompositorFrameSinkSupport> compositor_frame_sink_support,
+ const ReturnedResourceArray& resources,
+ BlockingTaskRunner* main_thread_task_runner) {
+ if (compositor_frame_sink_support)
+ compositor_frame_sink_support->UnrefResources(resources);
}
int SurfaceAggregator::RemapPassId(int surface_local_pass_id,
@@ -144,14 +145,14 @@ int SurfaceAggregator::RemapPassId(int surface_local_pass_id,
}
int SurfaceAggregator::ChildIdForSurface(Surface* surface) {
- SurfaceToResourceChildIdMap::iterator it =
- surface_id_to_resource_child_id_.find(surface->surface_id());
+ auto it = surface_id_to_resource_child_id_.find(surface->surface_id());
if (it == surface_id_to_resource_child_id_.end()) {
- int child_id =
- provider_->CreateChild(base::Bind(&UnrefHelper, surface->factory()));
- if (surface->factory()) {
+ int child_id = provider_->CreateChild(
+ base::Bind(&UnrefHelper, surface->compositor_frame_sink_support()));
+ if (surface->compositor_frame_sink_support()) {
provider_->SetChildNeedsSyncTokens(
- child_id, surface->factory()->needs_sync_points());
+ child_id,
+ surface->compositor_frame_sink_support()->needs_sync_points());
}
surface_id_to_resource_child_id_[surface->surface_id()] = child_id;
return child_id;
@@ -239,7 +240,7 @@ void SurfaceAggregator::HandleSurfaceQuad(
return;
}
- SurfaceSet::iterator it = referenced_surfaces_.insert(surface_id).first;
+ referenced_surfaces_.insert(surface_id);
// TODO(vmpstr): provider check is a hack for unittests that don't set up a
// resource provider.
ResourceProvider::ResourceIdMap empty_map;
@@ -337,7 +338,8 @@ void SurfaceAggregator::HandleSurfaceQuad(
gfx::RectF(surface_quad->rect));
}
- referenced_surfaces_.erase(it);
+ // Need to re-query since referenced_surfaces_ iterators are not stable.
+ referenced_surfaces_.erase(referenced_surfaces_.find(surface_id));
}
void SurfaceAggregator::AddColorConversionPass() {
@@ -362,7 +364,7 @@ void SurfaceAggregator::AddColorConversionPass() {
SharedQuadState* shared_quad_state =
color_conversion_pass->CreateAndAppendSharedQuadState();
- shared_quad_state->quad_layer_bounds = output_rect.size();
+ shared_quad_state->quad_layer_rect = output_rect;
shared_quad_state->visible_quad_layer_rect = output_rect;
shared_quad_state->opacity = 1.f;
@@ -568,8 +570,7 @@ void SurfaceAggregator::ProcessAddedAndRemovedSurfaces() {
for (const auto& surface : previous_contained_surfaces_) {
if (!contained_surfaces_.count(surface.first)) {
// Release resources of removed surface.
- SurfaceToResourceChildIdMap::iterator it =
- surface_id_to_resource_child_id_.find(surface.first);
+ auto it = surface_id_to_resource_child_id_.find(surface.first);
if (it != surface_id_to_resource_child_id_.end()) {
provider_->DestroyChild(it->second);
surface_id_to_resource_child_id_.erase(it);
@@ -578,7 +579,7 @@ void SurfaceAggregator::ProcessAddedAndRemovedSurfaces() {
// Notify client of removed surface.
Surface* surface_ptr = manager_->GetSurfaceForId(surface.first);
if (surface_ptr) {
- surface_ptr->RunDrawCallbacks();
+ surface_ptr->RunDrawCallback();
}
}
}
@@ -611,13 +612,14 @@ gfx::Rect SurfaceAggregator::PrewalkTree(const SurfaceId& surface_id,
// TODO(jbauman): hack for unit tests that don't set up rp
if (provider_) {
child_id = ChildIdForSurface(surface);
- if (surface->factory())
- surface->factory()->RefResources(frame.resource_list);
+ if (surface->compositor_frame_sink_support())
+ surface->compositor_frame_sink_support()->RefResources(
+ frame.resource_list);
provider_->ReceiveFromChild(child_id, frame.resource_list);
}
CHECK(debug_weak_this.get());
- ResourceIdSet referenced_resources;
+ std::vector<ResourceId> referenced_resources;
size_t reserve_size = frame.resource_list.size();
referenced_resources.reserve(reserve_size);
@@ -627,14 +629,12 @@ gfx::Rect SurfaceAggregator::PrewalkTree(const SurfaceId& surface_id,
provider_ ? provider_->GetChildToParentMap(child_id) : empty_map;
CHECK(debug_weak_this.get());
- if (!frame.render_pass_list.empty()) {
- int remapped_pass_id =
- RemapPassId(frame.render_pass_list.back()->id, surface_id);
- if (in_moved_pixel_surface)
- moved_pixel_passes_.insert(remapped_pass_id);
- if (parent_pass_id)
- render_pass_dependencies_[parent_pass_id].insert(remapped_pass_id);
- }
+ int remapped_pass_id =
+ RemapPassId(frame.render_pass_list.back()->id, surface_id);
+ if (in_moved_pixel_surface)
+ moved_pixel_passes_.insert(remapped_pass_id);
+ if (parent_pass_id)
+ render_pass_dependencies_[parent_pass_id].insert(remapped_pass_id);
struct SurfaceInfo {
SurfaceInfo(const SurfaceId& id,
@@ -653,13 +653,18 @@ gfx::Rect SurfaceAggregator::PrewalkTree(const SurfaceId& surface_id,
};
std::vector<SurfaceInfo> child_surfaces;
- std::unordered_set<int> pixel_moving_background_filter_passes;
+ // This data is created once and typically small or empty. Collect all items
+ // and pass to a flat_vector to sort once.
+ std::vector<int> pixel_moving_background_filter_passes_data;
for (const auto& render_pass : frame.render_pass_list) {
if (render_pass->background_filters.HasFilterThatMovesPixels()) {
- pixel_moving_background_filter_passes.insert(
+ pixel_moving_background_filter_passes_data.push_back(
RemapPassId(render_pass->id, surface_id));
}
}
+ base::flat_set<int> pixel_moving_background_filter_passes(
+ std::move(pixel_moving_background_filter_passes_data),
+ base::KEEP_FIRST_OF_DUPES);
for (const auto& render_pass : base::Reversed(frame.render_pass_list)) {
int remapped_pass_id = RemapPassId(render_pass->id, surface_id);
@@ -701,7 +706,7 @@ gfx::Rect SurfaceAggregator::PrewalkTree(const SurfaceId& surface_id,
invalid_frame = true;
break;
}
- referenced_resources.insert(resource_id);
+ referenced_resources.push_back(resource_id);
}
}
}
@@ -711,23 +716,22 @@ gfx::Rect SurfaceAggregator::PrewalkTree(const SurfaceId& surface_id,
CHECK(debug_weak_this.get());
valid_surfaces_.insert(surface->surface_id());
+ ResourceIdSet resource_set(std::move(referenced_resources),
+ base::KEEP_FIRST_OF_DUPES);
if (provider_)
- provider_->DeclareUsedResourcesFromChild(child_id, referenced_resources);
+ provider_->DeclareUsedResourcesFromChild(child_id, resource_set);
CHECK(debug_weak_this.get());
gfx::Rect damage_rect;
gfx::Rect full_damage;
- if (!frame.render_pass_list.empty()) {
- RenderPass* last_pass = frame.render_pass_list.back().get();
- full_damage = last_pass->output_rect;
- damage_rect =
- DamageRectForSurface(surface, *last_pass, last_pass->output_rect);
- }
+ RenderPass* last_pass = frame.render_pass_list.back().get();
+ full_damage = last_pass->output_rect;
+ damage_rect =
+ DamageRectForSurface(surface, *last_pass, last_pass->output_rect);
// Avoid infinite recursion by adding current surface to
// referenced_surfaces_.
- SurfaceSet::iterator it =
- referenced_surfaces_.insert(surface->surface_id()).first;
+ referenced_surfaces_.insert(surface->surface_id());
for (const auto& surface_info : child_surfaces) {
gfx::Rect surface_damage =
PrewalkTree(surface_info.id, surface_info.has_moved_pixels,
@@ -754,10 +758,10 @@ gfx::Rect SurfaceAggregator::PrewalkTree(const SurfaceId& surface_id,
}
CHECK(debug_weak_this.get());
- if (surface->factory()) {
- surface->factory()->WillDrawSurface(
- surface->surface_id().local_surface_id(), damage_rect);
- }
+ // TODO(staraz): It shouldn't need to call the callback when the damage is
+ // from |surface| and not from |child_surfaces|.
+ if (!damage_rect.IsEmpty())
+ surface->RunWillDrawCallback(damage_rect);
CHECK(debug_weak_this.get());
for (const auto& render_pass : frame.render_pass_list) {
@@ -767,7 +771,7 @@ gfx::Rect SurfaceAggregator::PrewalkTree(const SurfaceId& surface_id,
}
}
- referenced_surfaces_.erase(it);
+ referenced_surfaces_.erase(referenced_surfaces_.find(surface->surface_id()));
if (!damage_rect.IsEmpty() && frame.metadata.may_contain_video)
result->may_contain_video = true;
return damage_rect;
@@ -808,7 +812,7 @@ void SurfaceAggregator::CopyUndrawnSurfaces(PrewalkResult* prewalk_result) {
}
}
} else {
- SurfaceSet::iterator it = referenced_surfaces_.insert(surface_id).first;
+ auto it = referenced_surfaces_.insert(surface_id).first;
CopyPasses(frame, surface);
referenced_surfaces_.erase(it);
}
@@ -847,7 +851,6 @@ CompositorFrame SurfaceAggregator::Aggregate(const SurfaceId& surface_id) {
CompositorFrame frame;
- dest_resource_list_ = &frame.resource_list;
dest_pass_list_ = &frame.render_pass_list;
valid_surfaces_.clear();
@@ -858,9 +861,10 @@ CompositorFrame SurfaceAggregator::Aggregate(const SurfaceId& surface_id) {
frame.metadata.may_contain_video = prewalk_result.may_contain_video;
CopyUndrawnSurfaces(&prewalk_result);
- SurfaceSet::iterator it = referenced_surfaces_.insert(surface_id).first;
+ referenced_surfaces_.insert(surface_id);
CopyPasses(root_surface_frame, surface);
- referenced_surfaces_.erase(it);
+ // CopyPasses may have mutated container, need to re-query to erase.
+ referenced_surfaces_.erase(referenced_surfaces_.find(surface_id));
AddColorConversionPass();
moved_pixel_passes_.clear();
@@ -888,10 +892,8 @@ CompositorFrame SurfaceAggregator::Aggregate(const SurfaceId& surface_id) {
contained_surfaces_.swap(previous_contained_surfaces_);
contained_surfaces_.clear();
- for (SurfaceIndexMap::iterator it = previous_contained_surfaces_.begin();
- it != previous_contained_surfaces_.end();
- ++it) {
- Surface* surface = manager_->GetSurfaceForId(it->first);
+ for (auto it : previous_contained_surfaces_) {
+ Surface* surface = manager_->GetSurfaceForId(it.first);
if (surface)
surface->TakeLatencyInfo(&frame.metadata.latency_info);
}
@@ -912,8 +914,7 @@ CompositorFrame SurfaceAggregator::Aggregate(const SurfaceId& surface_id) {
}
void SurfaceAggregator::ReleaseResources(const SurfaceId& surface_id) {
- SurfaceToResourceChildIdMap::iterator it =
- surface_id_to_resource_child_id_.find(surface_id);
+ auto it = surface_id_to_resource_child_id_.find(surface_id);
if (it != surface_id_to_resource_child_id_.end()) {
provider_->DestroyChild(it->second);
surface_id_to_resource_child_id_.erase(it);
diff --git a/chromium/cc/surfaces/surface_aggregator.h b/chromium/cc/surfaces/surface_aggregator.h
index ec69f5d3319..28aeb493bcc 100644
--- a/chromium/cc/surfaces/surface_aggregator.h
+++ b/chromium/cc/surfaces/surface_aggregator.h
@@ -5,12 +5,11 @@
#ifndef CC_SURFACES_SURFACE_AGGREGATOR_H_
#define CC_SURFACES_SURFACE_AGGREGATOR_H_
-#include <map>
#include <memory>
-#include <set>
#include <unordered_map>
-#include <unordered_set>
+#include "base/containers/flat_map.h"
+#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "cc/quads/draw_quad.h"
@@ -30,7 +29,7 @@ class SurfaceManager;
class CC_SURFACES_EXPORT SurfaceAggregator {
public:
- using SurfaceIndexMap = std::unordered_map<SurfaceId, int, SurfaceIdHash>;
+ using SurfaceIndexMap = base::flat_map<SurfaceId, int>;
SurfaceAggregator(SurfaceManager* manager,
ResourceProvider* provider,
@@ -65,7 +64,7 @@ class CC_SURFACES_EXPORT SurfaceAggregator {
~PrewalkResult();
// This is the set of Surfaces that were referenced by another Surface, but
// not included in a SurfaceDrawQuad.
- std::set<SurfaceId> undrawn_surfaces;
+ base::flat_set<SurfaceId> undrawn_surfaces;
bool may_contain_video = false;
};
@@ -145,9 +144,8 @@ class CC_SURFACES_EXPORT SurfaceAggregator {
// each source (SurfaceId, RenderPass id) to a unified ID namespace that's
// used in the aggregated frame. An entry is removed from the map if it's not
// used for one output frame.
- using RenderPassIdAllocatorMap =
- std::map<std::pair<SurfaceId, int>, RenderPassInfo>;
- RenderPassIdAllocatorMap render_pass_allocator_map_;
+ base::flat_map<std::pair<SurfaceId, int>, RenderPassInfo>
+ render_pass_allocator_map_;
int next_render_pass_id_;
const bool aggregate_only_damaged_;
bool output_is_secure_;
@@ -162,9 +160,7 @@ class CC_SURFACES_EXPORT SurfaceAggregator {
// The id for the final color conversion render pass.
int color_conversion_render_pass_id_ = 0;
- using SurfaceToResourceChildIdMap =
- std::unordered_map<SurfaceId, int, SurfaceIdHash>;
- SurfaceToResourceChildIdMap surface_id_to_resource_child_id_;
+ base::flat_map<SurfaceId, int> surface_id_to_resource_child_id_;
// The following state is only valid for the duration of one Aggregate call
// and is only stored on the class to avoid having to pass through every
@@ -172,8 +168,7 @@ class CC_SURFACES_EXPORT SurfaceAggregator {
// This is the set of surfaces referenced in the aggregation so far, used to
// detect cycles.
- using SurfaceSet = std::set<SurfaceId>;
- SurfaceSet referenced_surfaces_;
+ base::flat_set<SurfaceId> referenced_surfaces_;
// For each Surface used in the last aggregation, gives the frame_index at
// that time.
@@ -181,22 +176,22 @@ class CC_SURFACES_EXPORT SurfaceAggregator {
SurfaceIndexMap contained_surfaces_;
// After surface validation, every Surface in this set is valid.
- std::unordered_set<SurfaceId, SurfaceIdHash> valid_surfaces_;
+ base::flat_set<SurfaceId> valid_surfaces_;
// This is the pass list for the aggregated frame.
RenderPassList* dest_pass_list_;
// This is the set of aggregated pass ids that are affected by filters that
// move pixels.
- std::unordered_set<int> moved_pixel_passes_;
+ base::flat_set<int> moved_pixel_passes_;
// This is the set of aggregated pass ids that are drawn by copy requests, so
// should not have their damage rects clipped to the root damage rect.
- std::unordered_set<int> copy_request_passes_;
+ base::flat_set<int> copy_request_passes_;
// This maps each aggregated pass id to the set of (aggregated) pass ids
// that its RenderPassDrawQuads depend on
- std::unordered_map<int, std::unordered_set<int>> render_pass_dependencies_;
+ base::flat_map<int, base::flat_set<int>> render_pass_dependencies_;
// The root damage rect of the currently-aggregating frame.
gfx::Rect root_damage_rect_;
@@ -205,9 +200,6 @@ class CC_SURFACES_EXPORT SurfaceAggregator {
// This is valid during Aggregate after PrewalkTree is called.
bool has_copy_requests_;
- // Resource list for the aggregated frame.
- TransferableResourceArray* dest_resource_list_;
-
// Tracks UMA stats for SurfaceDrawQuads during a call to Aggregate().
SurfaceDrawQuadUmaStats uma_stats_;
diff --git a/chromium/cc/surfaces/surface_aggregator_perftest.cc b/chromium/cc/surfaces/surface_aggregator_perftest.cc
index 691acfd9908..ac7fb4b5b45 100644
--- a/chromium/cc/surfaces/surface_aggregator_perftest.cc
+++ b/chromium/cc/surfaces/surface_aggregator_perftest.cc
@@ -7,10 +7,10 @@
#include "cc/output/compositor_frame.h"
#include "cc/quads/surface_draw_quad.h"
#include "cc/quads/texture_draw_quad.h"
+#include "cc/surfaces/compositor_frame_sink_support.h"
#include "cc/surfaces/surface_aggregator.h"
-#include "cc/surfaces/surface_factory.h"
-#include "cc/surfaces/surface_factory_client.h"
#include "cc/surfaces/surface_manager.h"
+#include "cc/test/compositor_frame_helpers.h"
#include "cc/test/fake_output_surface_client.h"
#include "cc/test/fake_resource_provider.h"
#include "cc/test/test_context_provider.h"
@@ -21,14 +21,12 @@
namespace cc {
namespace {
-static const base::UnguessableToken kArbitraryToken =
- base::UnguessableToken::Create();
+constexpr bool kIsRoot = true;
+constexpr bool kIsChildRoot = false;
+constexpr bool kHandlesFrameSinkIdInvalidation = true;
+constexpr bool kNeedsSyncPoints = true;
-class EmptySurfaceFactoryClient : public SurfaceFactoryClient {
- public:
- void ReturnResources(const ReturnedResourceArray& resources) override {}
- void SetBeginFrameSource(BeginFrameSource* begin_frame_source) override {}
-};
+const base::UnguessableToken kArbitraryToken = base::UnguessableToken::Create();
class SurfaceAggregatorPerfTest : public testing::Test {
public:
@@ -47,16 +45,22 @@ class SurfaceAggregatorPerfTest : public testing::Test {
bool optimize_damage,
bool full_damage,
const std::string& name) {
- std::vector<std::unique_ptr<SurfaceFactory>> child_factories(num_surfaces);
- for (int i = 0; i < num_surfaces; i++)
- child_factories[i].reset(
- new SurfaceFactory(FrameSinkId(1, i + 1), &manager_, &empty_client_));
+ std::vector<std::unique_ptr<CompositorFrameSinkSupport>> child_supports(
+ num_surfaces);
+ for (int i = 0; i < num_surfaces; i++) {
+ child_supports[i] = CompositorFrameSinkSupport::Create(
+ nullptr, &manager_, FrameSinkId(1, i + 1), kIsChildRoot,
+ kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+ }
aggregator_.reset(new SurfaceAggregator(&manager_, resource_provider_.get(),
optimize_damage));
for (int i = 0; i < num_surfaces; i++) {
LocalSurfaceId local_surface_id(i + 1, kArbitraryToken);
+
std::unique_ptr<RenderPass> pass(RenderPass::Create());
- CompositorFrame frame;
+ pass->output_rect = gfx::Rect(0, 0, 1, 2);
+
+ CompositorFrame frame = test::MakeEmptyCompositorFrame();
SharedQuadState* sqs = pass->CreateAndAppendSharedQuadState();
for (int j = 0; j < num_textures; j++) {
@@ -67,11 +71,11 @@ class SurfaceAggregatorPerfTest : public testing::Test {
TextureDrawQuad* quad =
pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
- const gfx::Rect rect(0, 0, 1, 1);
+ const gfx::Rect rect(0, 0, 1, 2);
const gfx::Rect opaque_rect;
// Half of rects should be visible with partial damage.
gfx::Rect visible_rect =
- j % 2 == 0 ? gfx::Rect(0, 0, 1, 1) : gfx::Rect(1, 1, 1, 1);
+ j % 2 == 0 ? gfx::Rect(0, 0, 1, 2) : gfx::Rect(0, 1, 1, 1);
bool needs_blending = false;
bool premultiplied_alpha = false;
const gfx::PointF uv_top_left;
@@ -97,16 +101,18 @@ class SurfaceAggregatorPerfTest : public testing::Test {
}
frame.render_pass_list.push_back(std::move(pass));
- child_factories[i]->SubmitCompositorFrame(
- local_surface_id, std::move(frame), SurfaceFactory::DrawCallback());
+ child_supports[i]->SubmitCompositorFrame(local_surface_id,
+ std::move(frame));
}
- SurfaceFactory root_factory(FrameSinkId(1, num_surfaces + 1), &manager_,
- &empty_client_);
+ std::unique_ptr<CompositorFrameSinkSupport> root_support =
+ CompositorFrameSinkSupport::Create(
+ nullptr, &manager_, FrameSinkId(1, num_surfaces + 1), kIsRoot,
+ kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
timer_.Reset();
do {
std::unique_ptr<RenderPass> pass(RenderPass::Create());
- CompositorFrame frame;
+ CompositorFrame frame = test::MakeEmptyCompositorFrame();
SharedQuadState* sqs = pass->CreateAndAppendSharedQuadState();
SurfaceDrawQuad* surface_quad =
@@ -117,6 +123,8 @@ class SurfaceAggregatorPerfTest : public testing::Test {
LocalSurfaceId(num_surfaces, kArbitraryToken)),
SurfaceDrawQuadType::PRIMARY, nullptr);
+ pass->output_rect = gfx::Rect(0, 0, 100, 100);
+
if (full_damage)
pass->damage_rect = gfx::Rect(0, 0, 100, 100);
else
@@ -124,9 +132,8 @@ class SurfaceAggregatorPerfTest : public testing::Test {
frame.render_pass_list.push_back(std::move(pass));
- root_factory.SubmitCompositorFrame(
- LocalSurfaceId(num_surfaces + 1, kArbitraryToken), std::move(frame),
- SurfaceFactory::DrawCallback());
+ root_support->SubmitCompositorFrame(
+ LocalSurfaceId(num_surfaces + 1, kArbitraryToken), std::move(frame));
CompositorFrame aggregated = aggregator_->Aggregate(
SurfaceId(FrameSinkId(1, num_surfaces + 1),
@@ -137,13 +144,12 @@ class SurfaceAggregatorPerfTest : public testing::Test {
perf_test::PrintResult("aggregator_speed", "", name, timer_.LapsPerSecond(),
"runs/s", true);
for (int i = 0; i < num_surfaces; i++)
- child_factories[i]->EvictSurface();
- root_factory.EvictSurface();
+ child_supports[i]->EvictCurrentSurface();
+ root_support->EvictCurrentSurface();
}
protected:
SurfaceManager manager_;
- EmptySurfaceFactoryClient empty_client_;
scoped_refptr<TestContextProvider> context_provider_;
std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_;
std::unique_ptr<ResourceProvider> resource_provider_;
diff --git a/chromium/cc/surfaces/surface_aggregator_unittest.cc b/chromium/cc/surfaces/surface_aggregator_unittest.cc
index 04cca7989e7..0ba3a146963 100644
--- a/chromium/cc/surfaces/surface_aggregator_unittest.cc
+++ b/chromium/cc/surfaces/surface_aggregator_unittest.cc
@@ -22,6 +22,7 @@
#include "cc/surfaces/local_surface_id_allocator.h"
#include "cc/surfaces/surface.h"
#include "cc/surfaces/surface_manager.h"
+#include "cc/test/compositor_frame_helpers.h"
#include "cc/test/fake_compositor_frame_sink_support_client.h"
#include "cc/test/fake_resource_provider.h"
#include "cc/test/render_pass_test_utils.h"
@@ -72,7 +73,7 @@ class SurfaceAggregatorTest : public testing::Test {
SurfaceAggregatorTest() : SurfaceAggregatorTest(false) {}
void TearDown() override {
- support_->EvictFrame();
+ support_->EvictCurrentSurface();
testing::Test::TearDown();
}
@@ -83,15 +84,6 @@ class SurfaceAggregatorTest : public testing::Test {
SurfaceAggregator aggregator_;
};
-TEST_F(SurfaceAggregatorTest, ValidSurfaceNoFrame) {
- LocalSurfaceId local_surface_id(7, base::UnguessableToken::Create());
- SurfaceId one_id(kArbitraryRootFrameSinkId, local_surface_id);
- support_->SubmitCompositorFrame(local_surface_id, CompositorFrame());
-
- CompositorFrame frame = aggregator_.Aggregate(one_id);
- EXPECT_TRUE(frame.render_pass_list.empty());
-}
-
class SurfaceAggregatorValidSurfaceTest : public SurfaceAggregatorTest {
public:
explicit SurfaceAggregatorValidSurfaceTest(bool use_damage_rect)
@@ -114,7 +106,7 @@ class SurfaceAggregatorValidSurfaceTest : public SurfaceAggregatorTest {
}
void TearDown() override {
- child_support_->EvictFrame();
+ child_support_->EvictCurrentSurface();
SurfaceAggregatorTest::TearDown();
}
@@ -146,7 +138,7 @@ class SurfaceAggregatorValidSurfaceTest : public SurfaceAggregatorTest {
void SubmitPassListAsFrame(CompositorFrameSinkSupport* support,
const LocalSurfaceId& local_surface_id,
RenderPassList* pass_list) {
- CompositorFrame frame;
+ CompositorFrame frame = test::MakeEmptyCompositorFrame();
pass_list->swap(frame.render_pass_list);
support->SubmitCompositorFrame(local_surface_id, std::move(frame));
@@ -164,7 +156,7 @@ class SurfaceAggregatorValidSurfaceTest : public SurfaceAggregatorTest {
void QueuePassAsFrame(std::unique_ptr<RenderPass> pass,
const LocalSurfaceId& local_surface_id,
CompositorFrameSinkSupport* support) {
- CompositorFrame child_frame;
+ CompositorFrame child_frame = test::MakeEmptyCompositorFrame();
child_frame.render_pass_list.push_back(std::move(pass));
support->SubmitCompositorFrame(local_surface_id, std::move(child_frame));
@@ -238,7 +230,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, OpacityCopied) {
ASSERT_EQ(1u, shared_quad_state_list2.size());
EXPECT_EQ(.5f, shared_quad_state_list2.ElementAt(0)->opacity);
- embedded_support->EvictFrame();
+ embedded_support->EvictCurrentSurface();
}
TEST_F(SurfaceAggregatorValidSurfaceTest, MultiPassSimpleFrame) {
@@ -348,7 +340,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, SimpleSurfaceReference) {
AggregateAndVerify(
expected_passes, arraysize(expected_passes), ids, arraysize(ids));
- embedded_support->EvictFrame();
+ embedded_support->EvictCurrentSurface();
}
// This test verifies that in the absence of a primary Surface,
@@ -423,8 +415,8 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, FallbackSurfaceReference) {
AggregateAndVerify(expected_passes2, arraysize(expected_passes2), ids,
arraysize(ids));
- primary_child_support->EvictFrame();
- fallback_child_support->EvictFrame();
+ primary_child_support->EvictCurrentSurface();
+ fallback_child_support->EvictCurrentSurface();
}
// This test verifies that in the presence of both primary Surface and fallback
@@ -488,8 +480,8 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, FallbackSurfaceReferenceWithPrimary) {
AggregateAndVerify(expected_passes1, arraysize(expected_passes1), ids,
arraysize(ids));
- primary_child_support->EvictFrame();
- fallback_child_support->EvictFrame();
+ primary_child_support->EvictCurrentSurface();
+ fallback_child_support->EvictCurrentSurface();
}
TEST_F(SurfaceAggregatorValidSurfaceTest, CopyRequest) {
@@ -547,7 +539,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, CopyRequest) {
aggregator_.previous_contained_surfaces().end());
}
- embedded_support->EvictFrame();
+ embedded_support->EvictCurrentSurface();
}
// Root surface may contain copy requests.
@@ -582,7 +574,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, RootCopyRequest) {
test::Pass(root_quads, arraysize(root_quads), 1),
test::Pass(root_quads2, arraysize(root_quads2), 2)};
{
- CompositorFrame frame;
+ CompositorFrame frame = test::MakeEmptyCompositorFrame();
AddPasses(&frame.render_pass_list, gfx::Rect(SurfaceSize()), root_passes,
arraysize(root_passes));
frame.render_pass_list[0]->copy_requests.push_back(std::move(copy_request));
@@ -628,7 +620,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, RootCopyRequest) {
DCHECK(original_pass_list[0]->copy_requests.empty());
DCHECK(original_pass_list[1]->copy_requests.empty());
- embedded_support->EvictFrame();
+ embedded_support->EvictCurrentSurface();
}
TEST_F(SurfaceAggregatorValidSurfaceTest, UnreferencedSurface) {
@@ -669,7 +661,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, UnreferencedSurface) {
test::Pass(parent_quads, arraysize(parent_quads))};
{
- CompositorFrame frame;
+ CompositorFrame frame = test::MakeEmptyCompositorFrame();
AddPasses(&frame.render_pass_list, gfx::Rect(SurfaceSize()), parent_passes,
arraysize(parent_passes));
@@ -685,7 +677,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, UnreferencedSurface) {
test::Pass root_passes[] = {test::Pass(root_quads, arraysize(root_quads))};
{
- CompositorFrame frame;
+ CompositorFrame frame = test::MakeEmptyCompositorFrame();
AddPasses(&frame.render_pass_list, gfx::Rect(SurfaceSize()), root_passes,
arraysize(root_passes));
@@ -725,8 +717,8 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, UnreferencedSurface) {
aggregator_.previous_contained_surfaces().end());
}
- embedded_support->EvictFrame();
- parent_support->EvictFrame();
+ embedded_support->EvictCurrentSurface();
+ parent_support->EvictCurrentSurface();
}
// This tests referencing a surface that has multiple render passes.
@@ -1042,7 +1034,7 @@ void AddSolidColorQuadWithBlendMode(const gfx::Size& size,
RenderPass* pass,
const SkBlendMode blend_mode) {
const gfx::Transform layer_to_target_transform;
- const gfx::Size layer_bounds(size);
+ const gfx::Rect layer_rect(size);
const gfx::Rect visible_layer_rect(size);
const gfx::Rect clip_rect(size);
@@ -1051,7 +1043,7 @@ void AddSolidColorQuadWithBlendMode(const gfx::Size& size,
bool force_anti_aliasing_off = false;
SharedQuadState* sqs = pass->CreateAndAppendSharedQuadState();
- sqs->SetAll(layer_to_target_transform, layer_bounds, visible_layer_rect,
+ sqs->SetAll(layer_to_target_transform, layer_rect, visible_layer_rect,
clip_rect, is_clipped, opacity, blend_mode, 0);
SolidColorDrawQuad* color_quad =
@@ -1114,8 +1106,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateSharedQuadStateProperties) {
LocalSurfaceId grandchild_local_surface_id = allocator_.GenerateId();
SurfaceId grandchild_surface_id(grandchild_support->frame_sink_id(),
grandchild_local_surface_id);
- grandchild_support->SubmitCompositorFrame(grandchild_local_surface_id,
- CompositorFrame());
+
std::unique_ptr<RenderPass> grandchild_pass = RenderPass::Create();
gfx::Rect output_rect(SurfaceSize());
gfx::Rect damage_rect(SurfaceSize());
@@ -1130,8 +1121,6 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateSharedQuadStateProperties) {
LocalSurfaceId child_one_local_surface_id = allocator_.GenerateId();
SurfaceId child_one_surface_id(child_one_support->frame_sink_id(),
child_one_local_surface_id);
- child_one_support->SubmitCompositorFrame(child_one_local_surface_id,
- CompositorFrame());
std::unique_ptr<RenderPass> child_one_pass = RenderPass::Create();
child_one_pass->SetNew(pass_id, output_rect, damage_rect,
@@ -1152,8 +1141,6 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateSharedQuadStateProperties) {
LocalSurfaceId child_two_local_surface_id = allocator_.GenerateId();
SurfaceId child_two_surface_id(child_two_support->frame_sink_id(),
child_two_local_surface_id);
- child_two_support->SubmitCompositorFrame(child_two_local_surface_id,
- CompositorFrame());
std::unique_ptr<RenderPass> child_two_pass = RenderPass::Create();
child_two_pass->SetNew(pass_id, output_rect, damage_rect,
@@ -1208,9 +1195,9 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateSharedQuadStateProperties) {
<< iter.index();
}
- grandchild_support->EvictFrame();
- child_one_support->EvictFrame();
- child_two_support->EvictFrame();
+ grandchild_support->EvictCurrentSurface();
+ child_one_support->EvictCurrentSurface();
+ child_two_support->EvictCurrentSurface();
}
// This tests that when aggregating a frame with multiple render passes that we
@@ -1251,7 +1238,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateMultiplePassWithTransform) {
test::Pass(child_quads[1], arraysize(child_quads[1]),
child_pass_id[1])};
- CompositorFrame child_frame;
+ CompositorFrame child_frame = test::MakeEmptyCompositorFrame();
AddPasses(&child_frame.render_pass_list, gfx::Rect(SurfaceSize()),
child_passes, arraysize(child_passes));
@@ -1283,7 +1270,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateMultiplePassWithTransform) {
test::Pass(middle_quads, arraysize(middle_quads)),
};
- CompositorFrame middle_frame;
+ CompositorFrame middle_frame = test::MakeEmptyCompositorFrame();
AddPasses(&middle_frame.render_pass_list, gfx::Rect(SurfaceSize()),
middle_passes, arraysize(middle_passes));
@@ -1307,7 +1294,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateMultiplePassWithTransform) {
test::Pass(secondary_quads, arraysize(secondary_quads)),
test::Pass(root_quads, arraysize(root_quads))};
- CompositorFrame root_frame;
+ CompositorFrame root_frame = test::MakeEmptyCompositorFrame();
AddPasses(&root_frame.render_pass_list, gfx::Rect(SurfaceSize()), root_passes,
arraysize(root_passes));
@@ -1398,7 +1385,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateMultiplePassWithTransform) {
->shared_quad_state_list.ElementAt(1)
->clip_rect.ToString());
- middle_support->EvictFrame();
+ middle_support->EvictCurrentSurface();
}
// Tests that damage rects are aggregated correctly when surfaces change.
@@ -1411,7 +1398,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateDamageRect) {
test::Pass child_passes[] = {
test::Pass(child_quads, arraysize(child_quads), 1)};
- CompositorFrame child_frame;
+ CompositorFrame child_frame = test::MakeEmptyCompositorFrame();
AddPasses(&child_frame.render_pass_list, gfx::Rect(SurfaceSize()),
child_passes, arraysize(child_passes));
@@ -1433,7 +1420,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateDamageRect) {
// Parent surface is only used to test if the transform is applied correctly
// to the child surface's damage.
- CompositorFrame parent_surface_frame;
+ CompositorFrame parent_surface_frame = test::MakeEmptyCompositorFrame();
AddPasses(&parent_surface_frame.render_pass_list, gfx::Rect(SurfaceSize()),
parent_surface_passes, arraysize(parent_surface_passes));
@@ -1451,7 +1438,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateDamageRect) {
test::Pass(root_surface_quads, arraysize(root_surface_quads), 1),
test::Pass(root_render_pass_quads, arraysize(root_render_pass_quads), 2)};
- CompositorFrame root_frame;
+ CompositorFrame root_frame = test::MakeEmptyCompositorFrame();
AddPasses(&root_frame.render_pass_list, gfx::Rect(SurfaceSize()), root_passes,
arraysize(root_passes));
@@ -1477,7 +1464,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateDamageRect) {
aggregated_pass_list[1]->damage_rect.Contains(gfx::Rect(SurfaceSize())));
{
- CompositorFrame child_frame;
+ CompositorFrame child_frame = test::MakeEmptyCompositorFrame();
AddPasses(&child_frame.render_pass_list, gfx::Rect(SurfaceSize()),
child_passes, arraysize(child_passes));
@@ -1506,7 +1493,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateDamageRect) {
}
{
- CompositorFrame root_frame;
+ CompositorFrame root_frame = test::MakeEmptyCompositorFrame();
AddPasses(&root_frame.render_pass_list, gfx::Rect(SurfaceSize()),
root_passes, arraysize(root_passes));
@@ -1520,7 +1507,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateDamageRect) {
}
{
- CompositorFrame root_frame;
+ CompositorFrame root_frame = test::MakeEmptyCompositorFrame();
AddPasses(&root_frame.render_pass_list, gfx::Rect(SurfaceSize()),
root_passes, arraysize(root_passes));
@@ -1576,7 +1563,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateDamageRect) {
gfx::Rect(SurfaceSize())));
}
- parent_support->EvictFrame();
+ parent_support->EvictCurrentSurface();
}
// Check that damage is correctly calculated for surfaces.
@@ -1586,7 +1573,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, SwitchSurfaceDamage) {
test::Pass root_passes[] = {
test::Pass(root_render_pass_quads, arraysize(root_render_pass_quads), 2)};
- CompositorFrame root_frame;
+ CompositorFrame root_frame = test::MakeEmptyCompositorFrame();
AddPasses(&root_frame.render_pass_list, gfx::Rect(SurfaceSize()), root_passes,
arraysize(root_passes));
@@ -1619,7 +1606,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, SwitchSurfaceDamage) {
test::Pass root_passes[] = {test::Pass(
root_render_pass_quads, arraysize(root_render_pass_quads), 2)};
- CompositorFrame root_frame;
+ CompositorFrame root_frame = test::MakeEmptyCompositorFrame();
AddPasses(&root_frame.render_pass_list, gfx::Rect(SurfaceSize()),
root_passes, arraysize(root_passes));
@@ -1964,9 +1951,9 @@ void SubmitCompositorFrameWithResources(ResourceId* resource_ids,
SurfaceId child_id,
CompositorFrameSinkSupport* support,
SurfaceId surface_id) {
- CompositorFrame frame;
+ CompositorFrame frame = test::MakeEmptyCompositorFrame();
std::unique_ptr<RenderPass> pass = RenderPass::Create();
- pass->id = 1;
+ pass->SetNew(1, gfx::Rect(0, 0, 20, 20), gfx::Rect(), gfx::Transform());
SharedQuadState* sqs = pass->CreateAndAppendSharedQuadState();
sqs->opacity = 1.f;
if (child_id.is_valid()) {
@@ -2036,7 +2023,7 @@ TEST_F(SurfaceAggregatorWithResourcesTest, TakeResourcesOneSurface) {
EXPECT_THAT(returned_ids,
testing::WhenSorted(testing::ElementsAreArray(ids)));
- support->EvictFrame();
+ support->EvictCurrentSurface();
}
TEST_F(SurfaceAggregatorWithResourcesTest, TakeInvalidResources) {
@@ -2048,16 +2035,13 @@ TEST_F(SurfaceAggregatorWithResourcesTest, TakeInvalidResources) {
LocalSurfaceId local_surface_id(7u, base::UnguessableToken::Create());
SurfaceId surface_id(support->frame_sink_id(), local_surface_id);
- CompositorFrame frame;
- std::unique_ptr<RenderPass> pass = RenderPass::Create();
- pass->id = 1;
+ CompositorFrame frame = test::MakeCompositorFrame();
TransferableResource resource;
resource.id = 11;
// ResourceProvider is software but resource is not, so it should be
// ignored.
resource.is_software = false;
frame.resource_list.push_back(resource);
- frame.render_pass_list.push_back(std::move(pass));
support->SubmitCompositorFrame(local_surface_id, std::move(frame));
CompositorFrame returned_frame = aggregator_->Aggregate(surface_id);
@@ -2070,7 +2054,7 @@ TEST_F(SurfaceAggregatorWithResourcesTest, TakeInvalidResources) {
ASSERT_EQ(1u, client.returned_resources().size());
EXPECT_EQ(11u, client.returned_resources()[0].id);
- support->EvictFrame();
+ support->EvictCurrentSurface();
}
TEST_F(SurfaceAggregatorWithResourcesTest, TwoSurfaces) {
@@ -2116,8 +2100,8 @@ TEST_F(SurfaceAggregatorWithResourcesTest, TwoSurfaces) {
testing::WhenSorted(testing::ElementsAreArray(ids)));
EXPECT_EQ(3u, resource_provider_->num_resources());
- support1->EvictFrame();
- support2->EvictFrame();
+ support1->EvictCurrentSurface();
+ support2->EvictCurrentSurface();
}
// Ensure that aggregator completely ignores Surfaces that reference invalid
@@ -2177,9 +2161,9 @@ TEST_F(SurfaceAggregatorWithResourcesTest, InvalidChildSurface) {
EXPECT_EQ(3u, pass_list->back()->shared_quad_state_list.size());
EXPECT_EQ(9u, pass_list->back()->quad_list.size());
- root_support->EvictFrame();
- middle_support->EvictFrame();
- child_support->EvictFrame();
+ root_support->EvictCurrentSurface();
+ middle_support->EvictCurrentSurface();
+ child_support->EvictCurrentSurface();
}
TEST_F(SurfaceAggregatorWithResourcesTest, SecureOutputTexture) {
@@ -2209,7 +2193,7 @@ TEST_F(SurfaceAggregatorWithResourcesTest, SecureOutputTexture) {
{
std::unique_ptr<RenderPass> pass = RenderPass::Create();
- pass->id = 1;
+ pass->SetNew(1, gfx::Rect(0, 0, 20, 20), gfx::Rect(), gfx::Transform());
SharedQuadState* sqs = pass->CreateAndAppendSharedQuadState();
sqs->opacity = 1.f;
SurfaceDrawQuad* surface_quad =
@@ -2219,7 +2203,7 @@ TEST_F(SurfaceAggregatorWithResourcesTest, SecureOutputTexture) {
surface1_id, SurfaceDrawQuadType::PRIMARY, nullptr);
pass->copy_requests.push_back(CopyOutputRequest::CreateEmptyRequest());
- CompositorFrame frame;
+ CompositorFrame frame = test::MakeEmptyCompositorFrame();
frame.render_pass_list.push_back(std::move(pass));
support2->SubmitCompositorFrame(local_frame2_id, std::move(frame));
@@ -2248,8 +2232,8 @@ TEST_F(SurfaceAggregatorWithResourcesTest, SecureOutputTexture) {
// Output is insecure, so texture should be drawn.
EXPECT_EQ(DrawQuad::SOLID_COLOR, render_pass->quad_list.back()->material);
- support1->EvictFrame();
- support2->EvictFrame();
+ support1->EvictCurrentSurface();
+ support2->EvictCurrentSurface();
}
// Ensure that the render passes have correct color spaces.
diff --git a/chromium/cc/surfaces/surface_dependency_deadline.cc b/chromium/cc/surfaces/surface_dependency_deadline.cc
new file mode 100644
index 00000000000..7bdbefcc546
--- /dev/null
+++ b/chromium/cc/surfaces/surface_dependency_deadline.cc
@@ -0,0 +1,55 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/surfaces/surface_dependency_deadline.h"
+
+#include "cc/surfaces/surface_dependency_tracker.h"
+
+namespace cc {
+
+SurfaceDependencyDeadline::SurfaceDependencyDeadline(
+ SurfaceDependencyTracker* dependency_tracker,
+ BeginFrameSource* begin_frame_source)
+ : dependency_tracker_(dependency_tracker),
+ begin_frame_source_(begin_frame_source) {
+ DCHECK(begin_frame_source_);
+}
+
+SurfaceDependencyDeadline::~SurfaceDependencyDeadline() {
+ // The deadline must be canceled before destruction.
+ DCHECK(!number_of_frames_to_deadline_);
+}
+
+void SurfaceDependencyDeadline::Set(uint32_t number_of_frames_to_deadline) {
+ DCHECK_GT(number_of_frames_to_deadline, 0u);
+ DCHECK(!number_of_frames_to_deadline_);
+ number_of_frames_to_deadline_ = number_of_frames_to_deadline;
+ begin_frame_source_->AddObserver(this);
+}
+
+void SurfaceDependencyDeadline::Cancel() {
+ if (!number_of_frames_to_deadline_)
+ return;
+ begin_frame_source_->RemoveObserver(this);
+ number_of_frames_to_deadline_.reset();
+}
+
+// BeginFrameObserver implementation.
+void SurfaceDependencyDeadline::OnBeginFrame(const BeginFrameArgs& args) {
+ last_begin_frame_args_ = args;
+ if (--(*number_of_frames_to_deadline_) > 0)
+ return;
+
+ Cancel();
+ dependency_tracker_->OnDeadline();
+}
+
+const BeginFrameArgs& SurfaceDependencyDeadline::LastUsedBeginFrameArgs()
+ const {
+ return last_begin_frame_args_;
+}
+
+void SurfaceDependencyDeadline::OnBeginFrameSourcePausedChanged(bool paused) {}
+
+} // namespace cc
diff --git a/chromium/cc/surfaces/surface_dependency_deadline.h b/chromium/cc/surfaces/surface_dependency_deadline.h
new file mode 100644
index 00000000000..f226bd0985f
--- /dev/null
+++ b/chromium/cc/surfaces/surface_dependency_deadline.h
@@ -0,0 +1,44 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_SURFACES_SURFACE_DEPENDENCY_DEADLINE_H_
+#define CC_SURFACES_SURFACE_DEPENDENCY_DEADLINE_H_
+
+#include "cc/scheduler/begin_frame_source.h"
+
+namespace cc {
+
+class SurfaceDependencyTracker;
+
+class SurfaceDependencyDeadline : public BeginFrameObserver {
+ public:
+ SurfaceDependencyDeadline(SurfaceDependencyTracker* dependency_tracker,
+ BeginFrameSource* begin_frame_source);
+ ~SurfaceDependencyDeadline() override;
+
+ void Set(uint32_t number_of_frames_to_deadline);
+ void Cancel();
+
+ bool has_deadline() const {
+ return number_of_frames_to_deadline_.has_value();
+ }
+
+ // BeginFrameObserver implementation.
+ void OnBeginFrame(const BeginFrameArgs& args) override;
+ const BeginFrameArgs& LastUsedBeginFrameArgs() const override;
+ void OnBeginFrameSourcePausedChanged(bool paused) override;
+
+ private:
+ SurfaceDependencyTracker* const dependency_tracker_;
+ BeginFrameSource* begin_frame_source_ = nullptr;
+ base::Optional<uint32_t> number_of_frames_to_deadline_;
+
+ BeginFrameArgs last_begin_frame_args_;
+
+ DISALLOW_COPY_AND_ASSIGN(SurfaceDependencyDeadline);
+};
+
+} // namespace cc
+
+#endif // CC_SURFACES_SURFACE_DEPENDENCY_DEADLINE_H_
diff --git a/chromium/cc/surfaces/surface_dependency_tracker.cc b/chromium/cc/surfaces/surface_dependency_tracker.cc
index 89eaf14fe0e..8540aab5236 100644
--- a/chromium/cc/surfaces/surface_dependency_tracker.cc
+++ b/chromium/cc/surfaces/surface_dependency_tracker.cc
@@ -17,21 +17,10 @@ constexpr uint32_t kMaxBeginFrameCount = 4;
SurfaceDependencyTracker::SurfaceDependencyTracker(
SurfaceManager* surface_manager,
BeginFrameSource* begin_frame_source)
- : surface_manager_(surface_manager),
- begin_frame_source_(begin_frame_source) {
- surface_manager_->AddObserver(this);
- begin_frame_source_->AddObserver(this);
-}
+ : surface_manager_(surface_manager), deadline_(this, begin_frame_source) {}
SurfaceDependencyTracker::~SurfaceDependencyTracker() {
- surface_manager_->RemoveObserver(this);
- begin_frame_source_->RemoveObserver(this);
- for (const SurfaceId& surface_id : observed_surfaces_by_id_) {
- Surface* observed_surface = surface_manager_->GetSurfaceForId(surface_id);
- DCHECK(observed_surface);
- observed_surface->RemoveObserver(this);
- }
- observed_surfaces_by_id_.clear();
+ deadline_.Cancel();
}
void SurfaceDependencyTracker::RequestSurfaceResolution(Surface* surface) {
@@ -49,72 +38,47 @@ void SurfaceDependencyTracker::RequestSurfaceResolution(Surface* surface) {
// Referenced surface IDs that aren't currently known to the surface manager
// or do not have an active CompsotiorFrame block this frame.
- for (const SurfaceId& surface_id : pending_frame.metadata.embedded_surfaces) {
+ for (const SurfaceId& surface_id :
+ pending_frame.metadata.activation_dependencies) {
Surface* surface_dependency = surface_manager_->GetSurfaceForId(surface_id);
if (!surface_dependency || !surface_dependency->HasActiveFrame())
blocked_surfaces_from_dependency_[surface_id].insert(
surface->surface_id());
}
- if (!observed_surfaces_by_id_.count(surface->surface_id())) {
- surface->AddObserver(this);
- observed_surfaces_by_id_.insert(surface->surface_id());
- }
+ blocked_surfaces_by_id_.insert(surface->surface_id());
- if (needs_deadline && !frames_since_deadline_set_)
- frames_since_deadline_set_ = 0;
+ if (needs_deadline && !deadline_.has_deadline())
+ deadline_.Set(kMaxBeginFrameCount);
}
-void SurfaceDependencyTracker::OnBeginFrame(const BeginFrameArgs& args) {
- // If no deadline is set then we have nothing to do.
- if (!frames_since_deadline_set_)
- return;
-
- // TODO(fsamuel, kylechar): We have a single global deadline here. We should
- // scope deadlines to surface subtrees. We cannot do that until
- // SurfaceReferences have been fully implemented
- // (see https://crbug.com/689719).
- last_begin_frame_args_ = args;
- // Nothing to do if we haven't hit a deadline yet.
- if (++(*frames_since_deadline_set_) != kMaxBeginFrameCount)
- return;
+void SurfaceDependencyTracker::OnSurfaceActivated(Surface* surface) {
+ blocked_surfaces_by_id_.erase(surface->surface_id());
+ NotifySurfaceIdAvailable(surface->surface_id());
+}
- late_surfaces_by_id_.clear();
+void SurfaceDependencyTracker::OnSurfaceDependenciesChanged(
+ Surface* surface,
+ const base::flat_set<SurfaceId>& added_dependencies,
+ const base::flat_set<SurfaceId>& removed_dependencies) {
+ // Update the |blocked_surfaces_from_dependency_| map with the changes in
+ // dependencies.
+ for (const SurfaceId& surface_id : added_dependencies)
+ blocked_surfaces_from_dependency_[surface_id].insert(surface->surface_id());
- // Activate all surfaces that respect the deadline.
- // Copy the set of blocked surfaces here because that set can mutate as we
- // activate CompositorFrames: an activation can trigger further activations
- // which will remove elements from |observed_surfaces_by_id_|. This
- // invalidates the iterator.
- base::flat_set<SurfaceId> blocked_surfaces_by_id(observed_surfaces_by_id_);
- for (const SurfaceId& surface_id : blocked_surfaces_by_id) {
- Surface* blocked_surface = surface_manager_->GetSurfaceForId(surface_id);
- if (!blocked_surface) {
- // A blocked surface may have been garbage collected during dependency
- // resolution.
- DCHECK(!observed_surfaces_by_id_.count(surface_id));
- continue;
- }
- // Clear all tracked blockers for |blocked_surface|.
- for (const SurfaceId& blocking_surface_id :
- blocked_surface->blocking_surfaces()) {
- // If we are not activating this blocker now, then it's late.
- if (!blocked_surfaces_by_id.count(blocking_surface_id))
- late_surfaces_by_id_.insert(blocking_surface_id);
- blocked_surfaces_from_dependency_[blocking_surface_id].erase(surface_id);
- }
- blocked_surface->ActivatePendingFrameForDeadline();
+ for (const SurfaceId& surface_id : removed_dependencies) {
+ auto it = blocked_surfaces_from_dependency_.find(surface_id);
+ it->second.erase(surface->surface_id());
+ if (it->second.empty())
+ blocked_surfaces_from_dependency_.erase(it);
}
- frames_since_deadline_set_.reset();
-}
-
-const BeginFrameArgs& SurfaceDependencyTracker::LastUsedBeginFrameArgs() const {
- return last_begin_frame_args_;
+ // If there are no more dependencies to resolve then we don't need to have a
+ // deadline.
+ if (blocked_surfaces_from_dependency_.empty())
+ deadline_.Cancel();
}
-void SurfaceDependencyTracker::OnBeginFrameSourcePausedChanged(bool paused) {}
-
void SurfaceDependencyTracker::OnSurfaceDiscarded(Surface* surface) {
// If the surface being destroyed doesn't have a pending frame then we have
// nothing to do here.
@@ -123,9 +87,10 @@ void SurfaceDependencyTracker::OnSurfaceDiscarded(Surface* surface) {
const CompositorFrame& pending_frame = surface->GetPendingFrame();
- DCHECK(!pending_frame.metadata.embedded_surfaces.empty());
+ DCHECK(!pending_frame.metadata.activation_dependencies.empty());
- for (const SurfaceId& surface_id : pending_frame.metadata.embedded_surfaces) {
+ for (const SurfaceId& surface_id :
+ pending_frame.metadata.activation_dependencies) {
auto it = blocked_surfaces_from_dependency_.find(surface_id);
if (it == blocked_surfaces_from_dependency_.end())
continue;
@@ -141,57 +106,44 @@ void SurfaceDependencyTracker::OnSurfaceDiscarded(Surface* surface) {
}
if (blocked_surfaces_from_dependency_.empty())
- frames_since_deadline_set_.reset();
+ deadline_.Cancel();
- observed_surfaces_by_id_.erase(surface->surface_id());
- surface->RemoveObserver(this);
+ blocked_surfaces_by_id_.erase(surface->surface_id());
// Pretend that the discarded surface's SurfaceId is now available to unblock
// dependencies because we now know the surface will never activate.
NotifySurfaceIdAvailable(surface->surface_id());
}
-void SurfaceDependencyTracker::OnSurfaceActivated(Surface* surface) {
- surface->RemoveObserver(this);
- observed_surfaces_by_id_.erase(surface->surface_id());
- NotifySurfaceIdAvailable(surface->surface_id());
-}
-
-void SurfaceDependencyTracker::OnSurfaceDependenciesChanged(
- Surface* surface,
- const SurfaceDependencies& added_dependencies,
- const SurfaceDependencies& removed_dependencies) {
- // Update the |blocked_surfaces_from_dependency_| map with the changes in
- // dependencies.
- for (const SurfaceId& surface_id : added_dependencies)
- blocked_surfaces_from_dependency_[surface_id].insert(surface->surface_id());
+void SurfaceDependencyTracker::OnDeadline() {
+ late_surfaces_by_id_.clear();
- for (const SurfaceId& surface_id : removed_dependencies) {
- auto it = blocked_surfaces_from_dependency_.find(surface_id);
- it->second.erase(surface->surface_id());
- if (it->second.empty())
- blocked_surfaces_from_dependency_.erase(it);
+ // Activate all surfaces that respect the deadline.
+ // Copy the set of blocked surfaces here because that set can mutate as we
+ // activate CompositorFrames: an activation can trigger further activations
+ // which will remove elements from |blocked_surfaces_by_id_|. This
+ // invalidates the iterator.
+ base::flat_set<SurfaceId> blocked_surfaces_by_id(blocked_surfaces_by_id_);
+ for (const SurfaceId& surface_id : blocked_surfaces_by_id) {
+ Surface* blocked_surface = surface_manager_->GetSurfaceForId(surface_id);
+ if (!blocked_surface) {
+ // A blocked surface may have been garbage collected during dependency
+ // resolution.
+ DCHECK(!blocked_surfaces_by_id_.count(surface_id));
+ continue;
+ }
+ // Clear all tracked blockers for |blocked_surface|.
+ for (const SurfaceId& blocking_surface_id :
+ blocked_surface->blocking_surfaces()) {
+ // If we are not activating this blocker now, then it's late.
+ if (!blocked_surfaces_by_id.count(blocking_surface_id))
+ late_surfaces_by_id_.insert(blocking_surface_id);
+ blocked_surfaces_from_dependency_[blocking_surface_id].erase(surface_id);
+ }
+ blocked_surface->ActivatePendingFrameForDeadline();
}
-
- // If there are no more dependencies to resolve then we don't need to have a
- // deadline.
- if (blocked_surfaces_from_dependency_.empty())
- frames_since_deadline_set_.reset();
}
-// SurfaceObserver implementation:
-void SurfaceDependencyTracker::OnSurfaceCreated(
- const SurfaceInfo& surface_info) {
- // This is called when a Surface has an activated frame for the first time.
- // SurfaceDependencyTracker only observes Surfaces that contain pending
- // frames. SurfaceDependencyTracker becomes aware of CompositorFrames that
- // activate immediately go through here.
- NotifySurfaceIdAvailable(surface_info.id());
-}
-
-void SurfaceDependencyTracker::OnSurfaceDamaged(const SurfaceId& surface_id,
- bool* changed) {}
-
void SurfaceDependencyTracker::NotifySurfaceIdAvailable(
const SurfaceId& surface_id) {
auto it = blocked_surfaces_from_dependency_.find(surface_id);
@@ -204,7 +156,7 @@ void SurfaceDependencyTracker::NotifySurfaceIdAvailable(
// If there are no more blockers in the system, then we no longer need to
// have a deadline.
if (blocked_surfaces_from_dependency_.empty())
- frames_since_deadline_set_.reset();
+ deadline_.Cancel();
// Tell each surface about the availability of its blocker.
for (const SurfaceId& blocked_surface_by_id : blocked_surfaces_by_id) {
@@ -213,7 +165,7 @@ void SurfaceDependencyTracker::NotifySurfaceIdAvailable(
if (!blocked_surface) {
// A blocked surface may have been garbage collected during dependency
// resolution.
- DCHECK(!observed_surfaces_by_id_.count(blocked_surface_by_id));
+ DCHECK(!blocked_surfaces_by_id_.count(blocked_surface_by_id));
continue;
}
blocked_surface->NotifySurfaceIdAvailable(surface_id);
diff --git a/chromium/cc/surfaces/surface_dependency_tracker.h b/chromium/cc/surfaces/surface_dependency_tracker.h
index bdb8717fd06..45b543cd6fe 100644
--- a/chromium/cc/surfaces/surface_dependency_tracker.h
+++ b/chromium/cc/surfaces/surface_dependency_tracker.h
@@ -5,14 +5,13 @@
#ifndef CC_SURFACES_SURFACE_DEPENDENCY_TRACKER_H_
#define CC_SURFACES_SURFACE_DEPENDENCY_TRACKER_H_
-#include "cc/scheduler/begin_frame_source.h"
-#include "cc/surfaces/pending_frame_observer.h"
#include "cc/surfaces/surface.h"
-#include "cc/surfaces/surface_observer.h"
+#include "cc/surfaces/surface_dependency_deadline.h"
#include "cc/surfaces/surfaces_export.h"
namespace cc {
+class BeginFrameSource;
class SurfaceManager;
// SurfaceDependencyTracker tracks unresolved dependencies blocking
@@ -30,36 +29,26 @@ class SurfaceManager;
// TODO(fsamuel): Deadlines should not be global. They should be scoped to a
// surface subtree. However, that will not be possible until SurfaceReference
// work is complete.
-class CC_SURFACES_EXPORT SurfaceDependencyTracker : public BeginFrameObserver,
- public PendingFrameObserver,
- public SurfaceObserver {
+class CC_SURFACES_EXPORT SurfaceDependencyTracker {
public:
SurfaceDependencyTracker(SurfaceManager* surface_manager,
BeginFrameSource* begin_frame_source);
- ~SurfaceDependencyTracker() override;
+ ~SurfaceDependencyTracker();
// Called when |surface| has a pending CompositorFrame and it wishes to be
// informed when that surface's dependencies are resolved.
void RequestSurfaceResolution(Surface* surface);
- bool has_deadline() const { return frames_since_deadline_set_.has_value(); }
+ bool has_deadline() const { return deadline_.has_deadline(); }
- // BeginFrameObserver implementation.
- void OnBeginFrame(const BeginFrameArgs& args) override;
- const BeginFrameArgs& LastUsedBeginFrameArgs() const override;
- void OnBeginFrameSourcePausedChanged(bool paused) override;
+ void OnDeadline();
- // PendingFrameObserver implementation:
- void OnSurfaceActivated(Surface* surface) override;
+ void OnSurfaceActivated(Surface* surface);
void OnSurfaceDependenciesChanged(
Surface* surface,
- const SurfaceDependencies& added_dependencies,
- const SurfaceDependencies& removed_dependencies) override;
- void OnSurfaceDiscarded(Surface* surface) override;
-
- // SurfaceObserver implementation:
- void OnSurfaceCreated(const SurfaceInfo& surface_info) override;
- void OnSurfaceDamaged(const SurfaceId& surface_id, bool* changed) override;
+ const base::flat_set<SurfaceId>& added_dependencies,
+ const base::flat_set<SurfaceId>& removed_dependencies);
+ void OnSurfaceDiscarded(Surface* surface);
private:
// Informs all Surfaces with pending frames blocked on the provided
@@ -69,23 +58,16 @@ class CC_SURFACES_EXPORT SurfaceDependencyTracker : public BeginFrameObserver,
SurfaceManager* const surface_manager_;
- // The last begin frame args generated by the begin frame source.
- BeginFrameArgs last_begin_frame_args_;
-
- // The BeginFrameSource used to set deadlines.
- BeginFrameSource* const begin_frame_source_;
-
- // The number of BeginFrames observed since a deadline was set. If
- // base::nullopt_t then a deadline is not set.
- base::Optional<uint32_t> frames_since_deadline_set_;
+ // This object tracks the deadline when all pending CompositorFrames in the
+ // system will be activated.
+ SurfaceDependencyDeadline deadline_;
// A map from a SurfaceId to the set of Surfaces blocked on that SurfaceId.
std::unordered_map<SurfaceId, base::flat_set<SurfaceId>, SurfaceIdHash>
blocked_surfaces_from_dependency_;
- // The set of SurfaceIds corresponding to observed Surfaces that have
- // blockers.
- base::flat_set<SurfaceId> observed_surfaces_by_id_;
+ // The set of SurfaceIds corresponding that are known to have blockers.
+ base::flat_set<SurfaceId> blocked_surfaces_by_id_;
// The set of SurfaceIds to which corresponding CompositorFrames have not
// arrived by the time their deadline fired.
diff --git a/chromium/cc/surfaces/surface_factory.cc b/chromium/cc/surfaces/surface_factory.cc
deleted file mode 100644
index f6a6e0ec0f2..00000000000
--- a/chromium/cc/surfaces/surface_factory.cc
+++ /dev/null
@@ -1,151 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/surfaces/surface_factory.h"
-
-#include <utility>
-
-#include "base/memory/ptr_util.h"
-#include "base/trace_event/trace_event.h"
-#include "cc/output/compositor_frame.h"
-#include "cc/output/copy_output_request.h"
-#include "cc/surfaces/surface.h"
-#include "cc/surfaces/surface_factory_client.h"
-#include "cc/surfaces/surface_info.h"
-#include "cc/surfaces/surface_manager.h"
-#include "ui/gfx/geometry/size.h"
-
-namespace cc {
-SurfaceFactory::SurfaceFactory(const FrameSinkId& frame_sink_id,
- SurfaceManager* manager,
- SurfaceFactoryClient* client)
- : frame_sink_id_(frame_sink_id),
- manager_(manager),
- client_(client),
- holder_(client),
- needs_sync_points_(true),
- weak_factory_(this) {}
-
-SurfaceFactory::~SurfaceFactory() {
- // This is to prevent troubles when a factory that resides in a client is
- // being destroyed. In such cases, the factory might attempt to return
- // resources to the client while it's in the middle of destruction and this
- // could cause a crash or some unexpected behaviour.
- DCHECK(!current_surface_) << "Please call EvictSurface before destruction";
-}
-
-void SurfaceFactory::EvictSurface() {
- if (!current_surface_)
- return;
- Destroy(std::move(current_surface_));
-}
-
-void SurfaceFactory::SubmitCompositorFrame(
- const LocalSurfaceId& local_surface_id,
- CompositorFrame frame,
- const DrawCallback& callback) {
- TRACE_EVENT0("cc", "SurfaceFactory::SubmitCompositorFrame");
- DCHECK(local_surface_id.is_valid());
- std::unique_ptr<Surface> surface;
- bool create_new_surface =
- (!current_surface_ ||
- local_surface_id != current_surface_->surface_id().local_surface_id());
- if (!create_new_surface) {
- surface = std::move(current_surface_);
- } else {
- surface = Create(local_surface_id);
- }
- surface->QueueFrame(std::move(frame), callback);
-
- if (!manager_->SurfaceModified(SurfaceId(frame_sink_id_, local_surface_id))) {
- TRACE_EVENT_INSTANT0("cc", "Damage not visible.", TRACE_EVENT_SCOPE_THREAD);
- surface->RunDrawCallbacks();
- }
- if (current_surface_ && create_new_surface) {
- surface->SetPreviousFrameSurface(current_surface_.get());
- Destroy(std::move(current_surface_));
- }
- current_surface_ = std::move(surface);
-}
-
-void SurfaceFactory::RequestCopyOfSurface(
- std::unique_ptr<CopyOutputRequest> copy_request) {
- if (!current_surface_) {
- copy_request->SendEmptyResult();
- return;
- }
- DCHECK(current_surface_->factory().get() == this);
- current_surface_->RequestCopyOfOutput(std::move(copy_request));
- manager_->SurfaceModified(current_surface_->surface_id());
-}
-
-void SurfaceFactory::ClearSurface() {
- if (!current_surface_)
- return;
- current_surface_->EvictFrame();
- manager_->SurfaceModified(current_surface_->surface_id());
-}
-
-void SurfaceFactory::WillDrawSurface(const LocalSurfaceId& id,
- const gfx::Rect& damage_rect) {
- client_->WillDrawSurface(id, damage_rect);
-}
-
-void SurfaceFactory::ReceiveFromChild(
- const TransferableResourceArray& resources) {
- holder_.ReceiveFromChild(resources);
-}
-
-void SurfaceFactory::RefResources(const TransferableResourceArray& resources) {
- holder_.RefResources(resources);
-}
-
-void SurfaceFactory::UnrefResources(const ReturnedResourceArray& resources) {
- holder_.UnrefResources(resources);
-}
-
-void SurfaceFactory::OnSurfaceActivated(Surface* surface) {
- DCHECK(surface->HasActiveFrame());
- if (!seen_first_frame_activation_) {
- seen_first_frame_activation_ = true;
-
- const CompositorFrame& frame = surface->GetActiveFrame();
- // CompositorFrames might not be populated with a RenderPass in unit tests.
- gfx::Size frame_size;
- if (!frame.render_pass_list.empty())
- frame_size = frame.render_pass_list.back()->output_rect.size();
-
- // SurfaceCreated only applies for the first Surface activation. Thus,
- // SurfaceFactory stops observing new activations after the first one.
- manager_->SurfaceCreated(SurfaceInfo(
- surface->surface_id(), frame.metadata.device_scale_factor, frame_size));
- }
- // Fire SurfaceCreated first so that a temporary reference is added before it
- // is potentially transformed into a real reference by the client.
- client_->ReferencedSurfacesChanged(surface->surface_id().local_surface_id(),
- surface->active_referenced_surfaces());
-}
-
-void SurfaceFactory::OnSurfaceDependenciesChanged(
- Surface* surface,
- const SurfaceDependencies& added_dependencies,
- const SurfaceDependencies& removed_dependencies) {}
-
-void SurfaceFactory::OnSurfaceDiscarded(Surface* surface) {}
-
-std::unique_ptr<Surface> SurfaceFactory::Create(
- const LocalSurfaceId& local_surface_id) {
- seen_first_frame_activation_ = false;
- std::unique_ptr<Surface> surface =
- manager_->CreateSurface(weak_factory_.GetWeakPtr(), local_surface_id);
- surface->AddObserver(this);
- return surface;
-}
-
-void SurfaceFactory::Destroy(std::unique_ptr<Surface> surface) {
- surface->RemoveObserver(this);
- manager_->DestroySurface(std::move(surface));
-}
-
-} // namespace cc
diff --git a/chromium/cc/surfaces/surface_factory.h b/chromium/cc/surfaces/surface_factory.h
deleted file mode 100644
index 29b3e488ab4..00000000000
--- a/chromium/cc/surfaces/surface_factory.h
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_SURFACES_SURFACE_FACTORY_H_
-#define CC_SURFACES_SURFACE_FACTORY_H_
-
-#include <memory>
-#include <set>
-
-#include "base/callback_forward.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/observer_list.h"
-#include "cc/output/compositor_frame.h"
-#include "cc/surfaces/pending_frame_observer.h"
-#include "cc/surfaces/surface_id.h"
-#include "cc/surfaces/surface_resource_holder.h"
-#include "cc/surfaces/surface_sequence.h"
-#include "cc/surfaces/surfaces_export.h"
-
-namespace cc {
-class CopyOutputRequest;
-class Surface;
-class SurfaceFactoryClient;
-class SurfaceManager;
-
-// This class is used for creating surfaces and submitting compositor frames to
-// them. Surfaces are created lazily each time SubmitCompositorFrame is
-// called with a local frame id that is different from the last call. Only one
-// surface is owned by this class at a time, and upon constructing a new surface
-// the old one will be destructed. Resources submitted to surfaces created by a
-// particular factory will be returned to that factory's client when they are no
-// longer being used. This is the only class most users of surfaces will need to
-// directly interact with.
-class CC_SURFACES_EXPORT SurfaceFactory : public PendingFrameObserver {
- public:
- using DrawCallback = base::Callback<void()>;
-
- SurfaceFactory(const FrameSinkId& frame_sink_id,
- SurfaceManager* manager,
- SurfaceFactoryClient* client);
- ~SurfaceFactory() override;
-
- const FrameSinkId& frame_sink_id() const { return frame_sink_id_; }
-
- // Destroys the current surface. You need to call this method before the
- // factory is destroyed, or when you would like to get rid of the surface as
- // soon as possible (otherwise, the next time you call SubmitCompositorFrame
- // the old surface will be dealt with).
- void EvictSurface();
-
- // Submits the frame to the current surface being managed by the factory if
- // the local frame ids match, or creates a new surface with the given local
- // frame id, destroys the old one, and submits the frame to this new surface.
- // The frame can contain references to any surface, regardless of which
- // factory owns it. The callback is called the first time this frame is used
- // to draw, or if the frame is discarded.
- void SubmitCompositorFrame(const LocalSurfaceId& local_surface_id,
- CompositorFrame frame,
- const DrawCallback& callback);
- void RequestCopyOfSurface(std::unique_ptr<CopyOutputRequest> copy_request);
-
- // Evicts the current frame on the surface. All the resources
- // will be released and Surface::HasFrame will return false.
- void ClearSurface();
-
- void WillDrawSurface(const LocalSurfaceId& id, const gfx::Rect& damage_rect);
-
- SurfaceFactoryClient* client() { return client_; }
-
- void ReceiveFromChild(const TransferableResourceArray& resources);
- void RefResources(const TransferableResourceArray& resources);
- void UnrefResources(const ReturnedResourceArray& resources);
-
- SurfaceManager* manager() { return manager_; }
-
- Surface* current_surface_for_testing() { return current_surface_.get(); }
-
- // This can be set to false if resources from this SurfaceFactory don't need
- // to have sync points set on them when returned from the Display, for
- // example if the Display shares a context with the creator.
- bool needs_sync_points() const { return needs_sync_points_; }
- void set_needs_sync_points(bool needs) { needs_sync_points_ = needs; }
-
- private:
- // PendingFrameObserver implementation.
- void OnSurfaceActivated(Surface* surface) override;
- void OnSurfaceDependenciesChanged(
- Surface* surface,
- const SurfaceDependencies& added_dependencies,
- const SurfaceDependencies& removed_dependencies) override;
- void OnSurfaceDiscarded(Surface* surface) override;
-
- std::unique_ptr<Surface> Create(const LocalSurfaceId& local_surface_id);
- void Destroy(std::unique_ptr<Surface> surface);
-
- const FrameSinkId frame_sink_id_;
- SurfaceManager* manager_;
- SurfaceFactoryClient* client_;
- SurfaceResourceHolder holder_;
- bool needs_sync_points_;
- bool seen_first_frame_activation_ = false;
- std::unique_ptr<Surface> current_surface_;
- base::WeakPtrFactory<SurfaceFactory> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(SurfaceFactory);
-};
-
-} // namespace cc
-
-#endif // CC_SURFACES_SURFACE_FACTORY_H_
diff --git a/chromium/cc/surfaces/surface_factory_client.h b/chromium/cc/surfaces/surface_factory_client.h
deleted file mode 100644
index 57ecfed1104..00000000000
--- a/chromium/cc/surfaces/surface_factory_client.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_SURFACES_SURFACE_FACTORY_CLIENT_H_
-#define CC_SURFACES_SURFACE_FACTORY_CLIENT_H_
-
-#include "cc/resources/returned_resource.h"
-#include "cc/surfaces/local_surface_id.h"
-#include "cc/surfaces/surfaces_export.h"
-#include "ui/gfx/geometry/rect.h"
-
-namespace cc {
-
-class BeginFrameSource;
-class SurfaceId;
-
-class CC_SURFACES_EXPORT SurfaceFactoryClient {
- public:
- virtual ~SurfaceFactoryClient() {}
-
- virtual void ReferencedSurfacesChanged(
- const LocalSurfaceId& local_surface_id,
- const std::vector<SurfaceId>* active_referenced_surfaces) {}
-
- virtual void ReturnResources(const ReturnedResourceArray& resources) = 0;
-
- virtual void WillDrawSurface(const LocalSurfaceId& local_surface_id,
- const gfx::Rect& damage_rect) {}
-
- // This allows the SurfaceFactory to pass a BeginFrameSource to use.
- virtual void SetBeginFrameSource(BeginFrameSource* begin_frame_source) = 0;
-};
-
-} // namespace cc
-
-#endif // CC_SURFACES_SURFACE_FACTORY_CLIENT_H_
diff --git a/chromium/cc/surfaces/surface_factory_unittest.cc b/chromium/cc/surfaces/surface_factory_unittest.cc
deleted file mode 100644
index 0e445dd8caf..00000000000
--- a/chromium/cc/surfaces/surface_factory_unittest.cc
+++ /dev/null
@@ -1,768 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/surfaces/surface_factory.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <utility>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/macros.h"
-#include "cc/output/compositor_frame.h"
-#include "cc/output/copy_output_request.h"
-#include "cc/output/copy_output_result.h"
-#include "cc/resources/resource_provider.h"
-#include "cc/surfaces/surface.h"
-#include "cc/surfaces/surface_factory_client.h"
-#include "cc/surfaces/surface_info.h"
-#include "cc/surfaces/surface_manager.h"
-#include "cc/test/scheduler_test_common.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/geometry/size.h"
-
-namespace cc {
-namespace {
-
-static constexpr FrameSinkId kArbitraryFrameSinkId(1, 1);
-static constexpr FrameSinkId kAnotherArbitraryFrameSinkId(2, 2);
-static const base::UnguessableToken kArbitraryToken =
- base::UnguessableToken::Create();
-static auto kArbitrarySourceId1 =
- base::UnguessableToken::Deserialize(0xdead, 0xbeef);
-static auto kArbitrarySourceId2 =
- base::UnguessableToken::Deserialize(0xdead, 0xbee0);
-
-class TestSurfaceFactoryClient : public SurfaceFactoryClient {
- public:
- TestSurfaceFactoryClient() : begin_frame_source_(nullptr) {}
- ~TestSurfaceFactoryClient() override {}
-
- void ReturnResources(const ReturnedResourceArray& resources) override {
- returned_resources_.insert(
- returned_resources_.end(), resources.begin(), resources.end());
- }
-
- void SetBeginFrameSource(BeginFrameSource* begin_frame_source) override {
- begin_frame_source_ = begin_frame_source;
- }
-
- const ReturnedResourceArray& returned_resources() const {
- return returned_resources_;
- }
-
- void clear_returned_resources() { returned_resources_.clear(); }
-
- BeginFrameSource* begin_frame_source() const { return begin_frame_source_; }
-
- private:
- ReturnedResourceArray returned_resources_;
- BeginFrameSource* begin_frame_source_;
-
- DISALLOW_COPY_AND_ASSIGN(TestSurfaceFactoryClient);
-};
-
-gpu::SyncToken GenTestSyncToken(int id) {
- gpu::SyncToken token;
- token.Set(gpu::CommandBufferNamespace::GPU_IO, 0,
- gpu::CommandBufferId::FromUnsafeValue(id), 1);
- return token;
-}
-
-class SurfaceFactoryTest : public testing::Test, public SurfaceObserver {
- public:
- SurfaceFactoryTest()
- : factory_(
- new SurfaceFactory(kArbitraryFrameSinkId, &manager_, &client_)),
- local_surface_id_(3, kArbitraryToken),
- frame_sync_token_(GenTestSyncToken(4)),
- consumer_sync_token_(GenTestSyncToken(5)) {
- manager_.AddObserver(this);
- }
-
- const SurfaceId& last_created_surface_id() const {
- return last_created_surface_id_;
- }
-
- // SurfaceObserver implementation.
- void OnSurfaceCreated(const SurfaceInfo& surface_info) override {
- EXPECT_EQ(kArbitraryFrameSinkId, surface_info.id().frame_sink_id());
- last_created_surface_id_ = surface_info.id();
- last_surface_info_ = surface_info;
- }
-
- void OnSurfaceDamaged(const SurfaceId& id, bool* changed) override {
- *changed = true;
- }
-
- ~SurfaceFactoryTest() override {
- manager_.RemoveObserver(this);
- factory_->EvictSurface();
- }
-
- void SubmitCompositorFrameWithResources(ResourceId* resource_ids,
- size_t num_resource_ids) {
- CompositorFrame frame;
- for (size_t i = 0u; i < num_resource_ids; ++i) {
- TransferableResource resource;
- resource.id = resource_ids[i];
- resource.mailbox_holder.texture_target = GL_TEXTURE_2D;
- resource.mailbox_holder.sync_token = frame_sync_token_;
- frame.resource_list.push_back(resource);
- }
- factory_->SubmitCompositorFrame(local_surface_id_, std::move(frame),
- SurfaceFactory::DrawCallback());
- EXPECT_EQ(last_created_surface_id_.local_surface_id(), local_surface_id_);
- }
-
- void UnrefResources(ResourceId* ids_to_unref,
- int* counts_to_unref,
- size_t num_ids_to_unref) {
- ReturnedResourceArray unref_array;
- for (size_t i = 0; i < num_ids_to_unref; ++i) {
- ReturnedResource resource;
- resource.sync_token = consumer_sync_token_;
- resource.id = ids_to_unref[i];
- resource.count = counts_to_unref[i];
- unref_array.push_back(resource);
- }
- factory_->UnrefResources(unref_array);
- }
-
- void CheckReturnedResourcesMatchExpected(ResourceId* expected_returned_ids,
- int* expected_returned_counts,
- size_t expected_resources,
- gpu::SyncToken expected_sync_token) {
- const ReturnedResourceArray& actual_resources =
- client_.returned_resources();
- ASSERT_EQ(expected_resources, actual_resources.size());
- for (size_t i = 0; i < expected_resources; ++i) {
- ReturnedResource resource = actual_resources[i];
- EXPECT_EQ(expected_sync_token, resource.sync_token);
- EXPECT_EQ(expected_returned_ids[i], resource.id);
- EXPECT_EQ(expected_returned_counts[i], resource.count);
- }
- client_.clear_returned_resources();
- }
-
- void RefCurrentFrameResources() {
- Surface* surface = manager_.GetSurfaceForId(
- SurfaceId(factory_->frame_sink_id(), local_surface_id_));
- factory_->RefResources(surface->GetActiveFrame().resource_list);
- }
-
- protected:
- SurfaceManager manager_;
- TestSurfaceFactoryClient client_;
- std::unique_ptr<SurfaceFactory> factory_;
- LocalSurfaceId local_surface_id_;
- SurfaceId last_created_surface_id_;
- SurfaceInfo last_surface_info_;
-
- // This is the sync token submitted with the frame. It should never be
- // returned to the client.
- const gpu::SyncToken frame_sync_token_;
-
- // This is the sync token returned by the consumer. It should always be
- // returned to the client.
- const gpu::SyncToken consumer_sync_token_;
-};
-
-// Tests submitting a frame with resources followed by one with no resources
-// with no resource provider action in between.
-TEST_F(SurfaceFactoryTest, ResourceLifetimeSimple) {
- ResourceId first_frame_ids[] = {1, 2, 3};
- SubmitCompositorFrameWithResources(first_frame_ids,
- arraysize(first_frame_ids));
-
- // All of the resources submitted in the first frame are still in use at this
- // time by virtue of being in the pending frame, so none can be returned to
- // the client yet.
- EXPECT_EQ(0u, client_.returned_resources().size());
- client_.clear_returned_resources();
-
- // The second frame references no resources of first frame and thus should
- // make all resources of first frame available to be returned.
- SubmitCompositorFrameWithResources(NULL, 0);
-
- ResourceId expected_returned_ids[] = {1, 2, 3};
- int expected_returned_counts[] = {1, 1, 1};
- // Resources were never consumed so no sync token should be set.
- CheckReturnedResourcesMatchExpected(
- expected_returned_ids, expected_returned_counts,
- arraysize(expected_returned_counts), gpu::SyncToken());
-
- ResourceId third_frame_ids[] = {4, 5, 6};
- SubmitCompositorFrameWithResources(third_frame_ids,
- arraysize(third_frame_ids));
-
- // All of the resources submitted in the third frame are still in use at this
- // time by virtue of being in the pending frame, so none can be returned to
- // the client yet.
- EXPECT_EQ(0u, client_.returned_resources().size());
- client_.clear_returned_resources();
-
- // The forth frame references no resources of third frame and thus should
- // make all resources of third frame available to be returned.
- ResourceId forth_frame_ids[] = {7, 8, 9};
- SubmitCompositorFrameWithResources(forth_frame_ids,
- arraysize(forth_frame_ids));
-
- ResourceId forth_expected_returned_ids[] = {4, 5, 6};
- int forth_expected_returned_counts[] = {1, 1, 1};
- // Resources were never consumed so no sync token should be set.
- CheckReturnedResourcesMatchExpected(
- forth_expected_returned_ids, forth_expected_returned_counts,
- arraysize(forth_expected_returned_counts), gpu::SyncToken());
-}
-
-// Tests submitting a frame with resources followed by one with no resources
-// with the resource provider holding everything alive.
-TEST_F(SurfaceFactoryTest, ResourceLifetimeSimpleWithProviderHoldingAlive) {
- ResourceId first_frame_ids[] = {1, 2, 3};
- SubmitCompositorFrameWithResources(first_frame_ids,
- arraysize(first_frame_ids));
-
- // All of the resources submitted in the first frame are still in use at this
- // time by virtue of being in the pending frame, so none can be returned to
- // the client yet.
- EXPECT_EQ(0u, client_.returned_resources().size());
- client_.clear_returned_resources();
-
- // Hold on to everything.
- RefCurrentFrameResources();
-
- // The second frame references no resources and thus should make all resources
- // available to be returned as soon as the resource provider releases them.
- SubmitCompositorFrameWithResources(NULL, 0);
-
- EXPECT_EQ(0u, client_.returned_resources().size());
- client_.clear_returned_resources();
-
- int release_counts[] = {1, 1, 1};
- UnrefResources(first_frame_ids, release_counts, arraysize(first_frame_ids));
-
- ResourceId expected_returned_ids[] = {1, 2, 3};
- int expected_returned_counts[] = {1, 1, 1};
- CheckReturnedResourcesMatchExpected(
- expected_returned_ids, expected_returned_counts,
- arraysize(expected_returned_counts), consumer_sync_token_);
-}
-
-// Tests referencing a resource, unref'ing it to zero, then using it again
-// before returning it to the client.
-TEST_F(SurfaceFactoryTest, ResourceReusedBeforeReturn) {
- ResourceId first_frame_ids[] = {7};
- SubmitCompositorFrameWithResources(first_frame_ids,
- arraysize(first_frame_ids));
-
- // This removes all references to resource id 7.
- SubmitCompositorFrameWithResources(NULL, 0);
-
- // This references id 7 again.
- SubmitCompositorFrameWithResources(first_frame_ids,
- arraysize(first_frame_ids));
-
- // This removes it again.
- SubmitCompositorFrameWithResources(NULL, 0);
-
- // Now it should be returned.
- // We don't care how many entries are in the returned array for 7, so long as
- // the total returned count matches the submitted count.
- const ReturnedResourceArray& returned = client_.returned_resources();
- size_t return_count = 0;
- for (size_t i = 0; i < returned.size(); ++i) {
- EXPECT_EQ(7u, returned[i].id);
- return_count += returned[i].count;
- }
- EXPECT_EQ(2u, return_count);
-}
-
-// Tests having resources referenced multiple times, as if referenced by
-// multiple providers.
-TEST_F(SurfaceFactoryTest, ResourceRefMultipleTimes) {
- ResourceId first_frame_ids[] = {3, 4};
- SubmitCompositorFrameWithResources(first_frame_ids,
- arraysize(first_frame_ids));
-
- // Ref resources from the first frame twice.
- RefCurrentFrameResources();
- RefCurrentFrameResources();
-
- ResourceId second_frame_ids[] = {4, 5};
- SubmitCompositorFrameWithResources(second_frame_ids,
- arraysize(second_frame_ids));
-
- // Ref resources from the second frame 3 times.
- RefCurrentFrameResources();
- RefCurrentFrameResources();
- RefCurrentFrameResources();
-
- // Submit a frame with no resources to remove all current frame refs from
- // submitted resources.
- SubmitCompositorFrameWithResources(NULL, 0);
-
- EXPECT_EQ(0u, client_.returned_resources().size());
- client_.clear_returned_resources();
-
- // Expected current refs:
- // 3 -> 2
- // 4 -> 2 + 3 = 5
- // 5 -> 3
- {
- SCOPED_TRACE("unref all 3");
- ResourceId ids_to_unref[] = {3, 4, 5};
- int counts[] = {1, 1, 1};
- UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref));
-
- EXPECT_EQ(0u, client_.returned_resources().size());
- client_.clear_returned_resources();
-
- UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref));
-
- ResourceId expected_returned_ids[] = {3};
- int expected_returned_counts[] = {1};
- CheckReturnedResourcesMatchExpected(
- expected_returned_ids, expected_returned_counts,
- arraysize(expected_returned_counts), consumer_sync_token_);
- }
-
- // Expected refs remaining:
- // 4 -> 3
- // 5 -> 1
- {
- SCOPED_TRACE("unref 4 and 5");
- ResourceId ids_to_unref[] = {4, 5};
- int counts[] = {1, 1};
- UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref));
-
- ResourceId expected_returned_ids[] = {5};
- int expected_returned_counts[] = {1};
- CheckReturnedResourcesMatchExpected(
- expected_returned_ids, expected_returned_counts,
- arraysize(expected_returned_counts), consumer_sync_token_);
- }
-
- // Now, just 2 refs remaining on resource 4. Unref both at once and make sure
- // the returned count is correct.
- {
- SCOPED_TRACE("unref only 4");
- ResourceId ids_to_unref[] = {4};
- int counts[] = {2};
- UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref));
-
- ResourceId expected_returned_ids[] = {4};
- int expected_returned_counts[] = {2};
- CheckReturnedResourcesMatchExpected(
- expected_returned_ids, expected_returned_counts,
- arraysize(expected_returned_counts), consumer_sync_token_);
- }
-}
-
-TEST_F(SurfaceFactoryTest, ResourceLifetime) {
- ResourceId first_frame_ids[] = {1, 2, 3};
- SubmitCompositorFrameWithResources(first_frame_ids,
- arraysize(first_frame_ids));
-
- // All of the resources submitted in the first frame are still in use at this
- // time by virtue of being in the pending frame, so none can be returned to
- // the client yet.
- EXPECT_EQ(0u, client_.returned_resources().size());
- client_.clear_returned_resources();
-
- // The second frame references some of the same resources, but some different
- // ones. We expect to receive back resource 1 with a count of 1 since it was
- // only referenced by the first frame.
- ResourceId second_frame_ids[] = {2, 3, 4};
- SubmitCompositorFrameWithResources(second_frame_ids,
- arraysize(second_frame_ids));
-
- {
- SCOPED_TRACE("second frame");
- ResourceId expected_returned_ids[] = {1};
- int expected_returned_counts[] = {1};
- CheckReturnedResourcesMatchExpected(
- expected_returned_ids, expected_returned_counts,
- arraysize(expected_returned_counts), gpu::SyncToken());
- }
-
- // The third frame references a disjoint set of resources, so we expect to
- // receive back all resources from the first and second frames. Resource IDs 2
- // and 3 will have counts of 2, since they were used in both frames, and
- // resource ID 4 will have a count of 1.
- ResourceId third_frame_ids[] = {10, 11, 12, 13};
- SubmitCompositorFrameWithResources(third_frame_ids,
- arraysize(third_frame_ids));
-
- {
- SCOPED_TRACE("third frame");
- ResourceId expected_returned_ids[] = {2, 3, 4};
- int expected_returned_counts[] = {2, 2, 1};
- CheckReturnedResourcesMatchExpected(
- expected_returned_ids, expected_returned_counts,
- arraysize(expected_returned_counts), gpu::SyncToken());
- }
-
- // Simulate a ResourceProvider taking a ref on all of the resources.
- RefCurrentFrameResources();
-
- ResourceId fourth_frame_ids[] = {12, 13};
- SubmitCompositorFrameWithResources(fourth_frame_ids,
- arraysize(fourth_frame_ids));
-
- EXPECT_EQ(0u, client_.returned_resources().size());
-
- RefCurrentFrameResources();
-
- // All resources are still being used by the external reference, so none can
- // be returned to the client.
- EXPECT_EQ(0u, client_.returned_resources().size());
-
- // Release resources associated with the first RefCurrentFrameResources() call
- // first.
- {
- ResourceId ids_to_unref[] = {10, 11, 12, 13};
- int counts[] = {1, 1, 1, 1};
- UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref));
- }
-
- {
- SCOPED_TRACE("fourth frame, first unref");
- ResourceId expected_returned_ids[] = {10, 11};
- int expected_returned_counts[] = {1, 1};
- CheckReturnedResourcesMatchExpected(
- expected_returned_ids, expected_returned_counts,
- arraysize(expected_returned_counts), consumer_sync_token_);
- }
-
- {
- ResourceId ids_to_unref[] = {12, 13};
- int counts[] = {1, 1};
- UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref));
- }
-
- // Resources 12 and 13 are still in use by the current frame, so they
- // shouldn't be available to be returned.
- EXPECT_EQ(0u, client_.returned_resources().size());
-
- // If we submit an empty frame, however, they should become available.
- SubmitCompositorFrameWithResources(NULL, 0u);
-
- {
- SCOPED_TRACE("fourth frame, second unref");
- ResourceId expected_returned_ids[] = {12, 13};
- int expected_returned_counts[] = {2, 2};
- CheckReturnedResourcesMatchExpected(
- expected_returned_ids, expected_returned_counts,
- arraysize(expected_returned_counts), consumer_sync_token_);
- }
-}
-
-TEST_F(SurfaceFactoryTest, BlankNoIndexIncrement) {
- LocalSurfaceId local_surface_id(6, kArbitraryToken);
- SurfaceId surface_id(kArbitraryFrameSinkId, local_surface_id);
- factory_->SubmitCompositorFrame(local_surface_id, CompositorFrame(),
- SurfaceFactory::DrawCallback());
- Surface* surface = manager_.GetSurfaceForId(surface_id);
- ASSERT_NE(nullptr, surface);
- EXPECT_EQ(2, surface->frame_index());
- EXPECT_EQ(last_created_surface_id().local_surface_id(), local_surface_id);
-}
-
-void CreateSurfaceDrawCallback(SurfaceFactory* factory,
- uint32_t* execute_count) {
- LocalSurfaceId new_id(7, base::UnguessableToken::Create());
- factory->SubmitCompositorFrame(new_id, CompositorFrame(),
- SurfaceFactory::DrawCallback());
- factory->EvictSurface();
- *execute_count += 1;
-}
-
-TEST_F(SurfaceFactoryTest, AddDuringEviction) {
- LocalSurfaceId local_surface_id(6, kArbitraryToken);
-
- uint32_t execute_count = 0;
- factory_->SubmitCompositorFrame(
- local_surface_id, CompositorFrame(),
- base::Bind(&CreateSurfaceDrawCallback, base::Unretained(factory_.get()),
- &execute_count));
- EXPECT_EQ(0u, execute_count);
- factory_->EvictSurface();
- EXPECT_EQ(1u, execute_count);
-}
-
-void DrawCallback(uint32_t* execute_count) {
- *execute_count += 1;
-}
-
-// Tests doing an EvictSurface before shutting down the factory.
-TEST_F(SurfaceFactoryTest, EvictSurface) {
- LocalSurfaceId local_surface_id(7, kArbitraryToken);
- SurfaceId id(kArbitraryFrameSinkId, local_surface_id);
-
- TransferableResource resource;
- resource.id = 1;
- resource.mailbox_holder.texture_target = GL_TEXTURE_2D;
- CompositorFrame frame;
- frame.resource_list.push_back(resource);
- uint32_t execute_count = 0;
- factory_->SubmitCompositorFrame(local_surface_id, std::move(frame),
- base::Bind(&DrawCallback, &execute_count));
- EXPECT_EQ(last_created_surface_id().local_surface_id(), local_surface_id);
- local_surface_id_ = LocalSurfaceId();
-
- EXPECT_TRUE(manager_.GetSurfaceForId(id));
- EXPECT_TRUE(client_.returned_resources().empty());
- factory_->EvictSurface();
- EXPECT_FALSE(manager_.GetSurfaceForId(id));
- EXPECT_FALSE(client_.returned_resources().empty());
- EXPECT_EQ(1u, execute_count);
-}
-
-// Tests doing an EvictSurface which has unregistered dependency.
-TEST_F(SurfaceFactoryTest, EvictSurfaceDependencyUnRegistered) {
- LocalSurfaceId local_surface_id(7, kArbitraryToken);
-
- TransferableResource resource;
- resource.id = 1;
- resource.mailbox_holder.texture_target = GL_TEXTURE_2D;
- CompositorFrame frame;
- frame.resource_list.push_back(resource);
- uint32_t execute_count = 0;
- factory_->SubmitCompositorFrame(local_surface_id, std::move(frame),
- base::Bind(&DrawCallback, &execute_count));
- EXPECT_EQ(last_created_surface_id().local_surface_id(), local_surface_id);
- local_surface_id_ = LocalSurfaceId();
-
- SurfaceId surface_id(kArbitraryFrameSinkId, local_surface_id);
- Surface* surface = manager_.GetSurfaceForId(surface_id);
- surface->AddDestructionDependency(
- SurfaceSequence(kAnotherArbitraryFrameSinkId, 4));
-
- EXPECT_TRUE(manager_.GetSurfaceForId(surface_id));
- EXPECT_TRUE(client_.returned_resources().empty());
- factory_->EvictSurface();
- EXPECT_FALSE(manager_.GetSurfaceForId(surface_id));
- EXPECT_FALSE(client_.returned_resources().empty());
- EXPECT_EQ(1u, execute_count);
-}
-
-// Tests doing an EvictSurface which has registered dependency.
-TEST_F(SurfaceFactoryTest, EvictSurfaceDependencyRegistered) {
- LocalSurfaceId local_surface_id(7, kArbitraryToken);
-
- TransferableResource resource;
- resource.id = 1;
- resource.mailbox_holder.texture_target = GL_TEXTURE_2D;
- CompositorFrame frame;
- frame.resource_list.push_back(resource);
- uint32_t execute_count = 0;
- factory_->SubmitCompositorFrame(local_surface_id, std::move(frame),
- base::Bind(&DrawCallback, &execute_count));
- EXPECT_EQ(last_created_surface_id().local_surface_id(), local_surface_id);
- local_surface_id_ = LocalSurfaceId();
-
- manager_.RegisterFrameSinkId(kAnotherArbitraryFrameSinkId);
-
- SurfaceId surface_id(kArbitraryFrameSinkId, local_surface_id);
- Surface* surface = manager_.GetSurfaceForId(surface_id);
- surface->AddDestructionDependency(
- SurfaceSequence(kAnotherArbitraryFrameSinkId, 4));
-
- EXPECT_TRUE(manager_.GetSurfaceForId(surface_id));
- EXPECT_TRUE(client_.returned_resources().empty());
- factory_->EvictSurface();
- EXPECT_TRUE(manager_.GetSurfaceForId(surface_id));
- EXPECT_TRUE(client_.returned_resources().empty());
- EXPECT_EQ(0u, execute_count);
-
- manager_.SatisfySequence(SurfaceSequence(kAnotherArbitraryFrameSinkId, 4));
- EXPECT_FALSE(manager_.GetSurfaceForId(surface_id));
- EXPECT_FALSE(client_.returned_resources().empty());
-}
-
-TEST_F(SurfaceFactoryTest, DestroySequence) {
- LocalSurfaceId local_surface_id2(5, kArbitraryToken);
- std::unique_ptr<SurfaceFactory> factory2(
- new SurfaceFactory(kArbitraryFrameSinkId, &manager_, &client_));
- SurfaceId id2(kArbitraryFrameSinkId, local_surface_id2);
- factory2->SubmitCompositorFrame(local_surface_id2, CompositorFrame(),
- SurfaceFactory::DrawCallback());
-
- manager_.RegisterFrameSinkId(kArbitraryFrameSinkId);
-
- // Check that waiting before the sequence is satisfied works.
- manager_.GetSurfaceForId(id2)->AddDestructionDependency(
- SurfaceSequence(kArbitraryFrameSinkId, 4));
- factory2->EvictSurface();
-
- DCHECK(manager_.GetSurfaceForId(id2));
- manager_.SatisfySequence(SurfaceSequence(kArbitraryFrameSinkId, 4));
- manager_.SatisfySequence(SurfaceSequence(kArbitraryFrameSinkId, 6));
- DCHECK(!manager_.GetSurfaceForId(id2));
-
- // Check that waiting after the sequence is satisfied works.
- factory2->SubmitCompositorFrame(local_surface_id2, CompositorFrame(),
- SurfaceFactory::DrawCallback());
- DCHECK(manager_.GetSurfaceForId(id2));
- manager_.GetSurfaceForId(id2)->AddDestructionDependency(
- SurfaceSequence(kAnotherArbitraryFrameSinkId, 6));
- factory2->EvictSurface();
- DCHECK(!manager_.GetSurfaceForId(id2));
-}
-
-// Tests that Surface ID namespace invalidation correctly allows
-// Sequences to be ignored.
-TEST_F(SurfaceFactoryTest, InvalidFrameSinkId) {
- FrameSinkId frame_sink_id(1234, 5678);
-
- LocalSurfaceId local_surface_id(5, kArbitraryToken);
- SurfaceId id(factory_->frame_sink_id(), local_surface_id);
- factory_->SubmitCompositorFrame(local_surface_id, CompositorFrame(),
- SurfaceFactory::DrawCallback());
-
- manager_.RegisterFrameSinkId(frame_sink_id);
- manager_.GetSurfaceForId(id)->AddDestructionDependency(
- SurfaceSequence(frame_sink_id, 4));
-
- factory_->EvictSurface();
-
- // Verify the dependency has prevented the surface from getting destroyed.
- EXPECT_TRUE(manager_.GetSurfaceForId(id));
-
- manager_.InvalidateFrameSinkId(frame_sink_id);
-
- // Verify that the invalidated namespace caused the unsatisfied sequence
- // to be ignored.
- EXPECT_FALSE(manager_.GetSurfaceForId(id));
-}
-
-TEST_F(SurfaceFactoryTest, DestroyCycle) {
- LocalSurfaceId local_surface_id2(5, kArbitraryToken);
- SurfaceId id2(kArbitraryFrameSinkId, local_surface_id2);
- std::unique_ptr<SurfaceFactory> factory2(
- new SurfaceFactory(kArbitraryFrameSinkId, &manager_, &client_));
- manager_.RegisterFrameSinkId(kAnotherArbitraryFrameSinkId);
- // Give id2 a frame that references local_surface_id_.
- {
- std::unique_ptr<RenderPass> render_pass(RenderPass::Create());
- CompositorFrame frame;
- frame.render_pass_list.push_back(std::move(render_pass));
- frame.metadata.referenced_surfaces.push_back(
- SurfaceId(factory_->frame_sink_id(), local_surface_id_));
- factory2->SubmitCompositorFrame(local_surface_id2, std::move(frame),
- SurfaceFactory::DrawCallback());
- EXPECT_EQ(last_created_surface_id().local_surface_id(), local_surface_id2);
- }
- manager_.GetSurfaceForId(id2)->AddDestructionDependency(
- SurfaceSequence(kAnotherArbitraryFrameSinkId, 4));
- factory2->EvictSurface();
- // Give local_surface_id_ a frame that references id2.
- {
- std::unique_ptr<RenderPass> render_pass(RenderPass::Create());
- CompositorFrame frame;
- frame.render_pass_list.push_back(std::move(render_pass));
- frame.metadata.referenced_surfaces.push_back(id2);
- factory_->SubmitCompositorFrame(local_surface_id_, std::move(frame),
- SurfaceFactory::DrawCallback());
- }
- factory_->EvictSurface();
- EXPECT_TRUE(manager_.GetSurfaceForId(id2));
- // local_surface_id_ should be retained by reference from id2.
- EXPECT_TRUE(manager_.GetSurfaceForId(
- SurfaceId(factory_->frame_sink_id(), local_surface_id_)));
-
- // Satisfy last destruction dependency for id2.
- manager_.SatisfySequence(SurfaceSequence(kAnotherArbitraryFrameSinkId, 4));
-
- // id2 and local_surface_id_ are in a reference cycle that has no surface
- // sequences holding on to it, so they should be destroyed.
- EXPECT_TRUE(!manager_.GetSurfaceForId(id2));
- EXPECT_TRUE(!manager_.GetSurfaceForId(
- SurfaceId(factory_->frame_sink_id(), local_surface_id_)));
-
- local_surface_id_ = LocalSurfaceId();
-}
-
-void CopyRequestTestCallback(bool* called,
- std::unique_ptr<CopyOutputResult> result) {
- *called = true;
-}
-
-TEST_F(SurfaceFactoryTest, DuplicateCopyRequest) {
- {
- std::unique_ptr<RenderPass> render_pass(RenderPass::Create());
- CompositorFrame frame;
- frame.render_pass_list.push_back(std::move(render_pass));
- frame.metadata.referenced_surfaces.push_back(
- SurfaceId(factory_->frame_sink_id(), local_surface_id_));
- factory_->SubmitCompositorFrame(local_surface_id_, std::move(frame),
- SurfaceFactory::DrawCallback());
- EXPECT_EQ(last_created_surface_id().local_surface_id(), local_surface_id_);
- }
-
- bool called1 = false;
- std::unique_ptr<CopyOutputRequest> request;
- request = CopyOutputRequest::CreateRequest(
- base::Bind(&CopyRequestTestCallback, &called1));
- request->set_source(kArbitrarySourceId1);
-
- factory_->RequestCopyOfSurface(std::move(request));
- EXPECT_FALSE(called1);
-
- bool called2 = false;
- request = CopyOutputRequest::CreateRequest(
- base::Bind(&CopyRequestTestCallback, &called2));
- request->set_source(kArbitrarySourceId2);
-
- factory_->RequestCopyOfSurface(std::move(request));
- // Callbacks have different sources so neither should be called.
- EXPECT_FALSE(called1);
- EXPECT_FALSE(called2);
-
- bool called3 = false;
- request = CopyOutputRequest::CreateRequest(
- base::Bind(&CopyRequestTestCallback, &called3));
- request->set_source(kArbitrarySourceId1);
-
- factory_->RequestCopyOfSurface(std::move(request));
- // Two callbacks are from source1, so the first should be called.
- EXPECT_TRUE(called1);
- EXPECT_FALSE(called2);
- EXPECT_FALSE(called3);
-
- factory_->EvictSurface();
- local_surface_id_ = LocalSurfaceId();
- EXPECT_TRUE(called1);
- EXPECT_TRUE(called2);
- EXPECT_TRUE(called3);
-}
-
-// Check whether the SurfaceInfo object is created and populated correctly
-// after the frame submission.
-TEST_F(SurfaceFactoryTest, SurfaceInfo) {
- CompositorFrame frame;
-
- auto render_pass = RenderPass::Create();
- render_pass->SetNew(1, gfx::Rect(5, 6), gfx::Rect(), gfx::Transform());
- frame.render_pass_list.push_back(std::move(render_pass));
-
- render_pass = RenderPass::Create();
- render_pass->SetNew(2, gfx::Rect(7, 8), gfx::Rect(), gfx::Transform());
- frame.render_pass_list.push_back(std::move(render_pass));
-
- frame.metadata.device_scale_factor = 2.5f;
-
- factory_->SubmitCompositorFrame(local_surface_id_, std::move(frame),
- SurfaceFactory::DrawCallback());
- SurfaceId expected_surface_id(factory_->frame_sink_id(), local_surface_id_);
- EXPECT_EQ(expected_surface_id, last_surface_info_.id());
- EXPECT_EQ(2.5f, last_surface_info_.device_scale_factor());
- EXPECT_EQ(gfx::Size(7, 8), last_surface_info_.size_in_pixels());
-}
-
-} // namespace
-} // namespace cc
diff --git a/chromium/cc/surfaces/surface_hittest.cc b/chromium/cc/surfaces/surface_hittest.cc
index 88de04fc8fe..01a0fe2e02e 100644
--- a/chromium/cc/surfaces/surface_hittest.cc
+++ b/chromium/cc/surfaces/surface_hittest.cc
@@ -260,9 +260,6 @@ const RenderPass* SurfaceHittest::GetRenderPassForSurfaceById(
return nullptr;
const CompositorFrame& surface_frame = surface->GetActiveFrame();
- if (surface_frame.render_pass_list.empty())
- return nullptr;
-
if (!render_pass_id)
return surface_frame.render_pass_list.back().get();
diff --git a/chromium/cc/surfaces/surface_hittest_unittest.cc b/chromium/cc/surfaces/surface_hittest_unittest.cc
index 312a7ae9b50..4e406e39ad6 100644
--- a/chromium/cc/surfaces/surface_hittest_unittest.cc
+++ b/chromium/cc/surfaces/surface_hittest_unittest.cc
@@ -10,6 +10,7 @@
#include "cc/surfaces/surface.h"
#include "cc/surfaces/surface_hittest.h"
#include "cc/surfaces/surface_manager.h"
+#include "cc/test/compositor_frame_helpers.h"
#include "cc/test/surface_hittest_test_helpers.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkColor.h"
@@ -103,7 +104,7 @@ TEST(SurfaceHittestTest, Hittest_BadCompositorFrameDoesNotCrash) {
root_surface_id, gfx::Point(100, 100), &transform));
}
- root_support->EvictFrame();
+ root_support->EvictCurrentSurface();
}
TEST(SurfaceHittestTest, Hittest_SingleSurface) {
@@ -138,7 +139,7 @@ TEST(SurfaceHittestTest, Hittest_SingleSurface) {
RunTests(nullptr, &manager, tests, arraysize(tests));
- root_support->EvictFrame();
+ root_support->EvictCurrentSurface();
}
TEST(SurfaceHittestTest, Hittest_ChildSurface) {
@@ -278,8 +279,8 @@ TEST(SurfaceHittestTest, Hittest_ChildSurface) {
EXPECT_EQ(gfx::Point(25, 25), point_in_target_space);
}
- root_support->EvictFrame();
- child_support->EvictFrame();
+ root_support->EvictCurrentSurface();
+ child_support->EvictCurrentSurface();
}
// This test verifies that hit testing will progress to the next quad if it
@@ -391,8 +392,8 @@ TEST(SurfaceHittestTest, Hittest_InvalidRenderPassDrawQuad) {
RunTests(nullptr, &manager, tests, arraysize(tests));
- root_support->EvictFrame();
- child_support->EvictFrame();
+ root_support->EvictCurrentSurface();
+ child_support->EvictCurrentSurface();
}
TEST(SurfaceHittestTest, Hittest_RenderPassDrawQuad) {
@@ -405,7 +406,7 @@ TEST(SurfaceHittestTest, Hittest_RenderPassDrawQuad) {
// Create a CompostiorFrame with two RenderPasses.
gfx::Rect root_rect(300, 300);
- CompositorFrame root_frame;
+ CompositorFrame root_frame = test::MakeCompositorFrame();
RenderPassList& render_pass_list = root_frame.render_pass_list;
// Create a child RenderPass.
@@ -495,7 +496,7 @@ TEST(SurfaceHittestTest, Hittest_RenderPassDrawQuad) {
RunTests(nullptr, &manager, tests, arraysize(tests));
- support->EvictFrame();
+ support->EvictCurrentSurface();
}
TEST(SurfaceHittestTest, Hittest_SingleSurface_WithInsetsDelegate) {
@@ -633,8 +634,8 @@ TEST(SurfaceHittestTest, Hittest_SingleSurface_WithInsetsDelegate) {
EXPECT_EQ(0, accept_delegate.reject_target_overrides());
EXPECT_EQ(2, accept_delegate.accept_target_overrides());
- root_support->EvictFrame();
- child_support->EvictFrame();
+ root_support->EvictCurrentSurface();
+ child_support->EvictCurrentSurface();
}
} // namespace cc
diff --git a/chromium/cc/surfaces/surface_manager.cc b/chromium/cc/surfaces/surface_manager.cc
index d4b0d01397f..07d23380094 100644
--- a/chromium/cc/surfaces/surface_manager.cc
+++ b/chromium/cc/surfaces/surface_manager.cc
@@ -11,10 +11,10 @@
#include <utility>
#include "base/logging.h"
+#include "cc/surfaces/compositor_frame_sink_support.h"
#include "cc/surfaces/direct_surface_reference_factory.h"
#include "cc/surfaces/local_surface_id_allocator.h"
#include "cc/surfaces/surface.h"
-#include "cc/surfaces/surface_factory_client.h"
#include "cc/surfaces/surface_info.h"
#if DCHECK_IS_ON()
@@ -65,8 +65,8 @@ std::string SurfaceManager::SurfaceReferencesToString() {
#endif
void SurfaceManager::SetDependencyTracker(
- std::unique_ptr<SurfaceDependencyTracker> dependency_tracker) {
- dependency_tracker_ = std::move(dependency_tracker);
+ SurfaceDependencyTracker* dependency_tracker) {
+ dependency_tracker_ = dependency_tracker;
}
void SurfaceManager::RequestSurfaceResolution(Surface* pending_surface) {
@@ -75,18 +75,20 @@ void SurfaceManager::RequestSurfaceResolution(Surface* pending_surface) {
}
std::unique_ptr<Surface> SurfaceManager::CreateSurface(
- base::WeakPtr<SurfaceFactory> surface_factory,
- const LocalSurfaceId& local_surface_id) {
+ base::WeakPtr<CompositorFrameSinkSupport> compositor_frame_sink_support,
+ const SurfaceInfo& surface_info) {
DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(local_surface_id.is_valid() && surface_factory);
-
- SurfaceId surface_id(surface_factory->frame_sink_id(), local_surface_id);
+ DCHECK(surface_info.is_valid());
+ DCHECK(compositor_frame_sink_support);
+ DCHECK_EQ(surface_info.id().frame_sink_id(),
+ compositor_frame_sink_support->frame_sink_id());
// If no surface with this SurfaceId exists, simply create the surface and
// return.
- auto surface_iter = surface_map_.find(surface_id);
+ auto surface_iter = surface_map_.find(surface_info.id());
if (surface_iter == surface_map_.end()) {
- auto surface = base::MakeUnique<Surface>(surface_id, surface_factory);
+ auto surface =
+ base::MakeUnique<Surface>(surface_info, compositor_frame_sink_support);
surface_map_[surface->surface_id()] = surface.get();
return surface;
}
@@ -101,14 +103,15 @@ std::unique_ptr<Surface> SurfaceManager::CreateSurface(
// the queue and reuse it.
auto it =
std::find_if(surfaces_to_destroy_.begin(), surfaces_to_destroy_.end(),
- [&surface_id](const std::unique_ptr<Surface>& surface) {
- return surface->surface_id() == surface_id;
+ [&surface_info](const std::unique_ptr<Surface>& surface) {
+ return surface->surface_id() == surface_info.id();
});
DCHECK(it != surfaces_to_destroy_.end());
std::unique_ptr<Surface> surface = std::move(*it);
surfaces_to_destroy_.erase(it);
surface->set_destroyed(false);
- DCHECK_EQ(surface_factory.get(), surface->factory().get());
+ DCHECK_EQ(compositor_frame_sink_support.get(),
+ surface->compositor_frame_sink_support().get());
return surface;
}
@@ -407,15 +410,15 @@ void SurfaceManager::RemoveTemporaryReference(const SurfaceId& surface_id,
temporary_reference_ranges_.erase(frame_sink_id);
}
-void SurfaceManager::RegisterSurfaceFactoryClient(
+void SurfaceManager::RegisterFrameSinkManagerClient(
const FrameSinkId& frame_sink_id,
- SurfaceFactoryClient* client) {
- framesink_manager_.RegisterSurfaceFactoryClient(frame_sink_id, client);
+ FrameSinkManagerClient* client) {
+ framesink_manager_.RegisterFrameSinkManagerClient(frame_sink_id, client);
}
-void SurfaceManager::UnregisterSurfaceFactoryClient(
+void SurfaceManager::UnregisterFrameSinkManagerClient(
const FrameSinkId& frame_sink_id) {
- framesink_manager_.UnregisterSurfaceFactoryClient(frame_sink_id);
+ framesink_manager_.UnregisterFrameSinkManagerClient(frame_sink_id);
}
void SurfaceManager::RegisterBeginFrameSource(
@@ -428,6 +431,10 @@ void SurfaceManager::UnregisterBeginFrameSource(BeginFrameSource* source) {
framesink_manager_.UnregisterBeginFrameSource(source);
}
+BeginFrameSource* SurfaceManager::GetPrimaryBeginFrameSource() {
+ return framesink_manager_.GetPrimaryBeginFrameSource();
+}
+
void SurfaceManager::RegisterFrameSinkHierarchy(
const FrameSinkId& parent_frame_sink_id,
const FrameSinkId& child_frame_sink_id) {
@@ -475,6 +482,28 @@ void SurfaceManager::SurfaceCreated(const SurfaceInfo& surface_info) {
observer.OnSurfaceCreated(surface_info);
}
+void SurfaceManager::SurfaceActivated(Surface* surface) {
+ if (dependency_tracker_)
+ dependency_tracker_->OnSurfaceActivated(surface);
+}
+
+void SurfaceManager::SurfaceDependenciesChanged(
+ Surface* surface,
+ const base::flat_set<SurfaceId>& added_dependencies,
+ const base::flat_set<SurfaceId>& removed_dependencies) {
+ if (dependency_tracker_) {
+ dependency_tracker_->OnSurfaceDependenciesChanged(
+ surface, added_dependencies, removed_dependencies);
+ }
+}
+
+void SurfaceManager::SurfaceDiscarded(Surface* surface) {
+ for (auto& observer : observer_list_)
+ observer.OnSurfaceDiscarded(surface->surface_id());
+ if (dependency_tracker_)
+ dependency_tracker_->OnSurfaceDiscarded(surface);
+}
+
void SurfaceManager::UnregisterSurface(const SurfaceId& surface_id) {
DCHECK(thread_checker_.CalledOnValidThread());
SurfaceMap::iterator it = surface_map_.find(surface_id);
@@ -498,19 +527,15 @@ void SurfaceManager::SurfaceReferencesToStringImpl(const SurfaceId& surface_id,
if (surface->HasPendingFrame()) {
// This provides the surface size from the root render pass.
const CompositorFrame& frame = surface->GetPendingFrame();
- if (!frame.render_pass_list.empty()) {
- *str << " pending "
- << frame.render_pass_list.back()->output_rect.size().ToString();
- }
+ *str << " pending "
+ << frame.render_pass_list.back()->output_rect.size().ToString();
}
if (surface->HasActiveFrame()) {
// This provides the surface size from the root render pass.
const CompositorFrame& frame = surface->GetActiveFrame();
- if (!frame.render_pass_list.empty()) {
- *str << " active "
- << frame.render_pass_list.back()->output_rect.size().ToString();
- }
+ *str << " active "
+ << frame.render_pass_list.back()->output_rect.size().ToString();
}
} else {
*str << surface_id;
diff --git a/chromium/cc/surfaces/surface_manager.h b/chromium/cc/surfaces/surface_manager.h
index 53998ec5cb9..4a45f2c34c2 100644
--- a/chromium/cc/surfaces/surface_manager.h
+++ b/chromium/cc/surfaces/surface_manager.h
@@ -13,13 +13,14 @@
#include <unordered_set>
#include <vector>
+#include "base/containers/flat_set.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/threading/thread_checker.h"
#include "cc/surfaces/frame_sink_id.h"
-#include "cc/surfaces/framesink_manager.h"
+#include "cc/surfaces/frame_sink_manager.h"
#include "cc/surfaces/surface_dependency_tracker.h"
#include "cc/surfaces/surface_id.h"
#include "cc/surfaces/surface_observer.h"
@@ -36,12 +37,11 @@
namespace cc {
class BeginFrameSource;
class CompositorFrame;
+class FrameSinkManagerClient;
class Surface;
-class SurfaceFactory;
-class SurfaceFactoryClient;
namespace test {
-class CompositorFrameSinkSupportTest;
+class SurfaceSynchronizationTest;
}
class CC_SURFACES_EXPORT SurfaceManager {
@@ -59,17 +59,14 @@ class CC_SURFACES_EXPORT SurfaceManager {
std::string SurfaceReferencesToString();
#endif
- void SetDependencyTracker(
- std::unique_ptr<SurfaceDependencyTracker> dependency_tracker);
- SurfaceDependencyTracker* dependency_tracker() {
- return dependency_tracker_.get();
- }
+ void SetDependencyTracker(SurfaceDependencyTracker* dependency_tracker);
+ SurfaceDependencyTracker* dependency_tracker() { return dependency_tracker_; }
void RequestSurfaceResolution(Surface* pending_surface);
std::unique_ptr<Surface> CreateSurface(
- base::WeakPtr<SurfaceFactory> surface_factory,
- const LocalSurfaceId& local_surface_id);
+ base::WeakPtr<CompositorFrameSinkSupport> compositor_frame_sink_support,
+ const SurfaceInfo& surface_info);
// Destroy the Surface once a set of sequence numbers has been satisfied.
void DestroySurface(std::unique_ptr<Surface> surface);
@@ -84,10 +81,23 @@ class CC_SURFACES_EXPORT SurfaceManager {
bool SurfaceModified(const SurfaceId& surface_id);
- // Called when a CompositorFrame is submitted to a SurfaceFactory for a given
- // |surface_id| for the first time.
+ // Called when a CompositorFrame is submitted to a CompositorFrameSinkSupport
+ // for a given |surface_id| for the first time.
void SurfaceCreated(const SurfaceInfo& surface_info);
+ // Called when a CompositorFrame within |surface| has activated.
+ void SurfaceActivated(Surface* surface);
+
+ // Called when the dependencies of a pending CompositorFrame within |surface|
+ // has changed.
+ void SurfaceDependenciesChanged(
+ Surface* surface,
+ const base::flat_set<SurfaceId>& added_dependencies,
+ const base::flat_set<SurfaceId>& removed_dependencies);
+
+ // Called when |surface| is being destroyed.
+ void SurfaceDiscarded(Surface* surface);
+
// Require that the given sequence number must be satisfied (using
// SatisfySequence) before the given surface can be destroyed.
void RequireSequence(const SurfaceId& surface_id,
@@ -103,23 +113,23 @@ class CC_SURFACES_EXPORT SurfaceManager {
// possibly because a renderer process has crashed.
void InvalidateFrameSinkId(const FrameSinkId& frame_sink_id);
- // SurfaceFactoryClient, hierarchy, and BeginFrameSource can be registered
- // and unregistered in any order with respect to each other.
+ // CompositorFrameSinkSupport, hierarchy, and BeginFrameSource can be
+ // registered and unregistered in any order with respect to each other.
//
// This happens in practice, e.g. the relationship to between ui::Compositor /
// DelegatedFrameHost is known before ui::Compositor has a surface/client).
// However, DelegatedFrameHost can register itself as a client before its
// relationship with the ui::Compositor is known.
- // Associates a SurfaceFactoryClient with the surface id frame_sink_id it
+ // Associates a FrameSinkManagerClient with the surface id frame_sink_id it
// uses.
- // SurfaceFactoryClient and surface namespaces/allocators have a 1:1 mapping.
- // Caller guarantees the client is alive between register/unregister.
+ // FrameSinkManagerClient and surface namespaces/allocators have a 1:1
+ // mapping. Caller guarantees the client is alive between register/unregister.
// Reregistering the same namespace when a previous client is active is not
// valid.
- void RegisterSurfaceFactoryClient(const FrameSinkId& frame_sink_id,
- SurfaceFactoryClient* client);
- void UnregisterSurfaceFactoryClient(const FrameSinkId& frame_sink_id);
+ void RegisterFrameSinkManagerClient(const FrameSinkId& frame_sink_id,
+ FrameSinkManagerClient* client);
+ void UnregisterFrameSinkManagerClient(const FrameSinkId& frame_sink_id);
// Associates a |source| with a particular namespace. That namespace and
// any children of that namespace with valid clients can potentially use
@@ -128,6 +138,10 @@ class CC_SURFACES_EXPORT SurfaceManager {
const FrameSinkId& frame_sink_id);
void UnregisterBeginFrameSource(BeginFrameSource* source);
+ // Returns a stable BeginFrameSource that forwards BeginFrames from the first
+ // available BeginFrameSource.
+ BeginFrameSource* GetPrimaryBeginFrameSource();
+
// Register a relationship between two namespaces. This relationship means
// that surfaces from the child namespace will be displayed in the parent.
// Children are allowed to use any begin frame source that their parent can
@@ -171,7 +185,7 @@ class CC_SURFACES_EXPORT SurfaceManager {
}
private:
- friend class test::CompositorFrameSinkSupportTest;
+ friend class test::SurfaceSynchronizationTest;
friend class SurfaceManagerRefTest;
using SurfaceIdSet = std::unordered_set<SurfaceId, SurfaceIdHash>;
@@ -242,11 +256,11 @@ class CC_SURFACES_EXPORT SurfaceManager {
// Tracks references from the child surface to parent surface. If there are
// zero entries in the set for a SurfaceId then nothing is referencing the
// surface and it can be garbage collected.
- std::unordered_map<SurfaceId, SurfaceIdSet, SurfaceIdHash>
+ std::unordered_map<SurfaceId, base::flat_set<SurfaceId>, SurfaceIdHash>
child_to_parent_refs_;
// Tracks references from the parent surface to child surface. Is the inverse
// of |child_to_parent_refs_|.
- std::unordered_map<SurfaceId, SurfaceIdSet, SurfaceIdHash>
+ std::unordered_map<SurfaceId, base::flat_set<SurfaceId>, SurfaceIdHash>
parent_to_child_refs_;
// Root SurfaceId that references display root surfaces. There is no Surface
@@ -275,7 +289,7 @@ class CC_SURFACES_EXPORT SurfaceManager {
std::unordered_map<FrameSinkId, std::vector<LocalSurfaceId>, FrameSinkIdHash>
temporary_reference_ranges_;
- std::unique_ptr<SurfaceDependencyTracker> dependency_tracker_;
+ SurfaceDependencyTracker* dependency_tracker_ = nullptr;
base::WeakPtrFactory<SurfaceManager> weak_factory_;
diff --git a/chromium/cc/surfaces/surface_manager_ref_unittest.cc b/chromium/cc/surfaces/surface_manager_ref_unittest.cc
index eb678f8f0c9..e96b795e298 100644
--- a/chromium/cc/surfaces/surface_manager_ref_unittest.cc
+++ b/chromium/cc/surfaces/surface_manager_ref_unittest.cc
@@ -7,11 +7,13 @@
#include <unordered_map>
#include <vector>
+#include "base/containers/flat_set.h"
#include "base/memory/ptr_util.h"
#include "cc/surfaces/compositor_frame_sink_support.h"
#include "cc/surfaces/surface.h"
#include "cc/surfaces/surface_id.h"
#include "cc/surfaces/surface_manager.h"
+#include "cc/test/compositor_frame_helpers.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -21,7 +23,6 @@ using testing::SizeIs;
using testing::UnorderedElementsAre;
namespace cc {
-
namespace {
constexpr FrameSinkId kFrameSink1(1, 0);
@@ -41,13 +42,14 @@ class SurfaceManagerRefTest : public testing::Test {
LocalSurfaceId local_surface_id(local_id,
base::UnguessableToken::Deserialize(0, 1u));
GetCompositorFrameSinkSupport(frame_sink_id)
- .SubmitCompositorFrame(local_surface_id, CompositorFrame());
+ .SubmitCompositorFrame(local_surface_id, test::MakeCompositorFrame());
return SurfaceId(frame_sink_id, local_surface_id);
}
// Destroy Surface with |surface_id|.
void DestroySurface(const SurfaceId& surface_id) {
- GetCompositorFrameSinkSupport(surface_id.frame_sink_id()).EvictFrame();
+ GetCompositorFrameSinkSupport(surface_id.frame_sink_id())
+ .EvictCurrentSurface();
}
CompositorFrameSinkSupport& GetCompositorFrameSinkSupport(
@@ -81,13 +83,13 @@ class SurfaceManagerRefTest : public testing::Test {
}
// Returns all the references where |surface_id| is the parent.
- const SurfaceManager::SurfaceIdSet& GetReferencesFrom(
+ const base::flat_set<SurfaceId>& GetReferencesFrom(
const SurfaceId& surface_id) {
return manager().parent_to_child_refs_[surface_id];
}
// Returns all the references where |surface_id| is the child.
- const SurfaceManager::SurfaceIdSet& GetReferencesFor(
+ const base::flat_set<SurfaceId>& GetReferencesFor(
const SurfaceId& surface_id) {
return manager().child_to_parent_refs_[surface_id];
}
@@ -110,7 +112,7 @@ class SurfaceManagerRefTest : public testing::Test {
}
void TearDown() override {
for (auto& support : supports_)
- support.second->EvictFrame();
+ support.second->EvictCurrentSurface();
supports_.clear();
manager_.reset();
}
diff --git a/chromium/cc/surfaces/surface_manager_unittest.cc b/chromium/cc/surfaces/surface_manager_unittest.cc
index 6142560acb4..4dbce5d094e 100644
--- a/chromium/cc/surfaces/surface_manager_unittest.cc
+++ b/chromium/cc/surfaces/surface_manager_unittest.cc
@@ -5,25 +5,27 @@
#include <stddef.h>
#include "cc/scheduler/begin_frame_source.h"
-#include "cc/surfaces/surface_factory_client.h"
+#include "cc/surfaces/frame_sink_manager_client.h"
#include "cc/surfaces/surface_manager.h"
+#include "cc/test/begin_frame_source_test.h"
+#include "cc/test/fake_external_begin_frame_source.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cc {
-class FakeSurfaceFactoryClient : public SurfaceFactoryClient {
+class FakeFrameSinkManagerClient : public FrameSinkManagerClient {
public:
- explicit FakeSurfaceFactoryClient(const FrameSinkId& frame_sink_id)
+ explicit FakeFrameSinkManagerClient(const FrameSinkId& frame_sink_id)
: source_(nullptr), manager_(nullptr), frame_sink_id_(frame_sink_id) {}
- FakeSurfaceFactoryClient(const FrameSinkId& frame_sink_id,
- SurfaceManager* manager)
+ FakeFrameSinkManagerClient(const FrameSinkId& frame_sink_id,
+ SurfaceManager* manager)
: source_(nullptr), manager_(nullptr), frame_sink_id_(frame_sink_id) {
DCHECK(manager);
Register(manager);
}
- ~FakeSurfaceFactoryClient() override {
+ ~FakeFrameSinkManagerClient() override {
if (manager_) {
Unregister();
}
@@ -36,21 +38,20 @@ class FakeSurfaceFactoryClient : public SurfaceFactoryClient {
void Register(SurfaceManager* manager) {
EXPECT_EQ(nullptr, manager_);
manager_ = manager;
- manager_->RegisterSurfaceFactoryClient(frame_sink_id_, this);
+ manager_->RegisterFrameSinkManagerClient(frame_sink_id_, this);
}
void Unregister() {
EXPECT_NE(manager_, nullptr);
- manager_->UnregisterSurfaceFactoryClient(frame_sink_id_);
+ manager_->UnregisterFrameSinkManagerClient(frame_sink_id_);
manager_ = nullptr;
}
- // SurfaceFactoryClient implementation.
- void ReturnResources(const ReturnedResourceArray& resources) override {}
+ // FrameSinkManagerClient implementation.
void SetBeginFrameSource(BeginFrameSource* begin_frame_source) override {
DCHECK(!source_ || !begin_frame_source);
source_ = begin_frame_source;
- };
+ }
private:
BeginFrameSource* source_;
@@ -80,8 +81,8 @@ class SurfaceManagerTest : public testing::Test {
};
TEST_F(SurfaceManagerTest, SingleClients) {
- FakeSurfaceFactoryClient client(FrameSinkId(1, 1));
- FakeSurfaceFactoryClient other_client(FrameSinkId(2, 2));
+ FakeFrameSinkManagerClient client(FrameSinkId(1, 1));
+ FakeFrameSinkManagerClient other_client(FrameSinkId(2, 2));
StubBeginFrameSource source;
EXPECT_EQ(nullptr, client.source());
@@ -114,17 +115,76 @@ TEST_F(SurfaceManagerTest, SingleClients) {
EXPECT_EQ(nullptr, client.source());
}
+// This test verifies that a PrimaryBeginFrameSource will receive BeginFrames
+// from the first BeginFrameSource registered. If that BeginFrameSource goes
+// away then it will receive BeginFrames from the second BeginFrameSource.
+TEST_F(SurfaceManagerTest, PrimaryBeginFrameSource) {
+ // This PrimaryBeginFrameSource should track the first BeginFrameSource
+ // registered with the SurfaceManager.
+ testing::NiceMock<MockBeginFrameObserver> obs;
+ BeginFrameSource* begin_frame_source = manager_.GetPrimaryBeginFrameSource();
+ begin_frame_source->AddObserver(&obs);
+
+ FakeFrameSinkManagerClient root1(FrameSinkId(1, 1), &manager_);
+ std::unique_ptr<FakeExternalBeginFrameSource> external_source1 =
+ base::MakeUnique<FakeExternalBeginFrameSource>(60.f, false);
+ manager_.RegisterBeginFrameSource(external_source1.get(),
+ root1.frame_sink_id());
+
+ FakeFrameSinkManagerClient root2(FrameSinkId(2, 2), &manager_);
+ std::unique_ptr<FakeExternalBeginFrameSource> external_source2 =
+ base::MakeUnique<FakeExternalBeginFrameSource>(60.f, false);
+ manager_.RegisterBeginFrameSource(external_source2.get(),
+ root2.frame_sink_id());
+
+ BeginFrameArgs args =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1);
+
+ // Ticking |external_source2| does not propagate to |begin_frame_source|.
+ {
+ EXPECT_CALL(obs, OnBeginFrame(args)).Times(0);
+ external_source2->TestOnBeginFrame(args);
+ testing::Mock::VerifyAndClearExpectations(&obs);
+ }
+
+ // Ticking |external_source1| does propagate to |begin_frame_source| and
+ // |obs|.
+ {
+ EXPECT_CALL(obs, OnBeginFrame(testing::_)).Times(1);
+ external_source1->TestOnBeginFrame(args);
+ testing::Mock::VerifyAndClearExpectations(&obs);
+ }
+
+ // Getting rid of |external_source1| means those BeginFrames will not
+ // propagate. Instead, |external_source2|'s BeginFrames will propagate
+ // to |begin_frame_source|.
+ {
+ manager_.UnregisterBeginFrameSource(external_source1.get());
+ EXPECT_CALL(obs, OnBeginFrame(testing::_)).Times(0);
+ external_source1->TestOnBeginFrame(args);
+ testing::Mock::VerifyAndClearExpectations(&obs);
+
+ EXPECT_CALL(obs, OnBeginFrame(testing::_)).Times(1);
+ external_source2->TestOnBeginFrame(args);
+ testing::Mock::VerifyAndClearExpectations(&obs);
+ }
+
+ // Tear down
+ manager_.UnregisterBeginFrameSource(external_source2.get());
+ begin_frame_source->RemoveObserver(&obs);
+}
+
TEST_F(SurfaceManagerTest, MultipleDisplays) {
StubBeginFrameSource root1_source;
StubBeginFrameSource root2_source;
// root1 -> A -> B
// root2 -> C
- FakeSurfaceFactoryClient root1(FrameSinkId(1, 1), &manager_);
- FakeSurfaceFactoryClient root2(FrameSinkId(2, 2), &manager_);
- FakeSurfaceFactoryClient client_a(FrameSinkId(3, 3), &manager_);
- FakeSurfaceFactoryClient client_b(FrameSinkId(4, 4), &manager_);
- FakeSurfaceFactoryClient client_c(FrameSinkId(5, 5), &manager_);
+ FakeFrameSinkManagerClient root1(FrameSinkId(1, 1), &manager_);
+ FakeFrameSinkManagerClient root2(FrameSinkId(2, 2), &manager_);
+ FakeFrameSinkManagerClient client_a(FrameSinkId(3, 3), &manager_);
+ FakeFrameSinkManagerClient client_b(FrameSinkId(4, 4), &manager_);
+ FakeFrameSinkManagerClient client_c(FrameSinkId(5, 5), &manager_);
manager_.RegisterBeginFrameSource(&root1_source, root1.frame_sink_id());
manager_.RegisterBeginFrameSource(&root2_source, root2.frame_sink_id());
@@ -183,7 +243,7 @@ TEST_F(SurfaceManagerTest, MultipleDisplays) {
// This test verifies that a BeginFrameSource path to the root from a
// FrameSinkId is preserved even if that FrameSinkId has no children
-// and does not have a corresponding SurfaceFactoryClient.
+// and does not have a corresponding FrameSinkManagerClient.
TEST_F(SurfaceManagerTest, ParentWithoutClientRetained) {
StubBeginFrameSource root_source;
@@ -192,15 +252,15 @@ TEST_F(SurfaceManagerTest, ParentWithoutClientRetained) {
constexpr FrameSinkId kFrameSinkIdB(3, 3);
constexpr FrameSinkId kFrameSinkIdC(4, 4);
- FakeSurfaceFactoryClient root(kFrameSinkIdRoot, &manager_);
- FakeSurfaceFactoryClient client_b(kFrameSinkIdB, &manager_);
- FakeSurfaceFactoryClient client_c(kFrameSinkIdC, &manager_);
+ FakeFrameSinkManagerClient root(kFrameSinkIdRoot, &manager_);
+ FakeFrameSinkManagerClient client_b(kFrameSinkIdB, &manager_);
+ FakeFrameSinkManagerClient client_c(kFrameSinkIdC, &manager_);
manager_.RegisterBeginFrameSource(&root_source, root.frame_sink_id());
EXPECT_EQ(&root_source, root.source());
// Set up initial hierarchy: root -> A -> B.
- // Note that A does not have a SurfaceFactoryClient.
+ // Note that A does not have a FrameSinkManagerClient.
manager_.RegisterFrameSinkHierarchy(kFrameSinkIdRoot, kFrameSinkIdA);
manager_.RegisterFrameSinkHierarchy(kFrameSinkIdA, kFrameSinkIdB);
// The root's BeginFrameSource should propagate to B.
@@ -231,12 +291,12 @@ TEST_F(SurfaceManagerTest,
constexpr FrameSinkId kFrameSinkIdB(3, 3);
constexpr FrameSinkId kFrameSinkIdC(4, 4);
- FakeSurfaceFactoryClient root(kFrameSinkIdRoot, &manager_);
- FakeSurfaceFactoryClient client_b(kFrameSinkIdB, &manager_);
- FakeSurfaceFactoryClient client_c(kFrameSinkIdC, &manager_);
+ FakeFrameSinkManagerClient root(kFrameSinkIdRoot, &manager_);
+ FakeFrameSinkManagerClient client_b(kFrameSinkIdB, &manager_);
+ FakeFrameSinkManagerClient client_c(kFrameSinkIdC, &manager_);
// Set up initial hierarchy: root -> A -> B.
- // Note that A does not have a SurfaceFactoryClient.
+ // Note that A does not have a FrameSinkManagerClient.
manager_.RegisterFrameSinkHierarchy(kFrameSinkIdRoot, kFrameSinkIdA);
manager_.RegisterFrameSinkHierarchy(kFrameSinkIdA, kFrameSinkIdB);
// The root does not yet have a BeginFrameSource so client B should not have
@@ -259,7 +319,7 @@ TEST_F(SurfaceManagerTest,
}
// In practice, registering and unregistering both parent/child relationships
-// and SurfaceFactoryClients can happen in any ordering with respect to
+// and FrameSinkManagerClients can happen in any ordering with respect to
// each other. These following tests verify that all the data structures
// are properly set up and cleaned up under the four permutations of orderings
// of this nesting.
@@ -364,9 +424,9 @@ class SurfaceManagerOrderingTest : public SurfaceManagerTest {
StubBeginFrameSource source_;
// A -> B -> C hierarchy, with A always having the BFS.
- FakeSurfaceFactoryClient client_a_;
- FakeSurfaceFactoryClient client_b_;
- FakeSurfaceFactoryClient client_c_;
+ FakeFrameSinkManagerClient client_a_;
+ FakeFrameSinkManagerClient client_b_;
+ FakeFrameSinkManagerClient client_c_;
bool hierarchy_registered_;
bool clients_registered_;
diff --git a/chromium/cc/surfaces/surface_observer.h b/chromium/cc/surfaces/surface_observer.h
index e1c182a45c5..9b2fc1c57f6 100644
--- a/chromium/cc/surfaces/surface_observer.h
+++ b/chromium/cc/surfaces/surface_observer.h
@@ -18,6 +18,9 @@ class SurfaceObserver {
// Runs when a Surface is damaged. *changed should be set to true if this
// causes a Display to be damaged.
virtual void OnSurfaceDamaged(const SurfaceId& surface_id, bool* changed) = 0;
+
+ // Called when a surface is garbage-collected.
+ virtual void OnSurfaceDiscarded(const SurfaceId& surface_id) = 0;
};
} // namespace cc
diff --git a/chromium/cc/surfaces/surface_resource_holder.cc b/chromium/cc/surfaces/surface_resource_holder.cc
index 6d1e60d0c6a..8d46b25fd03 100644
--- a/chromium/cc/surfaces/surface_resource_holder.cc
+++ b/chromium/cc/surfaces/surface_resource_holder.cc
@@ -4,20 +4,17 @@
#include "cc/surfaces/surface_resource_holder.h"
-#include "cc/surfaces/surface_factory_client.h"
-
+#include "cc/surfaces/surface_resource_holder_client.h"
namespace cc {
-SurfaceResourceHolder::SurfaceResourceHolder(SurfaceFactoryClient* client)
- : client_(client) {
-}
+SurfaceResourceHolder::SurfaceResourceHolder(
+ SurfaceResourceHolderClient* client)
+ : client_(client) {}
-SurfaceResourceHolder::~SurfaceResourceHolder() {
-}
+SurfaceResourceHolder::~SurfaceResourceHolder() = default;
SurfaceResourceHolder::ResourceRefs::ResourceRefs()
- : refs_received_from_child(0), refs_holding_resource_alive(0) {
-}
+ : refs_received_from_child(0), refs_holding_resource_alive(0) {}
void SurfaceResourceHolder::Reset() {
resource_id_info_map_.clear();
@@ -25,10 +22,8 @@ void SurfaceResourceHolder::Reset() {
void SurfaceResourceHolder::ReceiveFromChild(
const TransferableResourceArray& resources) {
- for (TransferableResourceArray::const_iterator it = resources.begin();
- it != resources.end();
- ++it) {
- ResourceRefs& ref = resource_id_info_map_[it->id];
+ for (const auto& resource : resources) {
+ ResourceRefs& ref = resource_id_info_map_[resource.id];
ref.refs_holding_resource_alive++;
ref.refs_received_from_child++;
}
diff --git a/chromium/cc/surfaces/surface_resource_holder.h b/chromium/cc/surfaces/surface_resource_holder.h
index 5d222864e8b..e40f4945600 100644
--- a/chromium/cc/surfaces/surface_resource_holder.h
+++ b/chromium/cc/surfaces/surface_resource_holder.h
@@ -14,7 +14,7 @@
#include "cc/surfaces/surfaces_export.h"
namespace cc {
-class SurfaceFactoryClient;
+class SurfaceResourceHolderClient;
// A SurfaceResourceHolder manages the lifetime of resources submitted by a
// particular SurfaceFactory. Each resource is held by the service until
@@ -22,7 +22,7 @@ class SurfaceFactoryClient;
// resource providers.
class CC_SURFACES_EXPORT SurfaceResourceHolder {
public:
- explicit SurfaceResourceHolder(SurfaceFactoryClient* client);
+ explicit SurfaceResourceHolder(SurfaceResourceHolderClient* client);
~SurfaceResourceHolder();
void Reset();
@@ -31,7 +31,7 @@ class CC_SURFACES_EXPORT SurfaceResourceHolder {
void UnrefResources(const ReturnedResourceArray& resources);
private:
- SurfaceFactoryClient* client_;
+ SurfaceResourceHolderClient* client_;
struct ResourceRefs {
ResourceRefs();
diff --git a/chromium/cc/surfaces/surface_resource_holder_client.h b/chromium/cc/surfaces/surface_resource_holder_client.h
new file mode 100644
index 00000000000..2a9c78d86c2
--- /dev/null
+++ b/chromium/cc/surfaces/surface_resource_holder_client.h
@@ -0,0 +1,23 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#ifndef CC_SURFACES_SURFACE_RESOURCE_HOLDER_CLIENT_H_
+#define CC_SURFACES_SURFACE_RESOURCE_HOLDER_CLIENT_H_
+
+#include "cc/resources/returned_resource.h"
+#include "cc/surfaces/surfaces_export.h"
+
+namespace cc {
+
+class CC_SURFACES_EXPORT SurfaceResourceHolderClient {
+ public:
+ virtual ~SurfaceResourceHolderClient() = default;
+
+ // ReturnResources gets called when the display compositor is done using the
+ // resources so that the client can use them.
+ virtual void ReturnResources(const ReturnedResourceArray& resources) = 0;
+};
+
+} // namespace cc
+
+#endif // CC_SURFACES_SURFACE_RESOURCE_HOLDER_CLIENT_H_
diff --git a/chromium/cc/surfaces/surface_synchronization_unittest.cc b/chromium/cc/surfaces/surface_synchronization_unittest.cc
new file mode 100644
index 00000000000..3117f69be63
--- /dev/null
+++ b/chromium/cc/surfaces/surface_synchronization_unittest.cc
@@ -0,0 +1,1394 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/containers/flat_set.h"
+#include "cc/surfaces/compositor_frame_sink_support.h"
+#include "cc/surfaces/surface_id.h"
+#include "cc/surfaces/surface_manager.h"
+#include "cc/surfaces/surface_observer.h"
+#include "cc/test/begin_frame_args_test.h"
+#include "cc/test/compositor_frame_helpers.h"
+#include "cc/test/fake_external_begin_frame_source.h"
+#include "cc/test/mock_compositor_frame_sink_support_client.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::Eq;
+using testing::IsEmpty;
+using testing::UnorderedElementsAre;
+
+namespace cc {
+namespace test {
+namespace {
+
+constexpr bool kIsRoot = true;
+constexpr bool kIsChildRoot = false;
+constexpr bool kHandlesFrameSinkIdInvalidation = true;
+constexpr bool kNeedsSyncPoints = true;
+constexpr FrameSinkId kDisplayFrameSink(2, 0);
+constexpr FrameSinkId kParentFrameSink(3, 0);
+constexpr FrameSinkId kChildFrameSink1(65563, 0);
+constexpr FrameSinkId kChildFrameSink2(65564, 0);
+constexpr FrameSinkId kArbitraryFrameSink(1337, 7331);
+
+std::vector<SurfaceId> empty_surface_ids() {
+ return std::vector<SurfaceId>();
+}
+
+SurfaceId MakeSurfaceId(const FrameSinkId& frame_sink_id, uint32_t local_id) {
+ return SurfaceId(
+ frame_sink_id,
+ LocalSurfaceId(local_id, base::UnguessableToken::Deserialize(0, 1u)));
+}
+
+} // namespace
+
+class SurfaceSynchronizationTest : public testing::Test,
+ public SurfaceObserver {
+ public:
+ SurfaceSynchronizationTest()
+ : surface_manager_(SurfaceManager::LifetimeType::REFERENCES) {}
+ ~SurfaceSynchronizationTest() override {}
+
+ CompositorFrameSinkSupport& display_support() { return *supports_[0]; }
+ Surface* display_surface() {
+ return display_support().current_surface_for_testing();
+ }
+
+ CompositorFrameSinkSupport& parent_support() { return *supports_[1]; }
+ Surface* parent_surface() {
+ return parent_support().current_surface_for_testing();
+ }
+ const ReferencedSurfaceTracker& parent_reference_tracker() {
+ return parent_support().ReferenceTrackerForTesting();
+ }
+
+ CompositorFrameSinkSupport& child_support1() { return *supports_[2]; }
+ Surface* child_surface1() {
+ return child_support1().current_surface_for_testing();
+ }
+
+ CompositorFrameSinkSupport& child_support2() { return *supports_[3]; }
+ Surface* child_surface2() {
+ return child_support2().current_surface_for_testing();
+ }
+
+ CompositorFrameSinkSupport& support(int index) { return *supports_[index]; }
+ Surface* surface(int index) {
+ return support(index).current_surface_for_testing();
+ }
+
+ SurfaceManager& surface_manager() { return surface_manager_; }
+
+ // Returns all the references where |surface_id| is the parent.
+ const base::flat_set<SurfaceId>& GetChildReferences(
+ const SurfaceId& surface_id) {
+ return surface_manager().parent_to_child_refs_[surface_id];
+ }
+
+ // Returns true if there is a temporary reference for |surface_id|.
+ bool HasTemporaryReference(const SurfaceId& surface_id) {
+ return surface_manager().HasTemporaryReference(surface_id);
+ }
+
+ SurfaceDependencyTracker& dependency_tracker() {
+ return *surface_manager_.dependency_tracker();
+ }
+
+ FakeExternalBeginFrameSource* begin_frame_source() {
+ return begin_frame_source_.get();
+ }
+
+ // testing::Test:
+ void SetUp() override {
+ testing::Test::SetUp();
+
+ begin_frame_source_ =
+ base::MakeUnique<FakeExternalBeginFrameSource>(0.f, false);
+ dependency_tracker_ = base::MakeUnique<SurfaceDependencyTracker>(
+ &surface_manager_, begin_frame_source_.get());
+ surface_manager_.SetDependencyTracker(dependency_tracker_.get());
+ surface_manager_.AddObserver(this);
+ supports_.push_back(CompositorFrameSinkSupport::Create(
+ &support_client_, &surface_manager_, kDisplayFrameSink, kIsRoot,
+ kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints));
+ supports_.push_back(CompositorFrameSinkSupport::Create(
+ &support_client_, &surface_manager_, kParentFrameSink, kIsChildRoot,
+ kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints));
+ supports_.push_back(CompositorFrameSinkSupport::Create(
+ &support_client_, &surface_manager_, kChildFrameSink1, kIsChildRoot,
+ kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints));
+ supports_.push_back(CompositorFrameSinkSupport::Create(
+ &support_client_, &surface_manager_, kChildFrameSink2, kIsChildRoot,
+ kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints));
+
+ // Normally, the BeginFrameSource would be registered by the Display. We
+ // register it here so that BeginFrames are received by the display support,
+ // for use in the PassesOnBeginFrameAcks test. Other supports do not receive
+ // BeginFrames, since the frame sink hierarchy is not set up in this test.
+ surface_manager_.RegisterBeginFrameSource(begin_frame_source_.get(),
+ kDisplayFrameSink);
+ }
+
+ void TearDown() override {
+ surface_manager_.RemoveObserver(this);
+ surface_manager_.SetDependencyTracker(nullptr);
+ surface_manager_.UnregisterBeginFrameSource(begin_frame_source_.get());
+
+ dependency_tracker_.reset();
+
+ // SurfaceDependencyTracker depends on this BeginFrameSource and so it must
+ // be destroyed AFTER the dependency tracker is destroyed.
+ begin_frame_source_.reset();
+
+ supports_.clear();
+
+ damaged_surfaces_.clear();
+ }
+
+ bool IsSurfaceDamaged(const SurfaceId& surface_id) const {
+ return damaged_surfaces_.count(surface_id) > 0;
+ }
+
+ // SurfaceObserver implementation:
+ void OnSurfaceCreated(const SurfaceInfo& surface_info) override {}
+ void OnSurfaceDamaged(const SurfaceId& surface_id, bool* changed) override {
+ damaged_surfaces_.insert(surface_id);
+ }
+ void OnSurfaceDiscarded(const SurfaceId& surface_id) override {}
+
+ protected:
+ testing::NiceMock<MockCompositorFrameSinkSupportClient> support_client_;
+
+ private:
+ base::flat_set<SurfaceId> damaged_surfaces_;
+ SurfaceManager surface_manager_;
+ std::unique_ptr<FakeExternalBeginFrameSource> begin_frame_source_;
+ std::unique_ptr<SurfaceDependencyTracker> dependency_tracker_;
+ std::vector<std::unique_ptr<CompositorFrameSinkSupport>> supports_;
+
+ DISALLOW_COPY_AND_ASSIGN(SurfaceSynchronizationTest);
+};
+
+// The display root surface should have a surface reference from the top-level
+// root added/removed when a CompositorFrame is submitted with a new SurfaceId.
+TEST_F(SurfaceSynchronizationTest, RootSurfaceReceivesReferences) {
+ const SurfaceId display_id_first = MakeSurfaceId(kDisplayFrameSink, 1);
+ const SurfaceId display_id_second = MakeSurfaceId(kDisplayFrameSink, 2);
+
+ // Submit a CompositorFrame for the first display root surface.
+ display_support().SubmitCompositorFrame(display_id_first.local_surface_id(),
+ MakeCompositorFrame());
+
+ // A surface reference from the top-level root is added and there shouldn't be
+ // a temporary reference.
+ EXPECT_FALSE(HasTemporaryReference(display_id_first));
+ EXPECT_THAT(GetChildReferences(surface_manager().GetRootSurfaceId()),
+ UnorderedElementsAre(display_id_first));
+
+ // Submit a CompositorFrame for the second display root surface.
+ display_support().SubmitCompositorFrame(display_id_second.local_surface_id(),
+ MakeCompositorFrame());
+
+ // A surface reference from the top-level root to |display_id_second| should
+ // be added and the reference to |display_root_first| removed.
+ EXPECT_FALSE(HasTemporaryReference(display_id_second));
+ EXPECT_THAT(GetChildReferences(surface_manager().GetRootSurfaceId()),
+ UnorderedElementsAre(display_id_second));
+
+ // Surface |display_id_first| is unreachable and should get deleted.
+ EXPECT_EQ(nullptr, surface_manager().GetSurfaceForId(display_id_first));
+}
+
+// The parent Surface is blocked on |child_id1| and |child_id2|.
+TEST_F(SurfaceSynchronizationTest, BlockedOnTwo) {
+ const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
+ const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
+ const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1);
+
+ parent_support().SubmitCompositorFrame(
+ parent_id.local_surface_id(),
+ MakeCompositorFrame({child_id1, child_id2}, empty_surface_ids(),
+ TransferableResourceArray()));
+
+ // parent_support is blocked on |child_id1| and |child_id2|.
+ EXPECT_TRUE(dependency_tracker().has_deadline());
+ EXPECT_FALSE(parent_surface()->HasActiveFrame());
+ EXPECT_TRUE(parent_surface()->HasPendingFrame());
+ EXPECT_THAT(parent_surface()->blocking_surfaces(),
+ UnorderedElementsAre(child_id1, child_id2));
+
+ // Submit a CompositorFrame without any dependencies to |child_id1|.
+ // parent_support should now only be blocked on |child_id2|.
+ child_support1().SubmitCompositorFrame(child_id1.local_surface_id(),
+ MakeCompositorFrame());
+
+ EXPECT_TRUE(dependency_tracker().has_deadline());
+ EXPECT_FALSE(parent_surface()->HasActiveFrame());
+ EXPECT_TRUE(parent_surface()->HasPendingFrame());
+ EXPECT_THAT(parent_surface()->blocking_surfaces(),
+ UnorderedElementsAre(child_id2));
+
+ // Submit a CompositorFrame without any dependencies to |child_id2|.
+ // parent_support should be activated.
+ child_support2().SubmitCompositorFrame(child_id2.local_surface_id(),
+ MakeCompositorFrame());
+
+ EXPECT_FALSE(dependency_tracker().has_deadline());
+ EXPECT_TRUE(parent_surface()->HasActiveFrame());
+ EXPECT_FALSE(parent_surface()->HasPendingFrame());
+ EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty());
+}
+
+// The parent Surface is blocked on |child_id2| which is blocked on |child_id3|.
+TEST_F(SurfaceSynchronizationTest, BlockedChain) {
+ const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
+ const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
+ const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1);
+
+ parent_support().SubmitCompositorFrame(
+ parent_id.local_surface_id(),
+ MakeCompositorFrame({child_id1}, empty_surface_ids(),
+ TransferableResourceArray()));
+
+ // parent_support is blocked on |child_id1|.
+ EXPECT_TRUE(dependency_tracker().has_deadline());
+ EXPECT_FALSE(parent_surface()->HasActiveFrame());
+ EXPECT_TRUE(parent_surface()->HasPendingFrame());
+ EXPECT_THAT(parent_surface()->blocking_surfaces(),
+ UnorderedElementsAre(child_id1));
+ // The parent should not report damage until it activates.
+ EXPECT_FALSE(IsSurfaceDamaged(parent_id));
+
+ child_support1().SubmitCompositorFrame(
+ child_id1.local_surface_id(),
+ MakeCompositorFrame({child_id2}, empty_surface_ids(),
+ TransferableResourceArray()));
+
+ // child_support1 should now be blocked on |child_id2|.
+ EXPECT_TRUE(dependency_tracker().has_deadline());
+ EXPECT_FALSE(child_surface1()->HasActiveFrame());
+ EXPECT_TRUE(child_surface1()->HasPendingFrame());
+ EXPECT_THAT(child_surface1()->blocking_surfaces(),
+ UnorderedElementsAre(child_id2));
+ // The parent and child should not report damage until they activate.
+ EXPECT_FALSE(IsSurfaceDamaged(parent_id));
+ EXPECT_FALSE(IsSurfaceDamaged(child_id1));
+
+ // The parent should still be blocked on |child_id1| because it's pending.
+ EXPECT_THAT(parent_surface()->blocking_surfaces(),
+ UnorderedElementsAre(child_id1));
+
+ // Submit a CompositorFrame without any dependencies to |child_id2|.
+ // parent_support should be activated.
+ child_support2().SubmitCompositorFrame(
+ child_id2.local_surface_id(),
+ MakeCompositorFrame(empty_surface_ids(), empty_surface_ids(),
+ TransferableResourceArray()));
+
+ EXPECT_FALSE(dependency_tracker().has_deadline());
+
+ // child_surface1 should now be active.
+ EXPECT_TRUE(child_surface1()->HasActiveFrame());
+ EXPECT_FALSE(child_surface1()->HasPendingFrame());
+ EXPECT_THAT(child_surface1()->blocking_surfaces(), IsEmpty());
+
+ // parent_surface should now be active.
+ EXPECT_TRUE(parent_surface()->HasActiveFrame());
+ EXPECT_FALSE(parent_surface()->HasPendingFrame());
+ EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty());
+
+ // All three surfaces |parent_id|, |child_id1|, and |child_id2| should
+ // now report damage. This would trigger a new display frame.
+ EXPECT_TRUE(IsSurfaceDamaged(parent_id));
+ EXPECT_TRUE(IsSurfaceDamaged(child_id1));
+ EXPECT_TRUE(IsSurfaceDamaged(child_id2));
+}
+
+// parent_surface and child_surface1 are blocked on |child_id2|.
+TEST_F(SurfaceSynchronizationTest, TwoBlockedOnOne) {
+ const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
+ const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
+ const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1);
+
+ parent_support().SubmitCompositorFrame(
+ parent_id.local_surface_id(),
+ MakeCompositorFrame({child_id2}, empty_surface_ids(),
+ TransferableResourceArray()));
+
+ // parent_support is blocked on |child_id2|.
+ EXPECT_TRUE(dependency_tracker().has_deadline());
+ EXPECT_FALSE(parent_surface()->HasActiveFrame());
+ EXPECT_TRUE(parent_surface()->HasPendingFrame());
+ EXPECT_THAT(parent_surface()->blocking_surfaces(),
+ UnorderedElementsAre(child_id2));
+
+ // child_support1 should now be blocked on |child_id2|.
+ child_support1().SubmitCompositorFrame(
+ child_id1.local_surface_id(),
+ MakeCompositorFrame({child_id2}, empty_surface_ids(),
+ TransferableResourceArray()));
+
+ EXPECT_TRUE(dependency_tracker().has_deadline());
+ EXPECT_FALSE(child_surface1()->HasActiveFrame());
+ EXPECT_TRUE(child_surface1()->HasPendingFrame());
+ EXPECT_THAT(child_surface1()->blocking_surfaces(),
+ UnorderedElementsAre(child_id2));
+
+ // The parent should still be blocked on |child_id2|.
+ EXPECT_THAT(parent_surface()->blocking_surfaces(),
+ UnorderedElementsAre(child_id2));
+
+ // Submit a CompositorFrame without any dependencies to |child_id2|.
+ // parent_support should be activated.
+ child_support2().SubmitCompositorFrame(child_id2.local_surface_id(),
+ MakeCompositorFrame());
+
+ EXPECT_FALSE(dependency_tracker().has_deadline());
+
+ // child_surface1 should now be active.
+ EXPECT_TRUE(child_surface1()->HasActiveFrame());
+ EXPECT_FALSE(child_surface1()->HasPendingFrame());
+ EXPECT_THAT(child_surface1()->blocking_surfaces(), IsEmpty());
+
+ // parent_surface should now be active.
+ EXPECT_TRUE(parent_surface()->HasActiveFrame());
+ EXPECT_FALSE(parent_surface()->HasPendingFrame());
+ EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty());
+}
+
+// parent_surface is blocked on |child_id1|, and child_surface2 is blocked on
+// |child_id2| until the deadline hits.
+TEST_F(SurfaceSynchronizationTest, DeadlineHits) {
+ const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
+ const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
+ const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1);
+
+ parent_support().SubmitCompositorFrame(
+ parent_id.local_surface_id(),
+ MakeCompositorFrame({child_id1}, empty_surface_ids(),
+ TransferableResourceArray()));
+
+ // parent_support is blocked on |child_id1|.
+ EXPECT_TRUE(dependency_tracker().has_deadline());
+ EXPECT_FALSE(parent_surface()->HasActiveFrame());
+ EXPECT_TRUE(parent_surface()->HasPendingFrame());
+ EXPECT_THAT(parent_surface()->blocking_surfaces(),
+ UnorderedElementsAre(child_id1));
+
+ child_support1().SubmitCompositorFrame(
+ child_id1.local_surface_id(),
+ MakeCompositorFrame({child_id2}, empty_surface_ids(),
+ TransferableResourceArray()));
+
+ // child_support1 should now be blocked on |child_id2|.
+ EXPECT_TRUE(dependency_tracker().has_deadline());
+ EXPECT_FALSE(child_surface1()->HasActiveFrame());
+ EXPECT_TRUE(child_surface1()->HasPendingFrame());
+ EXPECT_THAT(child_surface1()->blocking_surfaces(),
+ UnorderedElementsAre(child_id2));
+
+ // The parent should still be blocked on |child_id1| because it's pending.
+ EXPECT_THAT(parent_surface()->blocking_surfaces(),
+ UnorderedElementsAre(child_id1));
+
+ BeginFrameArgs args =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1);
+
+ for (int i = 0; i < 3; ++i) {
+ begin_frame_source()->TestOnBeginFrame(args);
+ // There is still a looming deadline! Eeek!
+ EXPECT_TRUE(dependency_tracker().has_deadline());
+
+ // parent_support is still blocked on |child_id1|.
+ EXPECT_FALSE(parent_surface()->HasActiveFrame());
+ EXPECT_TRUE(parent_surface()->HasPendingFrame());
+ EXPECT_THAT(parent_surface()->blocking_surfaces(),
+ UnorderedElementsAre(child_id1));
+
+ // child_support1 is still blocked on |child_id2|.
+ EXPECT_FALSE(child_surface1()->HasActiveFrame());
+ EXPECT_TRUE(child_surface1()->HasPendingFrame());
+ EXPECT_THAT(child_surface1()->blocking_surfaces(),
+ UnorderedElementsAre(child_id2));
+ }
+
+ begin_frame_source()->TestOnBeginFrame(args);
+
+ // The deadline has passed.
+ EXPECT_FALSE(dependency_tracker().has_deadline());
+
+ // parent_surface has been activated.
+ EXPECT_TRUE(parent_surface()->HasActiveFrame());
+ EXPECT_FALSE(parent_surface()->HasPendingFrame());
+ EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty());
+
+ // child_surface1 has been activated.
+ EXPECT_TRUE(child_surface1()->HasActiveFrame());
+ EXPECT_FALSE(child_surface1()->HasPendingFrame());
+ EXPECT_THAT(child_surface1()->blocking_surfaces(), IsEmpty());
+}
+
+// Verifies that the deadline does not reset if we submit CompositorFrames
+// to new Surfaces with unresolved dependencies.
+TEST_F(SurfaceSynchronizationTest, FramesSubmittedAfterDeadlineSet) {
+ const SurfaceId arbitrary_id = MakeSurfaceId(kArbitraryFrameSink, 1);
+ BeginFrameArgs args =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1);
+ for (int i = 0; i < 3; ++i) {
+ LocalSurfaceId local_surface_id(1, base::UnguessableToken::Create());
+ support(i).SubmitCompositorFrame(
+ local_surface_id,
+ MakeCompositorFrame({arbitrary_id}, empty_surface_ids(),
+ TransferableResourceArray()));
+ // The deadline has been set.
+ EXPECT_TRUE(dependency_tracker().has_deadline());
+
+ // support(i) should be blocked on arbitrary_id.
+ EXPECT_FALSE(surface(i)->HasActiveFrame());
+ EXPECT_TRUE(surface(i)->HasPendingFrame());
+ EXPECT_THAT(surface(i)->blocking_surfaces(),
+ UnorderedElementsAre(arbitrary_id));
+
+ // Issue a BeginFrame to get closer to the deadline.
+ begin_frame_source()->TestOnBeginFrame(args);
+ }
+
+ // The deadline hits and all the Surfaces should activate.
+ begin_frame_source()->TestOnBeginFrame(args);
+ for (int i = 0; i < 3; ++i) {
+ EXPECT_TRUE(surface(i)->HasActiveFrame());
+ EXPECT_FALSE(surface(i)->HasPendingFrame());
+ EXPECT_THAT(surface(i)->blocking_surfaces(), IsEmpty());
+ }
+}
+
+// This test verifies at the Surface activates once a CompositorFrame is
+// submitted that has no unresolved dependencies.
+TEST_F(SurfaceSynchronizationTest, NewFrameOverridesOldDependencies) {
+ const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
+ const SurfaceId arbitrary_id = MakeSurfaceId(kArbitraryFrameSink, 1);
+
+ // Submit a CompositorFrame that depends on |arbitrary_id|.
+ parent_support().SubmitCompositorFrame(
+ parent_id.local_surface_id(),
+ MakeCompositorFrame({arbitrary_id}, empty_surface_ids(),
+ TransferableResourceArray()));
+
+ // Verify that the CompositorFrame is blocked on |arbitrary_id|.
+ EXPECT_FALSE(parent_surface()->HasActiveFrame());
+ EXPECT_TRUE(parent_surface()->HasPendingFrame());
+ EXPECT_THAT(parent_surface()->blocking_surfaces(),
+ UnorderedElementsAre(arbitrary_id));
+
+ // Submit a CompositorFrame that has no dependencies.
+ parent_support().SubmitCompositorFrame(parent_id.local_surface_id(),
+ MakeCompositorFrame());
+
+ // Verify that the CompositorFrame has been activated.
+ EXPECT_TRUE(parent_surface()->HasActiveFrame());
+ EXPECT_FALSE(parent_surface()->HasPendingFrame());
+ EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty());
+}
+
+// This test verifies that a pending CompositorFrame does not affect surface
+// references. A new surface from a child will continue to exist as a temporary
+// reference until the parent's frame activates.
+TEST_F(SurfaceSynchronizationTest, OnlyActiveFramesAffectSurfaceReferences) {
+ const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
+ const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
+ const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1);
+
+ // child_support1 submits a CompositorFrame without any dependencies.
+ // DidReceiveCompositorFrameAck should call on immediate activation.
+ EXPECT_CALL(support_client_, DidReceiveCompositorFrameAck(_)).Times(1);
+ child_support1().SubmitCompositorFrame(child_id1.local_surface_id(),
+ MakeCompositorFrame());
+ testing::Mock::VerifyAndClearExpectations(&support_client_);
+
+ // Verify that the child surface is not blocked.
+ EXPECT_TRUE(child_surface1()->HasActiveFrame());
+ EXPECT_FALSE(child_surface1()->HasPendingFrame());
+ EXPECT_THAT(child_surface1()->blocking_surfaces(), IsEmpty());
+
+ // Verify that there's a temporary reference for |child_id1|.
+ EXPECT_TRUE(HasTemporaryReference(child_id1));
+
+ // parent_support submits a CompositorFrame that depends on |child_id1|
+ // (which is already active) and |child_id2|. Thus, the parent should not
+ // activate immediately. DidReceiveCompositorFrameAck should not be called
+ // immediately because the parent CompositorFrame is also blocked on
+ // |child_id2|.
+ EXPECT_CALL(support_client_, DidReceiveCompositorFrameAck(_)).Times(0);
+ parent_support().SubmitCompositorFrame(
+ parent_id.local_surface_id(),
+ MakeCompositorFrame({child_id2}, {child_id1},
+ TransferableResourceArray()));
+ EXPECT_FALSE(parent_surface()->HasActiveFrame());
+ EXPECT_TRUE(parent_surface()->HasPendingFrame());
+ EXPECT_THAT(parent_surface()->blocking_surfaces(),
+ UnorderedElementsAre(child_id2));
+ EXPECT_THAT(GetChildReferences(parent_id), IsEmpty());
+ testing::Mock::VerifyAndClearExpectations(&support_client_);
+
+ // Verify that there's a temporary reference for |child_id1| that still
+ // exists.
+ EXPECT_TRUE(HasTemporaryReference(child_id1));
+
+ // child_support2 submits a CompositorFrame without any dependencies.
+ // Both the child and the parent should immediately ACK CompositorFrames
+ // on activation.
+ EXPECT_CALL(support_client_, DidReceiveCompositorFrameAck(_)).Times(2);
+ child_support2().SubmitCompositorFrame(child_id2.local_surface_id(),
+ MakeCompositorFrame());
+ testing::Mock::VerifyAndClearExpectations(&support_client_);
+
+ // Verify that the child surface is not blocked.
+ EXPECT_TRUE(child_surface1()->HasActiveFrame());
+ EXPECT_FALSE(child_surface1()->HasPendingFrame());
+ EXPECT_THAT(child_surface1()->blocking_surfaces(), IsEmpty());
+
+ // Verify that the parent surface's CompositorFrame has activated and that the
+ // temporary reference has been replaced by a permanent one.
+ EXPECT_TRUE(parent_surface()->HasActiveFrame());
+ EXPECT_FALSE(parent_surface()->HasPendingFrame());
+ EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty());
+ EXPECT_FALSE(HasTemporaryReference(child_id1));
+ EXPECT_THAT(GetChildReferences(parent_id), UnorderedElementsAre(child_id1));
+}
+
+// This test verifies that we do not double count returned resources when a
+// CompositorFrame starts out as pending, then becomes active, and then is
+// replaced with another active CompositorFrame.
+TEST_F(SurfaceSynchronizationTest, ResourcesOnlyReturnedOnce) {
+ const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
+ const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 1);
+
+ // The parent submits a CompositorFrame that depends on |child_id| before the
+ // child submits a CompositorFrame. The CompositorFrame also has resources in
+ // its resource list.
+ TransferableResource resource;
+ resource.id = 1337;
+ resource.format = ALPHA_8;
+ resource.filter = 1234;
+ resource.size = gfx::Size(1234, 5678);
+ TransferableResourceArray resource_list = {resource};
+ parent_support().SubmitCompositorFrame(
+ parent_id.local_surface_id(),
+ MakeCompositorFrame({child_id}, empty_surface_ids(), resource_list));
+
+ // Verify that the CompositorFrame is blocked on |child_id|.
+ EXPECT_FALSE(parent_surface()->HasActiveFrame());
+ EXPECT_TRUE(parent_surface()->HasPendingFrame());
+ EXPECT_THAT(parent_surface()->blocking_surfaces(),
+ UnorderedElementsAre(child_id));
+
+ child_support1().SubmitCompositorFrame(
+ child_id.local_surface_id(),
+ MakeCompositorFrame(empty_surface_ids(), empty_surface_ids(),
+ TransferableResourceArray()));
+
+ // Verify that the child CompositorFrame activates immediately.
+ EXPECT_TRUE(child_surface1()->HasActiveFrame());
+ EXPECT_FALSE(child_surface1()->HasPendingFrame());
+ EXPECT_THAT(child_surface1()->blocking_surfaces(), IsEmpty());
+
+ // Verify that the parent has activated.
+ EXPECT_TRUE(parent_surface()->HasActiveFrame());
+ EXPECT_FALSE(parent_surface()->HasPendingFrame());
+ EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty());
+
+ ReturnedResourceArray returned_resources = {resource.ToReturnedResource()};
+ EXPECT_CALL(support_client_,
+ DidReceiveCompositorFrameAck(returned_resources));
+
+ // The parent submits a CompositorFrame without any dependencies. That frame
+ // should activate immediately, replacing the earlier frame. The resource from
+ // the earlier frame should be returned to the client.
+ parent_support().SubmitCompositorFrame(
+ parent_id.local_surface_id(),
+ MakeCompositorFrame({empty_surface_ids()}, {empty_surface_ids()},
+ TransferableResourceArray()));
+ EXPECT_TRUE(parent_surface()->HasActiveFrame());
+ EXPECT_FALSE(parent_surface()->HasPendingFrame());
+ EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty());
+}
+
+// The parent Surface is blocked on |child_id2| which is blocked on |child_id3|.
+// child_support1 evicts its blocked Surface. The parent surface should
+// activate.
+TEST_F(SurfaceSynchronizationTest, EvictSurfaceWithPendingFrame) {
+ const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
+ const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
+ const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1);
+
+ // Submit a CompositorFrame that depends on |child_id1|.
+ parent_support().SubmitCompositorFrame(
+ parent_id1.local_surface_id(),
+ MakeCompositorFrame({child_id1}, empty_surface_ids(),
+ TransferableResourceArray()));
+
+ // Verify that the CompositorFrame is blocked on |child_id1|.
+ EXPECT_FALSE(parent_surface()->HasActiveFrame());
+ EXPECT_TRUE(parent_surface()->HasPendingFrame());
+ EXPECT_THAT(parent_surface()->blocking_surfaces(),
+ UnorderedElementsAre(child_id1));
+
+ // Submit a CompositorFrame that depends on |child_id2|.
+ child_support1().SubmitCompositorFrame(
+ child_id1.local_surface_id(),
+ MakeCompositorFrame({child_id2}, empty_surface_ids(),
+ TransferableResourceArray()));
+
+ // Verify that the CompositorFrame is blocked on |child_id2|.
+ EXPECT_FALSE(child_surface1()->HasActiveFrame());
+ EXPECT_TRUE(child_surface1()->HasPendingFrame());
+ EXPECT_THAT(child_surface1()->blocking_surfaces(),
+ UnorderedElementsAre(child_id2));
+
+ // Evict child_support1's current Surface.
+ // TODO(fsamuel): EvictCurrentSurface => EvictCurrentSurface.
+ child_support1().EvictCurrentSurface();
+
+ // The parent Surface should immediately activate.
+ EXPECT_TRUE(parent_surface()->HasActiveFrame());
+ EXPECT_FALSE(parent_surface()->HasPendingFrame());
+ EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty());
+ EXPECT_FALSE(dependency_tracker().has_deadline());
+}
+
+// This test verifies that if a surface has both a pending and active
+// CompositorFrame and the pending CompositorFrame activates, replacing the
+// existing active CompositorFrame, then the surface reference hierarchy will be
+// updated allowing garbage collection of surfaces that are no longer
+// referenced.
+TEST_F(SurfaceSynchronizationTest, DropStaleReferencesAfterActivation) {
+ const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
+ const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
+ const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1);
+
+ // The parent submits a CompositorFrame that depends on |child_id1| before the
+ // child submits a CompositorFrame.
+ EXPECT_CALL(support_client_, DidReceiveCompositorFrameAck(_)).Times(0);
+ parent_support().SubmitCompositorFrame(
+ parent_id.local_surface_id(),
+ MakeCompositorFrame({child_id1}, empty_surface_ids(),
+ TransferableResourceArray()));
+
+ // Verify that the CompositorFrame is blocked on |child_id|.
+ EXPECT_FALSE(parent_surface()->HasActiveFrame());
+ EXPECT_TRUE(parent_surface()->HasPendingFrame());
+ EXPECT_THAT(parent_surface()->blocking_surfaces(),
+ UnorderedElementsAre(child_id1));
+ testing::Mock::VerifyAndClearExpectations(&support_client_);
+
+ // Verify that no references are added while the CompositorFrame is pending.
+ EXPECT_THAT(GetChildReferences(parent_id), IsEmpty());
+
+ // DidReceiveCompositorFrameAck should get called twice: once for the child
+ // and once for the now active parent CompositorFrame.
+ EXPECT_CALL(support_client_, DidReceiveCompositorFrameAck(_)).Times(2);
+ child_support1().SubmitCompositorFrame(child_id1.local_surface_id(),
+ MakeCompositorFrame());
+ testing::Mock::VerifyAndClearExpectations(&support_client_);
+
+ // Verify that the child CompositorFrame activates immediately.
+ EXPECT_TRUE(child_surface1()->HasActiveFrame());
+ EXPECT_FALSE(child_surface1()->HasPendingFrame());
+ EXPECT_THAT(child_surface1()->blocking_surfaces(), IsEmpty());
+
+ // Verify that the parent Surface has activated.
+ EXPECT_TRUE(parent_surface()->HasActiveFrame());
+ EXPECT_FALSE(parent_surface()->HasPendingFrame());
+ EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty());
+
+ // Submit a new parent CompositorFrame to add a reference.
+ parent_support().SubmitCompositorFrame(
+ parent_id.local_surface_id(),
+ MakeCompositorFrame(empty_surface_ids(), {child_id1},
+ TransferableResourceArray()));
+
+ // Verify that the parent Surface has activated.
+ EXPECT_TRUE(parent_surface()->HasActiveFrame());
+ EXPECT_FALSE(parent_surface()->HasPendingFrame());
+ EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty());
+
+ // Verify that there is no temporary reference for the child and that
+ // the reference from the parent to the child still exists.
+ EXPECT_FALSE(HasTemporaryReference(child_id1));
+ EXPECT_THAT(GetChildReferences(parent_id), UnorderedElementsAre(child_id1));
+
+ // The parent submits another CompositorFrame that depends on |child_id2|.
+ // Submitting a pending CompositorFrame will not trigger a CompositorFrameAck.
+ EXPECT_CALL(support_client_, DidReceiveCompositorFrameAck(_)).Times(0);
+ parent_support().SubmitCompositorFrame(
+ parent_id.local_surface_id(),
+ MakeCompositorFrame({child_id2}, empty_surface_ids(),
+ TransferableResourceArray()));
+ testing::Mock::VerifyAndClearExpectations(&support_client_);
+
+ // The parent surface should now have both a pending and activate
+ // CompositorFrame. Verify that the set of child references from
+ // |parent_id| are only from the active CompositorFrame.
+ EXPECT_TRUE(parent_surface()->HasActiveFrame());
+ EXPECT_TRUE(parent_surface()->HasPendingFrame());
+ EXPECT_THAT(parent_surface()->blocking_surfaces(),
+ UnorderedElementsAre(child_id2));
+ EXPECT_THAT(GetChildReferences(parent_id), UnorderedElementsAre(child_id1));
+
+ child_support2().SubmitCompositorFrame(child_id2.local_surface_id(),
+ MakeCompositorFrame());
+
+ // Verify that the parent Surface has activated and no longer has a pending
+ // CompositorFrame. Also verify that |child_id1| is no longer a child
+ // reference of |parent_id|.
+ EXPECT_TRUE(parent_surface()->HasActiveFrame());
+ EXPECT_FALSE(parent_surface()->HasPendingFrame());
+ EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty());
+ // The parent will not immediately refer to the child until it submits a new
+ // CompositorFrame with the reference.
+ EXPECT_THAT(GetChildReferences(parent_id), IsEmpty());
+}
+
+// Checks whether the latency info are moved to the new surface from the old
+// one when LocalSurfaceId changes. No frame has unresolved dependencies.
+TEST_F(SurfaceSynchronizationTest,
+ LatencyInfoCarriedOverOnResize_NoUnresolvedDependencies) {
+ const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
+ const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2);
+ const ui::LatencyComponentType latency_type1 =
+ ui::BROWSER_SNAPSHOT_FRAME_NUMBER_COMPONENT;
+ const int64_t latency_id1 = 234;
+ const int64_t latency_sequence_number1 = 5645432;
+ const ui::LatencyComponentType latency_type2 = ui::TAB_SHOW_COMPONENT;
+ const int64_t latency_id2 = 31434351;
+ const int64_t latency_sequence_number2 = 663788;
+
+ // Submit a frame with latency info
+ ui::LatencyInfo info;
+ info.AddLatencyNumber(latency_type1, latency_id1, latency_sequence_number1);
+
+ CompositorFrame frame = MakeCompositorFrame();
+ frame.metadata.latency_info.push_back(info);
+
+ parent_support().SubmitCompositorFrame(parent_id1.local_surface_id(),
+ std::move(frame));
+
+ // Verify that the old surface has an active frame and no pending frame.
+ Surface* old_surface = surface_manager().GetSurfaceForId(parent_id1);
+ ASSERT_NE(nullptr, old_surface);
+ EXPECT_TRUE(old_surface->HasActiveFrame());
+ EXPECT_FALSE(old_surface->HasPendingFrame());
+
+ // Submit another frame with some other latency info and a different
+ // LocalSurfaceId.
+ ui::LatencyInfo info2;
+ info2.AddLatencyNumber(latency_type2, latency_id2, latency_sequence_number2);
+
+ CompositorFrame frame2 = MakeCompositorFrame();
+ frame2.metadata.latency_info.push_back(info2);
+
+ parent_support().SubmitCompositorFrame(parent_id2.local_surface_id(),
+ std::move(frame2));
+
+ // Verify that the new surface has an active frame and no pending frames.
+ Surface* surface = surface_manager().GetSurfaceForId(parent_id2);
+ ASSERT_NE(nullptr, surface);
+ EXPECT_TRUE(surface->HasActiveFrame());
+ EXPECT_FALSE(surface->HasPendingFrame());
+
+ // Verify that the new surface has both latency info elements.
+ std::vector<ui::LatencyInfo> info_list;
+ surface->TakeLatencyInfo(&info_list);
+ EXPECT_EQ(2u, info_list.size());
+
+ ui::LatencyInfo aggregated_latency_info = info_list[0];
+ aggregated_latency_info.AddNewLatencyFrom(info_list[1]);
+
+ // Two components are the original ones, and the third one is
+ // DISPLAY_COMPOSITOR_RECEIVED_FRAME_COMPONENT, logged on compositor frame
+ // submit.
+ EXPECT_EQ(3u, aggregated_latency_info.latency_components().size());
+
+ ui::LatencyInfo::LatencyComponent comp1;
+ EXPECT_TRUE(
+ aggregated_latency_info.FindLatency(latency_type1, latency_id1, &comp1));
+ EXPECT_EQ(latency_sequence_number1, comp1.sequence_number);
+ EXPECT_TRUE(
+ aggregated_latency_info.FindLatency(latency_type2, latency_id2, nullptr));
+ EXPECT_TRUE(aggregated_latency_info.FindLatency(
+ ui::DISPLAY_COMPOSITOR_RECEIVED_FRAME_COMPONENT, nullptr));
+}
+
+// Checks whether the latency info are moved to the new surface from the old
+// one when LocalSurfaceId changes. Old surface has unresolved dependencies.
+TEST_F(SurfaceSynchronizationTest,
+ LatencyInfoCarriedOverOnResize_OldSurfaceHasPendingAndActiveFrame) {
+ const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
+ const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2);
+ const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 1);
+
+ const ui::LatencyComponentType latency_type1 =
+ ui::BROWSER_SNAPSHOT_FRAME_NUMBER_COMPONENT;
+ const int64_t latency_id1 = 234;
+ const int64_t latency_sequence_number1 = 5645432;
+ const ui::LatencyComponentType latency_type2 = ui::TAB_SHOW_COMPONENT;
+ const int64_t latency_id2 = 31434351;
+ const int64_t latency_sequence_number2 = 663788;
+
+ // Submit a frame with no unresolved dependecy.
+ ui::LatencyInfo info;
+ info.AddLatencyNumber(latency_type1, latency_id1, latency_sequence_number1);
+
+ CompositorFrame frame = MakeCompositorFrame();
+ frame.metadata.latency_info.push_back(info);
+
+ parent_support().SubmitCompositorFrame(parent_id1.local_surface_id(),
+ std::move(frame));
+
+ // Submit a frame with unresolved dependencies.
+ ui::LatencyInfo info2;
+ info2.AddLatencyNumber(latency_type2, latency_id2, latency_sequence_number2);
+
+ CompositorFrame frame2 = MakeCompositorFrame({child_id}, empty_surface_ids(),
+ TransferableResourceArray());
+ frame2.metadata.latency_info.push_back(info2);
+
+ parent_support().SubmitCompositorFrame(parent_id1.local_surface_id(),
+ std::move(frame2));
+
+ // Verify that the old surface has both an active and a pending frame.
+ Surface* old_surface = surface_manager().GetSurfaceForId(parent_id1);
+ ASSERT_NE(nullptr, old_surface);
+ EXPECT_TRUE(old_surface->HasActiveFrame());
+ EXPECT_TRUE(old_surface->HasPendingFrame());
+
+ // Submit a frame with a new local surface id.
+ parent_support().SubmitCompositorFrame(parent_id2.local_surface_id(),
+ MakeCompositorFrame());
+
+ // Verify that the new surface has an active frame only.
+ Surface* surface = surface_manager().GetSurfaceForId(parent_id2);
+ ASSERT_NE(nullptr, surface);
+ EXPECT_TRUE(surface->HasActiveFrame());
+ EXPECT_FALSE(surface->HasPendingFrame());
+
+ // Verify that the new surface has latency info from both active and pending
+ // frame of the old surface.
+ std::vector<ui::LatencyInfo> info_list;
+ surface->TakeLatencyInfo(&info_list);
+ EXPECT_EQ(2u, info_list.size());
+
+ ui::LatencyInfo aggregated_latency_info = info_list[0];
+ aggregated_latency_info.AddNewLatencyFrom(info_list[1]);
+
+ // Two components are the original ones, and the third one is
+ // DISPLAY_COMPOSITOR_RECEIVED_FRAME_COMPONENT, logged on compositor frame
+ // submit.
+ EXPECT_EQ(3u, aggregated_latency_info.latency_components().size());
+
+ ui::LatencyInfo::LatencyComponent comp1;
+ EXPECT_TRUE(
+ aggregated_latency_info.FindLatency(latency_type1, latency_id1, &comp1));
+ EXPECT_EQ(latency_sequence_number1, comp1.sequence_number);
+ EXPECT_TRUE(
+ aggregated_latency_info.FindLatency(latency_type2, latency_id2, nullptr));
+ EXPECT_TRUE(aggregated_latency_info.FindLatency(
+ ui::DISPLAY_COMPOSITOR_RECEIVED_FRAME_COMPONENT, nullptr));
+}
+
+// Checks whether the latency info are moved to the new surface from the old
+// one when LocalSurfaceId changes. The new surface has unresolved dependencies.
+TEST_F(SurfaceSynchronizationTest,
+ LatencyInfoCarriedOverOnResize_NewSurfaceHasPendingFrame) {
+ const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
+ const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2);
+ const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 1);
+
+ const ui::LatencyComponentType latency_type1 =
+ ui::BROWSER_SNAPSHOT_FRAME_NUMBER_COMPONENT;
+ const int64_t latency_id1 = 234;
+ const int64_t latency_sequence_number1 = 5645432;
+ const ui::LatencyComponentType latency_type2 = ui::TAB_SHOW_COMPONENT;
+ const int64_t latency_id2 = 31434351;
+ const int64_t latency_sequence_number2 = 663788;
+
+ // Submit a frame with no unresolved dependencies.
+ ui::LatencyInfo info;
+ info.AddLatencyNumber(latency_type1, latency_id1, latency_sequence_number1);
+
+ CompositorFrame frame = MakeCompositorFrame();
+ frame.metadata.latency_info.push_back(info);
+
+ parent_support().SubmitCompositorFrame(parent_id1.local_surface_id(),
+ std::move(frame));
+
+ // Verify that the old surface has an active frame only.
+ Surface* old_surface = surface_manager().GetSurfaceForId(parent_id1);
+ ASSERT_NE(nullptr, old_surface);
+ EXPECT_TRUE(old_surface->HasActiveFrame());
+ EXPECT_FALSE(old_surface->HasPendingFrame());
+
+ // Submit a frame with a new local surface id and with unresolved
+ // dependencies.
+ ui::LatencyInfo info2;
+ info2.AddLatencyNumber(latency_type2, latency_id2, latency_sequence_number2);
+
+ CompositorFrame frame2 = MakeCompositorFrame({child_id}, empty_surface_ids(),
+ TransferableResourceArray());
+ frame2.metadata.latency_info.push_back(info2);
+
+ parent_support().SubmitCompositorFrame(parent_id2.local_surface_id(),
+ std::move(frame2));
+
+ // Verify that the new surface has a pending frame and no active frame.
+ Surface* surface = surface_manager().GetSurfaceForId(parent_id2);
+ ASSERT_NE(nullptr, surface);
+ EXPECT_TRUE(surface->HasPendingFrame());
+ EXPECT_FALSE(surface->HasActiveFrame());
+
+ // Resolve the dependencies. The frame in parent's surface must become active.
+ child_support1().SubmitCompositorFrame(child_id.local_surface_id(),
+ MakeCompositorFrame());
+ EXPECT_FALSE(surface->HasPendingFrame());
+ EXPECT_TRUE(surface->HasActiveFrame());
+
+ // Both latency info elements must exist in the now-activated frame of the
+ // new surface.
+ std::vector<ui::LatencyInfo> info_list;
+ surface->TakeLatencyInfo(&info_list);
+ EXPECT_EQ(2u, info_list.size());
+
+ ui::LatencyInfo aggregated_latency_info = info_list[0];
+ aggregated_latency_info.AddNewLatencyFrom(info_list[1]);
+
+ // Two components are the original ones, and the third one is
+ // DISPLAY_COMPOSITOR_RECEIVED_FRAME_COMPONENT, logged on compositor frame
+ // submit.
+ EXPECT_EQ(3u, aggregated_latency_info.latency_components().size());
+
+ ui::LatencyInfo::LatencyComponent comp1;
+ EXPECT_TRUE(
+ aggregated_latency_info.FindLatency(latency_type1, latency_id1, &comp1));
+ EXPECT_EQ(latency_sequence_number1, comp1.sequence_number);
+ EXPECT_TRUE(
+ aggregated_latency_info.FindLatency(latency_type2, latency_id2, nullptr));
+ EXPECT_TRUE(aggregated_latency_info.FindLatency(
+ ui::DISPLAY_COMPOSITOR_RECEIVED_FRAME_COMPONENT, nullptr));
+}
+
+TEST_F(SurfaceSynchronizationTest, PassesOnBeginFrameAcks) {
+ const SurfaceId display_id = MakeSurfaceId(kDisplayFrameSink, 1);
+
+ // Request BeginFrames.
+ display_support().SetNeedsBeginFrame(true);
+
+ // Issue a BeginFrame.
+ BeginFrameArgs args =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1);
+ begin_frame_source()->TestOnBeginFrame(args);
+
+ // Check that the support forwards a DidNotProduceFrame ack to the
+ // BeginFrameSource.
+ BeginFrameAck ack(0, 1, 1, false);
+ display_support().DidNotProduceFrame(ack);
+ EXPECT_EQ(ack, begin_frame_source()->LastAckForObserver(&display_support()));
+
+ // Issue another BeginFrame.
+ args = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 2);
+ begin_frame_source()->TestOnBeginFrame(args);
+
+ // Check that the support forwards the BeginFrameAck attached
+ // to a CompositorFrame to the BeginFrameSource.
+ BeginFrameAck ack2(0, 2, 2, true);
+ CompositorFrame frame = MakeCompositorFrame();
+ frame.metadata.begin_frame_ack = ack2;
+ display_support().SubmitCompositorFrame(display_id.local_surface_id(),
+ std::move(frame));
+ EXPECT_EQ(ack2, begin_frame_source()->LastAckForObserver(&display_support()));
+}
+
+// Checks that resources and ack are sent together if possible.
+TEST_F(SurfaceSynchronizationTest, ReturnResourcesWithAck) {
+ const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
+ TransferableResource resource;
+ resource.id = 1234;
+ parent_support().SubmitCompositorFrame(
+ parent_id.local_surface_id(),
+ MakeCompositorFrame(empty_surface_ids(), empty_surface_ids(),
+ {resource}));
+ ReturnedResourceArray returned_resources;
+ TransferableResource::ReturnResources({resource}, &returned_resources);
+ EXPECT_CALL(support_client_, ReclaimResources(_)).Times(0);
+ EXPECT_CALL(support_client_,
+ DidReceiveCompositorFrameAck(Eq(returned_resources)));
+ parent_support().SubmitCompositorFrame(parent_id.local_surface_id(),
+ MakeCompositorFrame());
+}
+
+// Verifies that if a surface is marked destroyed and a new frame arrives for
+// it, it will be recovered.
+TEST_F(SurfaceSynchronizationTest, SurfaceResurrection) {
+ const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
+ const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 3);
+
+ // Create the child surface by submitting a frame to it.
+ EXPECT_EQ(nullptr, surface_manager().GetSurfaceForId(child_id));
+ child_support1().SubmitCompositorFrame(child_id.local_surface_id(),
+ MakeCompositorFrame());
+
+ // Verify that the child surface is created.
+ Surface* surface = surface_manager().GetSurfaceForId(child_id);
+ EXPECT_NE(nullptr, surface);
+
+ // Add a reference from the parent to the child.
+ parent_support().SubmitCompositorFrame(
+ parent_id.local_surface_id(),
+ MakeCompositorFrame({child_id}, {child_id}, TransferableResourceArray()));
+
+ // Attempt to destroy the child surface. The surface must still exist since
+ // the parent needs it but it will be marked as destroyed.
+ child_support1().EvictCurrentSurface();
+ surface = surface_manager().GetSurfaceForId(child_id);
+ EXPECT_NE(nullptr, surface);
+ EXPECT_TRUE(surface->destroyed());
+
+ // Child submits another frame to the same local surface id that is marked
+ // destroyed.
+ child_support1().SubmitCompositorFrame(child_id.local_surface_id(),
+ MakeCompositorFrame());
+
+ // Verify that the surface that was marked destroyed is recovered and is being
+ // used again.
+ Surface* surface2 = surface_manager().GetSurfaceForId(child_id);
+ EXPECT_EQ(surface, surface2);
+ EXPECT_FALSE(surface2->destroyed());
+}
+
+// Verifies that if a LocalSurfaceId belonged to a surface that doesn't exist
+// anymore, it can still be reused for new surfaces.
+TEST_F(SurfaceSynchronizationTest, LocalSurfaceIdIsReusable) {
+ const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
+ const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 3);
+
+ // Submit the first frame. Creates the surface.
+ child_support1().SubmitCompositorFrame(child_id.local_surface_id(),
+ MakeCompositorFrame());
+ EXPECT_NE(nullptr, surface_manager().GetSurfaceForId(child_id));
+
+ // Add a reference from parent.
+ parent_support().SubmitCompositorFrame(
+ parent_id.local_surface_id(),
+ MakeCompositorFrame({child_id}, {child_id}, TransferableResourceArray()));
+
+ // Remove the reference from parant. This allows us to destroy the surface.
+ parent_support().SubmitCompositorFrame(parent_id.local_surface_id(),
+ MakeCompositorFrame());
+
+ // Destroy the surface.
+ child_support1().EvictCurrentSurface();
+ EXPECT_EQ(nullptr, surface_manager().GetSurfaceForId(child_id));
+
+ // Submit another frame with the same local surface id. This should work fine
+ // and a new surface must be created.
+ child_support1().SubmitCompositorFrame(child_id.local_surface_id(),
+ MakeCompositorFrame());
+ EXPECT_NE(nullptr, surface_manager().GetSurfaceForId(child_id));
+}
+
+// This test verifies that a crash does not occur if garbage collection is
+// triggered during surface dependency resolution. This test triggers garbage
+// collection during surface resolution, by causing an activation to remove
+// a surface subtree from the root. Both the old subtree and the new
+// activated subtree refer to the same dependency. The old subtree was activated
+// by deadline, and the new subtree was activated by a dependency finally
+// resolving.
+TEST_F(SurfaceSynchronizationTest, DependencyTrackingGarbageCollection) {
+ const SurfaceId display_id = MakeSurfaceId(kDisplayFrameSink, 1);
+ const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
+ const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2);
+ const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 1);
+
+ parent_support().SubmitCompositorFrame(
+ parent_id1.local_surface_id(),
+ MakeCompositorFrame({child_id}, empty_surface_ids(),
+ TransferableResourceArray()));
+ display_support().SubmitCompositorFrame(
+ display_id.local_surface_id(),
+ MakeCompositorFrame({parent_id1}, empty_surface_ids(),
+ TransferableResourceArray()));
+
+ EXPECT_TRUE(dependency_tracker().has_deadline());
+
+ BeginFrameArgs args =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1);
+
+ // Advance BeginFrames to trigger a deadline.
+ for (int i = 0; i < 3; ++i) {
+ begin_frame_source()->TestOnBeginFrame(args);
+ EXPECT_TRUE(dependency_tracker().has_deadline());
+ }
+ begin_frame_source()->TestOnBeginFrame(args);
+ EXPECT_FALSE(dependency_tracker().has_deadline());
+
+ EXPECT_TRUE(display_surface()->HasActiveFrame());
+ EXPECT_FALSE(display_surface()->HasPendingFrame());
+ EXPECT_TRUE(parent_surface()->HasActiveFrame());
+ EXPECT_FALSE(parent_surface()->HasPendingFrame());
+
+ parent_support().SubmitCompositorFrame(
+ parent_id2.local_surface_id(),
+ MakeCompositorFrame({child_id}, empty_surface_ids(),
+ TransferableResourceArray()));
+ display_support().SubmitCompositorFrame(
+ display_id.local_surface_id(),
+ MakeCompositorFrame({parent_id2}, empty_surface_ids(),
+ TransferableResourceArray()));
+
+ // The display surface now has two CompositorFrames. One that is pending,
+ // indirectly blocked on child_id and one that is active, also indirectly
+ // referring to child_id, but activated due to the deadline above.
+ EXPECT_TRUE(display_surface()->HasActiveFrame());
+ EXPECT_TRUE(display_surface()->HasPendingFrame());
+
+ // Submitting a CompositorFrame will trigger garbage collection of the
+ // |parent_id1| subtree. This should not crash.
+ child_support1().SubmitCompositorFrame(child_id.local_surface_id(),
+ MakeCompositorFrame());
+}
+
+// This test verifies that a crash does not occur if garbage collection is
+// triggered when a deadline forces frame activation. This test triggers garbage
+// collection during deadline activation by causing the activation of a display
+// frame to replace a previously activated display frame that was referring to
+// a now-unreachable surface subtree. That subtree gets garbage collected during
+// deadline activation. SurfaceDependencyTracker is also tracking a surface
+// from that subtree due to an unresolved dependency. This test verifies that
+// this dependency resolution does not crash.
+TEST_F(SurfaceSynchronizationTest, GarbageCollectionOnDeadline) {
+ const SurfaceId display_id = MakeSurfaceId(kDisplayFrameSink, 1);
+ const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
+ const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2);
+ const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 1);
+
+ // |parent_id1| is blocked on |child_id|.
+ parent_support().SubmitCompositorFrame(
+ parent_id1.local_surface_id(),
+ MakeCompositorFrame({child_id}, empty_surface_ids(),
+ TransferableResourceArray()));
+
+ display_support().SubmitCompositorFrame(
+ display_id.local_surface_id(),
+ MakeCompositorFrame({parent_id1}, {parent_id1},
+ TransferableResourceArray()));
+
+ EXPECT_TRUE(dependency_tracker().has_deadline());
+ EXPECT_TRUE(display_surface()->HasPendingFrame());
+ EXPECT_FALSE(display_surface()->HasActiveFrame());
+
+ // Advance BeginFrames to trigger a deadline. This activates the
+ // CompositorFrame submitted above.
+ BeginFrameArgs args =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1);
+ for (int i = 0; i < 3; ++i) {
+ begin_frame_source()->TestOnBeginFrame(args);
+ EXPECT_TRUE(dependency_tracker().has_deadline());
+ }
+ begin_frame_source()->TestOnBeginFrame(args);
+ EXPECT_FALSE(dependency_tracker().has_deadline());
+ EXPECT_FALSE(display_surface()->HasPendingFrame());
+ EXPECT_TRUE(display_surface()->HasActiveFrame());
+
+ // By submitting a display CompositorFrame, and replacing the parent's
+ // CompositorFrame with another surface ID, parent_id1 becomes unreachable and
+ // a candidate for garbage collection.
+ display_support().SubmitCompositorFrame(
+ display_id.local_surface_id(),
+ MakeCompositorFrame({parent_id2}, empty_surface_ids(),
+ TransferableResourceArray()));
+
+ // Now |parent_id1| is only kept alive by the active |display_id| frame.
+ parent_support().SubmitCompositorFrame(
+ parent_id2.local_surface_id(),
+ MakeCompositorFrame({child_id}, empty_surface_ids(),
+ TransferableResourceArray()));
+
+ // SurfaceDependencyTracker should now be tracking |display_id|, |parent_id1|
+ // and |parent_id2|. By activating the pending |display_id| frame by deadline,
+ // |parent_id1| becomes unreachable and is garbage collected while
+ // SurfaceDependencyTracker is in the process of activating surfaces. This
+ // should not cause a crash or use-after-free.
+ for (int i = 0; i < 3; ++i) {
+ begin_frame_source()->TestOnBeginFrame(args);
+ EXPECT_TRUE(dependency_tracker().has_deadline());
+ }
+ begin_frame_source()->TestOnBeginFrame(args);
+ EXPECT_FALSE(dependency_tracker().has_deadline());
+}
+
+// This test verifies that a CompositorFrame will only blocked on embedded
+// surfaces but not on other retained surface IDs in the CompositorFrame.
+TEST_F(SurfaceSynchronizationTest, OnlyBlockOnEmbeddedSurfaces) {
+ const SurfaceId display_id = MakeSurfaceId(kDisplayFrameSink, 1);
+ const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
+ const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2);
+
+ // Submitting a CompositorFrame with |parent_id2| so that the display
+ // CompositorFrame can hold a reference to it.
+ parent_support().SubmitCompositorFrame(parent_id2.local_surface_id(),
+ MakeCompositorFrame());
+
+ display_support().SubmitCompositorFrame(
+ display_id.local_surface_id(),
+ MakeCompositorFrame({parent_id1}, {parent_id2},
+ TransferableResourceArray()));
+
+ EXPECT_TRUE(display_surface()->HasPendingFrame());
+ EXPECT_FALSE(display_surface()->HasActiveFrame());
+ EXPECT_TRUE(dependency_tracker().has_deadline());
+
+ // Verify that the display CompositorFrame will only block on |parent_id1| but
+ // not |parent_id2|.
+ EXPECT_THAT(display_surface()->blocking_surfaces(),
+ UnorderedElementsAre(parent_id1));
+ // Verify that the display surface holds no references while its
+ // CompositorFrame is pending.
+ EXPECT_THAT(GetChildReferences(display_id), IsEmpty());
+
+ // Submitting a CompositorFrame with |parent_id1| should unblock the display
+ // CompositorFrame.
+ parent_support().SubmitCompositorFrame(parent_id1.local_surface_id(),
+ MakeCompositorFrame());
+
+ EXPECT_FALSE(dependency_tracker().has_deadline());
+ EXPECT_FALSE(display_surface()->HasPendingFrame());
+ EXPECT_TRUE(display_surface()->HasActiveFrame());
+ EXPECT_THAT(display_surface()->blocking_surfaces(), IsEmpty());
+}
+
+// This test verifies that a late arriving CompositorFrame activates immediately
+// and does not trigger a new deadline.
+TEST_F(SurfaceSynchronizationTest, LateArrivingDependency) {
+ const SurfaceId display_id = MakeSurfaceId(kDisplayFrameSink, 1);
+ const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
+ const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
+
+ display_support().SubmitCompositorFrame(
+ display_id.local_surface_id(),
+ MakeCompositorFrame({parent_id1}, empty_surface_ids(),
+ TransferableResourceArray()));
+
+ EXPECT_TRUE(display_surface()->HasPendingFrame());
+ EXPECT_FALSE(display_surface()->HasActiveFrame());
+ EXPECT_TRUE(dependency_tracker().has_deadline());
+
+ // Advance BeginFrames to trigger a deadline. This activates the
+ // CompositorFrame submitted above.
+ BeginFrameArgs args =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1);
+ for (int i = 0; i < 3; ++i) {
+ begin_frame_source()->TestOnBeginFrame(args);
+ EXPECT_TRUE(dependency_tracker().has_deadline());
+ }
+ begin_frame_source()->TestOnBeginFrame(args);
+ EXPECT_FALSE(dependency_tracker().has_deadline());
+ EXPECT_FALSE(display_surface()->HasPendingFrame());
+ EXPECT_TRUE(display_surface()->HasActiveFrame());
+
+ // A late arriving CompositorFrame should activate immediately without
+ // scheduling a deadline and without waiting for dependencies to resolve.
+ parent_support().SubmitCompositorFrame(
+ parent_id1.local_surface_id(),
+ MakeCompositorFrame({child_id1}, empty_surface_ids(),
+ TransferableResourceArray()));
+ EXPECT_FALSE(dependency_tracker().has_deadline());
+ EXPECT_FALSE(parent_surface()->HasPendingFrame());
+ EXPECT_TRUE(parent_surface()->HasActiveFrame());
+}
+
+// This test verifies that CompositorFrames submitted to a surface referenced
+// by a parent CompositorFrame as a fallback will be rejected and ACK'ed
+// immediately.
+TEST_F(SurfaceSynchronizationTest, FallbackSurfacesClosed) {
+ const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
+ // This is the fallback child surface that the parent holds a reference to.
+ const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
+ // This is the primary child surface that the parent wants to block on.
+ const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink1, 2);
+
+ // child_support1 submits a CompositorFrame without any dependencies.
+ // DidReceiveCompositorFrameAck should call on immediate activation.
+ // However, resources will not be returned because this frame is a candidate
+ // for display.
+ TransferableResource resource;
+ resource.id = 1337;
+ resource.format = ALPHA_8;
+ resource.filter = 1234;
+ resource.size = gfx::Size(1234, 5678);
+ ReturnedResourceArray returned_resources;
+ TransferableResource::ReturnResources({resource}, &returned_resources);
+
+ EXPECT_CALL(support_client_,
+ DidReceiveCompositorFrameAck(Eq(ReturnedResourceArray())));
+ child_support1().SubmitCompositorFrame(
+ child_id1.local_surface_id(),
+ MakeCompositorFrame(empty_surface_ids(), empty_surface_ids(),
+ {resource}));
+ testing::Mock::VerifyAndClearExpectations(&support_client_);
+
+ // The parent is blocked on |child_id2| and references |child_id1|. The
+ // surface corresponding to |child_id1| will not accept new CompositorFrames
+ // while the parent CompositorFrame is blocked.
+ parent_support().SubmitCompositorFrame(
+ parent_id1.local_surface_id(),
+ MakeCompositorFrame({child_id2}, {child_id1},
+ TransferableResourceArray()));
+ EXPECT_TRUE(dependency_tracker().has_deadline());
+ EXPECT_TRUE(parent_surface()->HasPendingFrame());
+ EXPECT_FALSE(parent_surface()->HasActiveFrame());
+
+ // Resources will be returned immediately because |child_id1|'s surface is
+ // closed.
+ TransferableResource resource2;
+ resource2.id = 1246;
+ resource2.format = ALPHA_8;
+ resource2.filter = 1357;
+ resource2.size = gfx::Size(8765, 4321);
+ ReturnedResourceArray returned_resources2;
+ TransferableResource::ReturnResources({resource2}, &returned_resources2);
+ EXPECT_CALL(support_client_,
+ DidReceiveCompositorFrameAck(Eq(returned_resources2)));
+ child_support1().SubmitCompositorFrame(
+ child_id1.local_surface_id(),
+ MakeCompositorFrame(empty_surface_ids(), empty_surface_ids(),
+ {resource2}));
+ testing::Mock::VerifyAndClearExpectations(&support_client_);
+
+ // Advance BeginFrames to trigger a deadline. This activates the
+ // CompositorFrame submitted to the parent.
+ BeginFrameArgs args =
+ CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1);
+ for (int i = 0; i < 3; ++i) {
+ begin_frame_source()->TestOnBeginFrame(args);
+ EXPECT_TRUE(dependency_tracker().has_deadline());
+ }
+ begin_frame_source()->TestOnBeginFrame(args);
+ EXPECT_FALSE(dependency_tracker().has_deadline());
+ EXPECT_FALSE(parent_surface()->HasPendingFrame());
+ EXPECT_TRUE(parent_surface()->HasActiveFrame());
+
+ // Resources will be returned immediately because |child_id1|'s surface is
+ // closed forever.
+ EXPECT_CALL(support_client_,
+ DidReceiveCompositorFrameAck(Eq(returned_resources2)));
+ child_support1().SubmitCompositorFrame(
+ child_id1.local_surface_id(),
+ MakeCompositorFrame(empty_surface_ids(), empty_surface_ids(),
+ {resource2}));
+ testing::Mock::VerifyAndClearExpectations(&support_client_);
+}
+
+} // namespace test
+} // namespace cc
diff --git a/chromium/cc/surfaces/surface_unittest.cc b/chromium/cc/surfaces/surface_unittest.cc
index e40cc05f9b3..beeebfc9fb3 100644
--- a/chromium/cc/surfaces/surface_unittest.cc
+++ b/chromium/cc/surfaces/surface_unittest.cc
@@ -10,6 +10,7 @@
#include "cc/surfaces/surface_dependency_tracker.h"
#include "cc/surfaces/surface_manager.h"
#include "cc/test/begin_frame_args_test.h"
+#include "cc/test/compositor_frame_helpers.h"
#include "cc/test/fake_external_begin_frame_source.h"
#include "cc/test/scheduler_test_common.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -32,9 +33,9 @@ TEST(SurfaceTest, SurfaceLifetime) {
LocalSurfaceId local_surface_id(6, base::UnguessableToken::Create());
SurfaceId surface_id(kArbitraryFrameSinkId, local_surface_id);
- support->SubmitCompositorFrame(local_surface_id, CompositorFrame());
+ support->SubmitCompositorFrame(local_surface_id, test::MakeCompositorFrame());
EXPECT_TRUE(manager.GetSurfaceForId(surface_id));
- support->EvictFrame();
+ support->EvictCurrentSurface();
EXPECT_EQ(NULL, manager.GetSurfaceForId(surface_id));
}
@@ -64,8 +65,7 @@ TEST(SurfaceTest, CopyRequestLifetime) {
LocalSurfaceId local_surface_id(6, base::UnguessableToken::Create());
SurfaceId surface_id(kArbitraryFrameSinkId, local_surface_id);
- CompositorFrame frame;
- frame.render_pass_list.push_back(RenderPass::Create());
+ CompositorFrame frame = test::MakeCompositorFrame();
support->SubmitCompositorFrame(local_surface_id, std::move(frame));
Surface* surface = manager.GetSurfaceForId(surface_id);
ASSERT_TRUE(!!surface);
@@ -78,13 +78,15 @@ TEST(SurfaceTest, CopyRequestLifetime) {
int max_frame = 3, start_id = 200;
for (int i = 0; i < max_frame; ++i) {
- CompositorFrame frame;
+ CompositorFrame frame = test::MakeEmptyCompositorFrame();
frame.render_pass_list.push_back(RenderPass::Create());
frame.render_pass_list.back()->id = i * 3 + start_id;
frame.render_pass_list.push_back(RenderPass::Create());
frame.render_pass_list.back()->id = i * 3 + start_id + 1;
frame.render_pass_list.push_back(RenderPass::Create());
- frame.render_pass_list.back()->id = i * 3 + start_id + 2;
+ frame.render_pass_list.back()->SetNew(i * 3 + start_id + 2,
+ gfx::Rect(0, 0, 20, 20), gfx::Rect(),
+ gfx::Transform());
support->SubmitCompositorFrame(local_surface_id, std::move(frame));
}
@@ -105,7 +107,7 @@ TEST(SurfaceTest, CopyRequestLifetime) {
copy_requests.find(last_pass_id)->second->SendEmptyResult();
EXPECT_TRUE(copy_called);
- support->EvictFrame();
+ support->EvictCurrentSurface();
}
} // namespace
diff --git a/chromium/cc/surfaces/surfaces_pixeltest.cc b/chromium/cc/surfaces/surfaces_pixeltest.cc
index 0b81474ccb5..2917c086e42 100644
--- a/chromium/cc/surfaces/surfaces_pixeltest.cc
+++ b/chromium/cc/surfaces/surfaces_pixeltest.cc
@@ -11,6 +11,7 @@
#include "cc/surfaces/surface.h"
#include "cc/surfaces/surface_aggregator.h"
#include "cc/surfaces/surface_manager.h"
+#include "cc/test/compositor_frame_helpers.h"
#include "cc/test/pixel_comparator.h"
#include "cc/test/pixel_test.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -39,7 +40,7 @@ class SurfacesPixelTest : public RendererPixelTest<GLRenderer> {
kIsRoot,
kHandlesFrameSinkIdInvalidation,
kNeedsSyncPoints)) {}
- ~SurfacesPixelTest() override { support_->EvictFrame(); }
+ ~SurfacesPixelTest() override { support_->EvictCurrentSurface(); }
protected:
SurfaceManager manager_;
@@ -51,14 +52,14 @@ SharedQuadState* CreateAndAppendTestSharedQuadState(
RenderPass* render_pass,
const gfx::Transform& transform,
const gfx::Size& size) {
- const gfx::Size layer_bounds = size;
+ const gfx::Rect layer_rect = gfx::Rect(size);
const gfx::Rect visible_layer_rect = gfx::Rect(size);
const gfx::Rect clip_rect = gfx::Rect(size);
bool is_clipped = false;
float opacity = 1.f;
const SkBlendMode blend_mode = SkBlendMode::kSrcOver;
SharedQuadState* shared_state = render_pass->CreateAndAppendSharedQuadState();
- shared_state->SetAll(transform, layer_bounds, visible_layer_rect, clip_rect,
+ shared_state->SetAll(transform, layer_rect, visible_layer_rect, clip_rect,
is_clipped, opacity, blend_mode, 0);
return shared_state;
}
@@ -82,8 +83,7 @@ TEST_F(SurfacesPixelTest, DrawSimpleFrame) {
SK_ColorGREEN,
force_anti_aliasing_off);
-
- CompositorFrame root_frame;
+ CompositorFrame root_frame = test::MakeCompositorFrame();
root_frame.render_pass_list.push_back(std::move(pass));
LocalSurfaceId root_local_surface_id = allocator_.GenerateId();
@@ -140,7 +140,7 @@ TEST_F(SurfacesPixelTest, DrawSimpleAggregatedFrame) {
SK_ColorYELLOW,
force_anti_aliasing_off);
- CompositorFrame root_frame;
+ CompositorFrame root_frame = test::MakeCompositorFrame();
root_frame.render_pass_list.push_back(std::move(pass));
support_->SubmitCompositorFrame(root_local_surface_id,
@@ -165,7 +165,7 @@ TEST_F(SurfacesPixelTest, DrawSimpleAggregatedFrame) {
SK_ColorBLUE,
force_anti_aliasing_off);
- CompositorFrame child_frame;
+ CompositorFrame child_frame = test::MakeCompositorFrame();
child_frame.render_pass_list.push_back(std::move(pass));
child_support->SubmitCompositorFrame(child_local_surface_id,
@@ -182,7 +182,7 @@ TEST_F(SurfacesPixelTest, DrawSimpleAggregatedFrame) {
base::FilePath(FILE_PATH_LITERAL("blue_yellow.png")),
pixel_comparator));
- child_support->EvictFrame();
+ child_support->EvictCurrentSurface();
}
// Tests a surface quad that has a non-identity transform into its pass.
@@ -240,7 +240,7 @@ TEST_F(SurfacesPixelTest, DrawAggregatedFrameWithSurfaceTransforms) {
right_child_id, SurfaceDrawQuadType::PRIMARY,
nullptr);
- CompositorFrame root_frame;
+ CompositorFrame root_frame = test::MakeCompositorFrame();
root_frame.render_pass_list.push_back(std::move(pass));
support_->SubmitCompositorFrame(root_local_surface_id,
@@ -273,7 +273,7 @@ TEST_F(SurfacesPixelTest, DrawAggregatedFrameWithSurfaceTransforms) {
SK_ColorBLUE,
force_anti_aliasing_off);
- CompositorFrame child_frame;
+ CompositorFrame child_frame = test::MakeCompositorFrame();
child_frame.render_pass_list.push_back(std::move(pass));
left_support->SubmitCompositorFrame(left_child_local_id,
@@ -306,7 +306,7 @@ TEST_F(SurfacesPixelTest, DrawAggregatedFrameWithSurfaceTransforms) {
SK_ColorGREEN,
force_anti_aliasing_off);
- CompositorFrame child_frame;
+ CompositorFrame child_frame = test::MakeCompositorFrame();
child_frame.render_pass_list.push_back(std::move(pass));
right_support->SubmitCompositorFrame(right_child_local_id,
@@ -324,8 +324,8 @@ TEST_F(SurfacesPixelTest, DrawAggregatedFrameWithSurfaceTransforms) {
base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers.png")),
pixel_comparator));
- left_support->EvictFrame();
- right_support->EvictFrame();
+ left_support->EvictCurrentSurface();
+ right_support->EvictCurrentSurface();
}
} // namespace
diff --git a/chromium/cc/tiles/checker_image_tracker.cc b/chromium/cc/tiles/checker_image_tracker.cc
index 8bbcbebe839..022269d87a9 100644
--- a/chromium/cc/tiles/checker_image_tracker.cc
+++ b/chromium/cc/tiles/checker_image_tracker.cc
@@ -5,6 +5,7 @@
#include "cc/tiles/checker_image_tracker.h"
#include "base/bind.h"
+#include "base/memory/ptr_util.h"
#include "base/stl_util.h"
#include "base/trace_event/trace_event.h"
@@ -30,35 +31,23 @@ CheckerImageTracker::CheckerImageTracker(ImageController* image_controller,
enable_checker_imaging_(enable_checker_imaging),
weak_factory_(this) {}
-CheckerImageTracker::~CheckerImageTracker() {
- // Unlock all images pending decode requests.
- for (auto it : image_id_to_decode_request_id_)
- image_controller_->UnlockImageDecode(it.second);
-}
+CheckerImageTracker::~CheckerImageTracker() = default;
-void CheckerImageTracker::FilterImagesForCheckeringForTile(
- std::vector<DrawImage>* images,
- ImageIdFlatSet* checkered_images,
- WhichTree tree) {
- TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
- "CheckerImageTracker::FilterImagesForCheckeringForTile", "tree",
- tree);
- DCHECK(checkered_images->empty());
-
- base::EraseIf(*images,
- [this, tree, &checkered_images](const DrawImage& draw_image) {
- const sk_sp<const SkImage>& image = draw_image.image();
- DCHECK(image->isLazyGenerated());
- if (ShouldCheckerImage(image, tree)) {
- ScheduleImageDecodeIfNecessary(image);
- checkered_images->insert(image->uniqueID());
- return true;
- }
- return false;
- });
+void CheckerImageTracker::ScheduleImageDecodeQueue(
+ ImageDecodeQueue image_decode_queue) {
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
+ "CheckerImageTracker::ScheduleImageDecodeQueue");
+ // Only checker-imaged (async updated) images are decoded using the image
+ // decode service. If |enable_checker_imaging_| is false, no image should
+ // be checkered.
+ DCHECK(image_decode_queue.empty() || enable_checker_imaging_);
+
+ image_decode_queue_ = std::move(image_decode_queue);
+ ScheduleNextImageDecode();
}
-const ImageIdFlatSet& CheckerImageTracker::TakeImagesToInvalidateOnSyncTree() {
+const PaintImageIdFlatSet&
+CheckerImageTracker::TakeImagesToInvalidateOnSyncTree() {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"CheckerImageTracker::TakeImagesToInvalidateOnSyncTree");
DCHECK_EQ(invalidated_images_on_current_sync_tree_.size(), 0u)
@@ -72,17 +61,45 @@ const ImageIdFlatSet& CheckerImageTracker::TakeImagesToInvalidateOnSyncTree() {
void CheckerImageTracker::DidActivateSyncTree() {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"CheckerImageTracker::DidActivateSyncTree");
- for (auto image_id : invalidated_images_on_current_sync_tree_) {
- auto it = image_id_to_decode_request_id_.find(image_id);
- image_controller_->UnlockImageDecode(it->second);
- image_id_to_decode_request_id_.erase(it);
- }
-
+ for (auto image_id : invalidated_images_on_current_sync_tree_)
+ image_id_to_decode_.erase(image_id);
invalidated_images_on_current_sync_tree_.clear();
}
+void CheckerImageTracker::ClearTracker(bool can_clear_decode_policy_tracking) {
+ // Unlock all images and tracking for images pending invalidation. The
+ // |images_invalidated_on_current_sync_tree_| will be cleared when the sync
+ // tree is activated.
+ //
+ // Note that we assume that any images with DecodePolicy::ASYNC, which may be
+ // checkered, are safe to stop tracking here and will either be re-checkered
+ // and invalidated when the decode completes or be invalidated externally.
+ // This is because the policy decision for checkering an image is based on
+ // inputs received from a PaintImage in the DisplayItemList. The policy chosen
+ // for a PaintImage should remain unchanged.
+ // If the external inputs for deciding the decode policy for an image change,
+ // they should be accompanied with an invalidation during paint.
+ image_id_to_decode_.clear();
+
+ if (can_clear_decode_policy_tracking) {
+ image_async_decode_state_.clear();
+ } else {
+ // If we can't clear the decode policy, we need to make sure we still
+ // re-decode and checker images that were pending invalidation.
+ for (auto image_id : images_pending_invalidation_) {
+ auto it = image_async_decode_state_.find(image_id);
+
+ DCHECK(it != image_async_decode_state_.end());
+ DCHECK_EQ(it->second, DecodePolicy::SYNC_DECODED_ONCE);
+
+ it->second = DecodePolicy::ASYNC;
+ }
+ }
+ images_pending_invalidation_.clear();
+}
+
void CheckerImageTracker::DidFinishImageDecode(
- ImageId image_id,
+ PaintImage::Id image_id,
ImageController::ImageDecodeRequestId request_id,
ImageController::ImageDecodeResult result) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
@@ -90,75 +107,114 @@ void CheckerImageTracker::DidFinishImageDecode(
TRACE_EVENT_ASYNC_END0("cc", "CheckerImageTracker::DeferImageDecode",
image_id);
- DCHECK_NE(result, ImageController::ImageDecodeResult::DECODE_NOT_REQUIRED);
- DCHECK_NE(pending_image_decodes_.count(image_id), 0u);
- pending_image_decodes_.erase(image_id);
+ DCHECK_NE(ImageController::ImageDecodeResult::DECODE_NOT_REQUIRED, result);
+ DCHECK_EQ(outstanding_image_decode_.value().stable_id(), image_id);
+ outstanding_image_decode_.reset();
+
+ // The async decode state may have been cleared if the tracker was cleared
+ // before this decode could be finished.
+ auto it = image_async_decode_state_.find(image_id);
+ if (it == image_async_decode_state_.end()) {
+ DCHECK_EQ(image_id_to_decode_.count(image_id), 0u);
+ return;
+ }
- images_decoded_once_.insert(image_id);
+ it->second = DecodePolicy::SYNC_DECODED_ONCE;
images_pending_invalidation_.insert(image_id);
+ ScheduleNextImageDecode();
client_->NeedsInvalidationForCheckerImagedTiles();
}
-bool CheckerImageTracker::ShouldCheckerImage(const sk_sp<const SkImage>& image,
- WhichTree tree) const {
+bool CheckerImageTracker::ShouldCheckerImage(const PaintImage& image,
+ WhichTree tree) {
TRACE_EVENT1("cc", "CheckerImageTracker::ShouldCheckerImage", "image_id",
- image->uniqueID());
+ image.stable_id());
if (!enable_checker_imaging_)
return false;
+ PaintImage::Id image_id = image.stable_id();
+
// If the image was invalidated on the current sync tree and the tile is
// for the active tree, continue checkering it on the active tree to ensure
// the image update is atomic for the frame.
- if (invalidated_images_on_current_sync_tree_.count(image->uniqueID()) != 0 &&
+ if (invalidated_images_on_current_sync_tree_.count(image_id) != 0 &&
tree == WhichTree::ACTIVE_TREE) {
return true;
}
- // If a decode request is pending for this image, continue checkering it.
- if (pending_image_decodes_.find(image->uniqueID()) !=
- pending_image_decodes_.end()) {
- return true;
- }
-
// If the image is pending invalidation, continue checkering it. All tiles
// for these images will be invalidated on the next pending tree.
- if (images_pending_invalidation_.find(image->uniqueID()) !=
+ if (images_pending_invalidation_.find(image_id) !=
images_pending_invalidation_.end()) {
return true;
}
- // If the image has been decoded once before, don't checker it again.
- if (images_decoded_once_.find(image->uniqueID()) !=
- images_decoded_once_.end()) {
- return false;
+ auto insert_result =
+ image_async_decode_state_.insert(std::pair<PaintImage::Id, DecodePolicy>(
+ image_id, DecodePolicy::SYNC_PERMANENT));
+ auto it = insert_result.first;
+ if (insert_result.second) {
+ bool can_checker_image =
+ image.animation_type() == PaintImage::AnimationType::STATIC &&
+ image.completion_state() == PaintImage::CompletionState::DONE;
+ if (can_checker_image) {
+ size_t size = SafeSizeOfImage(image.sk_image().get());
+ it->second = (size >= kMinImageSizeToCheckerBytes &&
+ size <= image_controller_->image_cache_max_limit_bytes())
+ ? DecodePolicy::ASYNC
+ : DecodePolicy::SYNC_PERMANENT;
+ }
}
- return SafeSizeOfImage(image.get()) >= kMinImageSizeToCheckerBytes;
+ return it->second == DecodePolicy::ASYNC;
}
-void CheckerImageTracker::ScheduleImageDecodeIfNecessary(
- const sk_sp<const SkImage>& image) {
+void CheckerImageTracker::ScheduleNextImageDecode() {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
- "CheckerImageTracker::ScheduleImageDecodeIfNecessary");
- ImageId image_id = image->uniqueID();
+ "CheckerImageTracker::ScheduleNextImageDecode");
+ // We can have only one outsanding decode pending completion with the decode
+ // service. We'll come back here when it is completed.
+ if (outstanding_image_decode_.has_value())
+ return;
+
+ while (!image_decode_queue_.empty()) {
+ auto candidate = std::move(image_decode_queue_.front());
+ image_decode_queue_.erase(image_decode_queue_.begin());
+
+ // Once an image has been decoded, it can still be present in the decode
+ // queue (duplicate entries), or while an image is still being skipped on
+ // the active tree. Check if the image is still ASYNC to see if a decode is
+ // needed.
+ PaintImage::Id image_id = candidate.stable_id();
+ auto it = image_async_decode_state_.find(image_id);
+ DCHECK(it != image_async_decode_state_.end());
+ if (it->second != DecodePolicy::ASYNC)
+ continue;
+
+ outstanding_image_decode_.emplace(candidate);
+ break;
+ }
- // If the image has already been decoded, or a decode request is pending, we
- // don't need to schedule another decode.
- if (images_decoded_once_.count(image_id) != 0 ||
- pending_image_decodes_.count(image_id) != 0) {
+ // We either found an image to decode or we reached the end of the queue. If
+ // we couldn't find an image, we're done.
+ if (!outstanding_image_decode_.has_value()) {
+ DCHECK(image_decode_queue_.empty());
return;
}
+ PaintImage::Id image_id = outstanding_image_decode_.value().stable_id();
+ DCHECK_EQ(image_id_to_decode_.count(image_id), 0u);
TRACE_EVENT_ASYNC_BEGIN0("cc", "CheckerImageTracker::DeferImageDecode",
image_id);
- DCHECK_EQ(image_id_to_decode_request_id_.count(image_id), 0U);
-
- image_id_to_decode_request_id_[image_id] =
+ ImageController::ImageDecodeRequestId request_id =
image_controller_->QueueImageDecode(
- image, base::Bind(&CheckerImageTracker::DidFinishImageDecode,
- weak_factory_.GetWeakPtr(), image_id));
- pending_image_decodes_.insert(image_id);
+ outstanding_image_decode_.value().sk_image(),
+ base::Bind(&CheckerImageTracker::DidFinishImageDecode,
+ weak_factory_.GetWeakPtr(), image_id));
+
+ image_id_to_decode_.emplace(image_id, base::MakeUnique<ScopedDecodeHolder>(
+ image_controller_, request_id));
}
} // namespace cc
diff --git a/chromium/cc/tiles/checker_image_tracker.h b/chromium/cc/tiles/checker_image_tracker.h
index 3bc29f55294..9f64d8d3f06 100644
--- a/chromium/cc/tiles/checker_image_tracker.h
+++ b/chromium/cc/tiles/checker_image_tracker.h
@@ -8,6 +8,7 @@
#include <unordered_map>
#include <vector>
+#include "base/optional.h"
#include "cc/cc_export.h"
#include "cc/paint/image_id.h"
#include "cc/tiles/image_controller.h"
@@ -37,33 +38,62 @@ class CC_EXPORT CheckerImageTracker {
bool enable_checker_imaging);
~CheckerImageTracker();
- // Given the |images| for a tile, filters the images which will be deferred
- // asynchronously using the image decoded service, eliminating them from
- // |images| adds them to the |checkered_images| set, so they can be skipped
- // during the rasterization of this tile.
- // The entries remaining in |images| are for images for which a cached decode
- // from the image decode service is available, or which must be decoded before
- // before this tile can be rasterized.
- void FilterImagesForCheckeringForTile(std::vector<DrawImage>* images,
- ImageIdFlatSet* checkered_images,
- WhichTree tree);
+ // Returns true if the decode for |image| will be deferred to the image decode
+ // service and it should be be skipped during raster.
+ bool ShouldCheckerImage(const PaintImage& image, WhichTree tree);
+
+ using ImageDecodeQueue = std::vector<PaintImage>;
+ void ScheduleImageDecodeQueue(ImageDecodeQueue image_decode_queue);
// Returns the set of images to invalidate on the sync tree.
- const ImageIdFlatSet& TakeImagesToInvalidateOnSyncTree();
+ const PaintImageIdFlatSet& TakeImagesToInvalidateOnSyncTree();
+ // Called when the sync tree is activated. Each call to
+ // TakeImagesToInvalidateOnSyncTree() must be followed by this when the
+ // invalidated sync tree is activated.
void DidActivateSyncTree();
+ // Called to reset the tracker state on navigation. This will release all
+ // cached images. Setting |can_clear_decode_policy_tracking| will also result
+ // in re-checkering any images already decoded by the tracker.
+ void ClearTracker(bool can_clear_decode_policy_tracking);
+
private:
- void DidFinishImageDecode(ImageId image_id,
+ enum class DecodePolicy {
+ // The image can be decoded asynchronously from raster. When set, the image
+ // is always skipped during rasterization of content that includes this
+ // image until it has been decoded using the decode service.
+ ASYNC,
+ // The image has been decoded asynchronously once and should now be
+ // synchronously rasterized with the content.
+ SYNC_DECODED_ONCE,
+ // The image has been permanently vetoed from being decoded async.
+ SYNC_PERMANENT,
+ };
+
+ // Wrapper to unlock an image decode requested from the ImageController on
+ // destruction.
+ class ScopedDecodeHolder {
+ public:
+ ScopedDecodeHolder(ImageController* controller,
+ ImageController::ImageDecodeRequestId request_id)
+ : controller_(controller), request_id_(request_id) {}
+ ~ScopedDecodeHolder() { controller_->UnlockImageDecode(request_id_); }
+
+ private:
+ ImageController* controller_;
+ ImageController::ImageDecodeRequestId request_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedDecodeHolder);
+ };
+
+ void DidFinishImageDecode(PaintImage::Id image_id,
ImageController::ImageDecodeRequestId request_id,
ImageController::ImageDecodeResult result);
- // Returns true if the decode for |image| will be deferred to the image decode
- // service and it should be be skipped during raster.
- bool ShouldCheckerImage(const sk_sp<const SkImage>& image,
- WhichTree tree) const;
-
- void ScheduleImageDecodeIfNecessary(const sk_sp<const SkImage>& image);
+ // Called when the next request in the |image_decode_queue_| should be
+ // scheduled with the image decode service.
+ void ScheduleNextImageDecode();
ImageController* image_controller_;
CheckerImageTrackerClient* client_;
@@ -71,27 +101,26 @@ class CC_EXPORT CheckerImageTracker {
// A set of images which have been decoded and are pending invalidation for
// raster on the checkered tiles.
- ImageIdFlatSet images_pending_invalidation_;
+ PaintImageIdFlatSet images_pending_invalidation_;
// A set of images which were invalidated on the current sync tree.
- ImageIdFlatSet invalidated_images_on_current_sync_tree_;
+ PaintImageIdFlatSet invalidated_images_on_current_sync_tree_;
+
+ // The queue of images pending decode. We maintain a queue to ensure that the
+ // order in which images are decoded is aligned with the priority of the tiles
+ // dependent on these images.
+ ImageDecodeQueue image_decode_queue_;
- // A set of images which are currently pending decode from the image decode
- // service.
- // TODO(khushalsagar): This should be a queue that gets re-built each time we
- // do a PrepareTiles? See crbug.com/689184.
- ImageIdFlatSet pending_image_decodes_;
+ // The currently outstanding image decode that has been scheduled with the
+ // decode service. There can be only one outstanding decode at a time.
+ base::Optional<PaintImage> outstanding_image_decode_;
- // A set of images which have been decoded at least once from the
- // ImageDecodeService and should not be checkered again.
- // TODO(khushalsagar): Limit the size of this set.
- // TODO(khushalsagar): Plumb navigation changes here to reset this. See
- // crbug.com/693228.
- std::unordered_set<ImageId> images_decoded_once_;
+ // A map of ImageId to its DecodePolicy.
+ std::unordered_map<PaintImage::Id, DecodePolicy> image_async_decode_state_;
// A map of image id to image decode request id for images to be unlocked.
- std::unordered_map<ImageId, ImageController::ImageDecodeRequestId>
- image_id_to_decode_request_id_;
+ std::unordered_map<PaintImage::Id, std::unique_ptr<ScopedDecodeHolder>>
+ image_id_to_decode_;
base::WeakPtrFactory<CheckerImageTracker> weak_factory_;
};
diff --git a/chromium/cc/tiles/checker_image_tracker_unittest.cc b/chromium/cc/tiles/checker_image_tracker_unittest.cc
index 9ca8d39f344..38de60dfd80 100644
--- a/chromium/cc/tiles/checker_image_tracker_unittest.cc
+++ b/chromium/cc/tiles/checker_image_tracker_unittest.cc
@@ -15,8 +15,13 @@
namespace cc {
namespace {
+// 5MB max image cache size.
+const size_t kMaxImageCacheSizeBytes = 5 * 1024 * 1024;
+
const int kCheckerableImageDimension = 512;
-const int kNonCheckerableImageDimension = 16;
+// This size will result in an image just over kMaxImageCacheSizeBytes.
+const int kLargeNonCheckerableImageDimension = 1145;
+const int kSmallNonCheckerableImageDimension = 16;
class TestImageController : public ImageController {
public:
@@ -24,11 +29,16 @@ class TestImageController : public ImageController {
// the ImageController is over-ridden here.
TestImageController()
: ImageController(base::ThreadTaskRunnerHandle::Get().get(),
- base::ThreadTaskRunnerHandle::Get()) {}
+ base::ThreadTaskRunnerHandle::Get()) {
+ SetMaxImageCacheLimitBytesForTesting(kMaxImageCacheSizeBytes);
+ }
~TestImageController() override { DCHECK_EQ(locked_images_.size(), 0U); }
int num_of_locked_images() const { return locked_images_.size(); }
+ const PaintImageIdFlatSet& decodes_requested() const {
+ return decodes_requested_;
+ }
void UnlockImageDecode(ImageDecodeRequestId id) override {
DCHECK_EQ(locked_images_.count(id), 1U);
@@ -40,10 +50,7 @@ class TestImageController : public ImageController {
const ImageDecodedCallback& callback) override {
ImageDecodeRequestId request_id = next_image_request_id_++;
- // The tracker should request a decode only once.
- EXPECT_EQ(decodes_requested_.count(image->uniqueID()), 0u);
decodes_requested_.insert(image->uniqueID());
-
locked_images_.insert(request_id);
// Post the callback asynchronously to match the behaviour in
@@ -58,13 +65,17 @@ class TestImageController : public ImageController {
private:
ImageDecodeRequestId next_image_request_id_ = 1U;
std::unordered_set<ImageDecodeRequestId> locked_images_;
- ImageIdFlatSet decodes_requested_;
+ PaintImageIdFlatSet decodes_requested_;
};
class CheckerImageTrackerTest : public testing::Test,
public CheckerImageTrackerClient {
public:
- enum class ImageType { CHECKERABLE, NON_CHECKERABLE };
+ enum class ImageType {
+ CHECKERABLE,
+ SMALL_NON_CHECKERABLE,
+ LARGE_NON_CHECKERABLE
+ };
void SetUpTracker(bool checker_images_enabled) {
checker_image_tracker_ = base::MakeUnique<CheckerImageTracker>(
@@ -73,15 +84,38 @@ class CheckerImageTrackerTest : public testing::Test,
void TearDown() override { checker_image_tracker_.reset(); }
- DrawImage CreateImage(ImageType image_type) {
- int dimension = image_type == ImageType::CHECKERABLE
- ? kCheckerableImageDimension
- : kNonCheckerableImageDimension;
+ PaintImage CreateImage(
+ ImageType image_type,
+ PaintImage::AnimationType animation = PaintImage::AnimationType::STATIC,
+ PaintImage::CompletionState completion =
+ PaintImage::CompletionState::DONE) {
+ int dimension = 0;
+ switch (image_type) {
+ case ImageType::CHECKERABLE:
+ dimension = kCheckerableImageDimension;
+ break;
+ case ImageType::SMALL_NON_CHECKERABLE:
+ dimension = kSmallNonCheckerableImageDimension;
+ break;
+ case ImageType::LARGE_NON_CHECKERABLE:
+ dimension = kLargeNonCheckerableImageDimension;
+ break;
+ }
+
sk_sp<SkImage> image =
CreateDiscardableImage(gfx::Size(dimension, dimension));
- gfx::ColorSpace target_color_space = gfx::ColorSpace::CreateSRGB();
- return DrawImage(image, SkIRect::MakeWH(image->width(), image->height()),
- kNone_SkFilterQuality, SkMatrix::I(), target_color_space);
+ return PaintImage(PaintImage::GetNextId(), image, animation, completion);
+ }
+
+ CheckerImageTracker::ImageDecodeQueue BuildImageDecodeQueue(
+ std::vector<PaintImage> images,
+ WhichTree tree) {
+ CheckerImageTracker::ImageDecodeQueue decode_queue;
+ for (const auto& image : images) {
+ if (checker_image_tracker_->ShouldCheckerImage(image, tree))
+ decode_queue.push_back(image);
+ }
+ return decode_queue;
}
// CheckerImageTrackerClient implementation.
@@ -101,13 +135,10 @@ TEST_F(CheckerImageTrackerTest, CheckerImagesDisabled) {
// disabled.
SetUpTracker(false);
- std::vector<DrawImage> draw_images;
- ImageIdFlatSet checkered_images;
- draw_images.push_back(CreateImage(ImageType::CHECKERABLE));
- checker_image_tracker_->FilterImagesForCheckeringForTile(
- &draw_images, &checkered_images, WhichTree::PENDING_TREE);
- EXPECT_EQ(draw_images.size(), 1U);
- EXPECT_EQ(checkered_images.size(), 0U);
+ PaintImageIdFlatSet checkered_images;
+ PaintImage paint_image = CreateImage(ImageType::CHECKERABLE);
+ EXPECT_FALSE(checker_image_tracker_->ShouldCheckerImage(
+ paint_image, WhichTree::PENDING_TREE));
EXPECT_EQ(image_controller_.num_of_locked_images(), 0);
}
@@ -115,22 +146,25 @@ TEST_F(CheckerImageTrackerTest, UpdatesImagesAtomically) {
// Ensures that the tracker updates images atomically for each frame.
SetUpTracker(true);
- DrawImage checkerable_image = CreateImage(ImageType::CHECKERABLE);
- DrawImage non_checkerable_image = CreateImage(ImageType::NON_CHECKERABLE);
- ImageIdFlatSet checkered_images;
- std::vector<DrawImage> draw_images;
+ PaintImage checkerable_image = CreateImage(ImageType::CHECKERABLE);
+ PaintImage small_non_checkerable_image =
+ CreateImage(ImageType::SMALL_NON_CHECKERABLE);
+ PaintImage large_non_checkerable_image =
+ CreateImage(ImageType::LARGE_NON_CHECKERABLE);
+ CheckerImageTracker::ImageDecodeQueue image_decode_queue;
// First request to filter images.
- draw_images.push_back(checkerable_image);
- draw_images.push_back(non_checkerable_image);
- draw_images.push_back(checkerable_image);
- checker_image_tracker_->FilterImagesForCheckeringForTile(
- &draw_images, &checkered_images, WhichTree::PENDING_TREE);
-
- EXPECT_EQ(draw_images.size(), 1U);
- EXPECT_EQ(draw_images[0].image(), non_checkerable_image.image());
- EXPECT_EQ(checkered_images.size(), 1U);
- EXPECT_EQ(checkered_images.count(checkerable_image.image()->uniqueID()), 1U);
+ std::vector<PaintImage> paint_images = {
+ checkerable_image, small_non_checkerable_image,
+ large_non_checkerable_image, checkerable_image};
+ image_decode_queue =
+ BuildImageDecodeQueue(paint_images, WhichTree::PENDING_TREE);
+
+ ASSERT_EQ(2u, image_decode_queue.size());
+ EXPECT_EQ(checkerable_image, image_decode_queue[0]);
+ EXPECT_EQ(checkerable_image, image_decode_queue[1]);
+
+ checker_image_tracker_->ScheduleImageDecodeQueue(image_decode_queue);
EXPECT_EQ(image_controller_.num_of_locked_images(), 1);
// Run pending task to indicate completion of decode request to the tracker.
@@ -143,44 +177,31 @@ TEST_F(CheckerImageTrackerTest, UpdatesImagesAtomically) {
// Continue checkering the image until the set of images to invalidate is
// pulled.
- draw_images.clear();
- draw_images.push_back(checkerable_image);
- checkered_images.clear();
- checker_image_tracker_->FilterImagesForCheckeringForTile(
- &draw_images, &checkered_images, WhichTree::PENDING_TREE);
- EXPECT_EQ(draw_images.size(), 0U);
- EXPECT_EQ(checkered_images.size(), 1U);
- EXPECT_EQ(image_controller_.num_of_locked_images(), 1);
+ EXPECT_TRUE(checker_image_tracker_->ShouldCheckerImage(
+ checkerable_image, WhichTree::PENDING_TREE));
- ImageIdFlatSet invalidated_images =
+ PaintImageIdFlatSet invalidated_images =
checker_image_tracker_->TakeImagesToInvalidateOnSyncTree();
EXPECT_EQ(invalidated_images.size(), 1U);
- EXPECT_EQ(invalidated_images.count(checkerable_image.image()->uniqueID()),
- 1U);
+ EXPECT_EQ(invalidated_images.count(checkerable_image.stable_id()), 1U);
// Use the same set of draw images to ensure that they are not checkered on
// the pending tree now.
- draw_images.clear();
- draw_images.push_back(checkerable_image);
- draw_images.push_back(non_checkerable_image);
- checkered_images.clear();
- checker_image_tracker_->FilterImagesForCheckeringForTile(
- &draw_images, &checkered_images, WhichTree::PENDING_TREE);
- EXPECT_EQ(draw_images.size(), 2U);
- EXPECT_EQ(checkered_images.size(), 0U);
+ EXPECT_FALSE(checker_image_tracker_->ShouldCheckerImage(
+ checkerable_image, WhichTree::PENDING_TREE));
+ EXPECT_FALSE(checker_image_tracker_->ShouldCheckerImage(
+ small_non_checkerable_image, WhichTree::PENDING_TREE));
+ EXPECT_FALSE(checker_image_tracker_->ShouldCheckerImage(
+ large_non_checkerable_image, WhichTree::PENDING_TREE));
// Use this set to make the same request from the active tree, we should
// continue checkering this image on the active tree until activation.
- draw_images.clear();
- draw_images.push_back(checkerable_image);
- draw_images.push_back(non_checkerable_image);
- checkered_images.clear();
- checker_image_tracker_->FilterImagesForCheckeringForTile(
- &draw_images, &checkered_images, WhichTree::ACTIVE_TREE);
- EXPECT_EQ(draw_images.size(), 1U);
- EXPECT_EQ(draw_images[0].image(), non_checkerable_image.image());
- EXPECT_EQ(checkered_images.size(), 1U);
- EXPECT_EQ(checkered_images.count(checkerable_image.image()->uniqueID()), 1U);
+ EXPECT_TRUE(checker_image_tracker_->ShouldCheckerImage(
+ checkerable_image, WhichTree::ACTIVE_TREE));
+ EXPECT_FALSE(checker_image_tracker_->ShouldCheckerImage(
+ small_non_checkerable_image, WhichTree::ACTIVE_TREE));
+ EXPECT_FALSE(checker_image_tracker_->ShouldCheckerImage(
+ large_non_checkerable_image, WhichTree::ACTIVE_TREE));
// Activate the sync tree. The images should be unlocked upon activation.
EXPECT_EQ(image_controller_.num_of_locked_images(), 1);
@@ -192,18 +213,13 @@ TEST_F(CheckerImageTrackerTest, NoConsecutiveCheckeringForImage) {
// checkered again in subsequent frames.
SetUpTracker(true);
- DrawImage checkerable_image = CreateImage(ImageType::CHECKERABLE);
- DrawImage non_checkerable_image = CreateImage(ImageType::NON_CHECKERABLE);
- ImageIdFlatSet checkered_images;
- std::vector<DrawImage> draw_images;
+ PaintImage checkerable_image = CreateImage(ImageType::CHECKERABLE);
+ std::vector<PaintImage> paint_images = {checkerable_image};
- draw_images.clear();
- draw_images.push_back(checkerable_image);
- checkered_images.clear();
- checker_image_tracker_->FilterImagesForCheckeringForTile(
- &draw_images, &checkered_images, WhichTree::PENDING_TREE);
- EXPECT_EQ(draw_images.size(), 0U);
- EXPECT_EQ(checkered_images.size(), 1U);
+ CheckerImageTracker::ImageDecodeQueue image_decode_queue =
+ BuildImageDecodeQueue(paint_images, WhichTree::PENDING_TREE);
+ EXPECT_EQ(image_decode_queue.size(), 1U);
+ checker_image_tracker_->ScheduleImageDecodeQueue(image_decode_queue);
// Trigger decode completion, take images to invalidate and activate the sync
// tree.
@@ -212,13 +228,8 @@ TEST_F(CheckerImageTrackerTest, NoConsecutiveCheckeringForImage) {
checker_image_tracker_->DidActivateSyncTree();
// Subsequent requests for this image should not be checkered.
- draw_images.clear();
- draw_images.push_back(checkerable_image);
- checkered_images.clear();
- checker_image_tracker_->FilterImagesForCheckeringForTile(
- &draw_images, &checkered_images, WhichTree::PENDING_TREE);
- EXPECT_EQ(draw_images.size(), 1U);
- EXPECT_EQ(checkered_images.size(), 0U);
+ EXPECT_FALSE(checker_image_tracker_->ShouldCheckerImage(
+ checkerable_image, WhichTree::PENDING_TREE));
}
TEST_F(CheckerImageTrackerTest,
@@ -227,72 +238,182 @@ TEST_F(CheckerImageTrackerTest,
// active tree are tracked correctly.
SetUpTracker(true);
- DrawImage checkerable_image1 = CreateImage(ImageType::CHECKERABLE);
- ImageIdFlatSet checkered_images;
- std::vector<DrawImage> draw_images;
+ PaintImage checkerable_image1 = CreateImage(ImageType::CHECKERABLE);
+ std::vector<PaintImage> paint_images;
+ CheckerImageTracker::ImageDecodeQueue image_decode_queue;
// First request to filter images on the pending and active tree.
- draw_images.push_back(checkerable_image1);
- checker_image_tracker_->FilterImagesForCheckeringForTile(
- &draw_images, &checkered_images, WhichTree::PENDING_TREE);
- EXPECT_EQ(draw_images.size(), 0U);
- EXPECT_EQ(checkered_images.size(), 1U);
+ paint_images.push_back(checkerable_image1);
+ image_decode_queue =
+ BuildImageDecodeQueue(paint_images, WhichTree::PENDING_TREE);
+ EXPECT_EQ(image_decode_queue.size(), 1U);
+ checker_image_tracker_->ScheduleImageDecodeQueue(image_decode_queue);
// The image is also checkered on the active tree while a decode request is
// pending.
- draw_images.clear();
- checkered_images.clear();
- draw_images.push_back(checkerable_image1);
- checker_image_tracker_->FilterImagesForCheckeringForTile(
- &draw_images, &checkered_images, WhichTree::ACTIVE_TREE);
- EXPECT_EQ(draw_images.size(), 0U);
- EXPECT_EQ(checkered_images.size(), 1U);
+ EXPECT_TRUE(checker_image_tracker_->ShouldCheckerImage(
+ checkerable_image1, WhichTree::ACTIVE_TREE));
// Trigger decode completion and take images to invalidate on the sync tree.
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(invalidation_request_pending_);
- ImageIdFlatSet invalidated_images =
+ PaintImageIdFlatSet invalidated_images =
checker_image_tracker_->TakeImagesToInvalidateOnSyncTree();
EXPECT_EQ(invalidated_images.size(), 1U);
- EXPECT_EQ(invalidated_images.count(checkerable_image1.image()->uniqueID()),
- 1U);
+ EXPECT_EQ(invalidated_images.count(checkerable_image1.stable_id()), 1U);
// Second request to filter the same image on the pending and active tree. It
// should be checkered on the active tree, but not the pending tree.
- draw_images.clear();
- checkered_images.clear();
- draw_images.push_back(checkerable_image1);
- checker_image_tracker_->FilterImagesForCheckeringForTile(
- &draw_images, &checkered_images, WhichTree::PENDING_TREE);
- EXPECT_EQ(draw_images.size(), 1U);
- EXPECT_EQ(checkered_images.size(), 0U);
-
- checker_image_tracker_->FilterImagesForCheckeringForTile(
- &draw_images, &checkered_images, WhichTree::ACTIVE_TREE);
- EXPECT_EQ(draw_images.size(), 0U);
- EXPECT_EQ(checkered_images.size(), 1U);
+ EXPECT_TRUE(checker_image_tracker_->ShouldCheckerImage(
+ checkerable_image1, WhichTree::ACTIVE_TREE));
+ EXPECT_FALSE(checker_image_tracker_->ShouldCheckerImage(
+ checkerable_image1, WhichTree::PENDING_TREE));
// New checkerable image on the pending tree.
- DrawImage checkerable_image2 = CreateImage(ImageType::CHECKERABLE);
- draw_images.clear();
- checkered_images.clear();
- draw_images.push_back(checkerable_image2);
- checker_image_tracker_->FilterImagesForCheckeringForTile(
- &draw_images, &checkered_images, WhichTree::PENDING_TREE);
- EXPECT_EQ(draw_images.size(), 0U);
- EXPECT_EQ(checkered_images.size(), 1U);
+ PaintImage checkerable_image2 = CreateImage(ImageType::CHECKERABLE);
+ EXPECT_TRUE(checker_image_tracker_->ShouldCheckerImage(
+ checkerable_image2, WhichTree::PENDING_TREE));
// Activate the sync tree. The initial image should no longer be checkered on
// the active tree.
checker_image_tracker_->DidActivateSyncTree();
+ EXPECT_FALSE(checker_image_tracker_->ShouldCheckerImage(
+ checkerable_image1, WhichTree::ACTIVE_TREE));
+}
+
+TEST_F(CheckerImageTrackerTest, CancelsScheduledDecodes) {
+ SetUpTracker(true);
+
+ PaintImage checkerable_image1 = CreateImage(ImageType::CHECKERABLE);
+ PaintImage checkerable_image2 = CreateImage(ImageType::CHECKERABLE);
+ std::vector<PaintImage> paint_images = {checkerable_image1,
+ checkerable_image2};
+
+ CheckerImageTracker::ImageDecodeQueue image_decode_queue;
+ image_decode_queue =
+ BuildImageDecodeQueue(paint_images, WhichTree::PENDING_TREE);
+ EXPECT_EQ(image_decode_queue.size(), 2U);
+ checker_image_tracker_->ScheduleImageDecodeQueue(
+ std::move(image_decode_queue));
+
+ // Only the first image in the queue should have been decoded.
+ EXPECT_EQ(image_controller_.decodes_requested().size(), 1U);
+ EXPECT_EQ(image_controller_.decodes_requested().count(
+ checkerable_image1.sk_image()->uniqueID()),
+ 1U);
+
+ // Rebuild the queue before the tracker is notified of decode completion,
+ // removing the second image and adding a new one.
+ PaintImage checkerable_image3 = CreateImage(ImageType::CHECKERABLE);
+ paint_images = {checkerable_image1, checkerable_image3};
+ image_decode_queue =
+ BuildImageDecodeQueue(paint_images, WhichTree::PENDING_TREE);
+
+ // The queue has 2 decodes because we are still checkering on the first one.
+ EXPECT_EQ(image_decode_queue.size(), 2U);
+ checker_image_tracker_->ScheduleImageDecodeQueue(
+ std::move(image_decode_queue));
+
+ // We still have only one decode because the tracker keeps only one decode
+ // pending at a time.
+ EXPECT_EQ(image_controller_.decodes_requested().size(), 1U);
+ EXPECT_EQ(image_controller_.decodes_requested().count(
+ checkerable_image1.sk_image()->uniqueID()),
+ 1U);
+
+ // Trigger completion for all decodes. Only 2 images should have been decoded
+ // since the second image was cancelled.
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(image_controller_.decodes_requested().size(), 2U);
+ EXPECT_EQ(image_controller_.decodes_requested().count(
+ checkerable_image3.sk_image()->uniqueID()),
+ 1U);
+ EXPECT_EQ(image_controller_.num_of_locked_images(), 2);
+}
+
+TEST_F(CheckerImageTrackerTest, ClearsTracker) {
+ SetUpTracker(true);
+
+ PaintImage checkerable_image = CreateImage(ImageType::CHECKERABLE);
+ CheckerImageTracker::ImageDecodeQueue image_decode_queue =
+ BuildImageDecodeQueue({checkerable_image}, WhichTree::PENDING_TREE);
+ EXPECT_EQ(image_decode_queue.size(), 1U);
+ checker_image_tracker_->ScheduleImageDecodeQueue(
+ std::move(image_decode_queue));
+ base::RunLoop().RunUntilIdle();
+ checker_image_tracker_->TakeImagesToInvalidateOnSyncTree();
+
+ // The image is no longer checkered on the pending tree.
+ image_decode_queue =
+ BuildImageDecodeQueue({checkerable_image}, WhichTree::PENDING_TREE);
+ EXPECT_EQ(image_decode_queue.size(), 0U);
+ EXPECT_EQ(image_controller_.num_of_locked_images(), 1);
+
+ // Clear the tracker without clearing the async decode tracking. This should
+ // drop the decode but the image should not be checkered.
+ bool can_clear_decode_policy_tracking = false;
+ checker_image_tracker_->ClearTracker(can_clear_decode_policy_tracking);
+ EXPECT_EQ(image_controller_.num_of_locked_images(), 0);
+ image_decode_queue =
+ BuildImageDecodeQueue({checkerable_image}, WhichTree::PENDING_TREE);
+ EXPECT_EQ(image_decode_queue.size(), 0U);
+ checker_image_tracker_->DidActivateSyncTree();
+
+ // Now clear the decode tracking as well. The image will be re-checkered.
+ can_clear_decode_policy_tracking = true;
+ checker_image_tracker_->ClearTracker(can_clear_decode_policy_tracking);
+ image_decode_queue =
+ BuildImageDecodeQueue({checkerable_image}, WhichTree::PENDING_TREE);
+ image_decode_queue =
+ BuildImageDecodeQueue({checkerable_image}, WhichTree::PENDING_TREE);
+ EXPECT_EQ(image_decode_queue.size(), 1U);
+
+ // If an image had been decoded and tracker was cleared after it, we should
+ // continue checkering it.
+ PaintImage checkerable_image2 = CreateImage(ImageType::CHECKERABLE);
+ image_decode_queue =
+ BuildImageDecodeQueue({checkerable_image}, WhichTree::PENDING_TREE);
+ EXPECT_EQ(image_decode_queue.size(), 1U);
+ checker_image_tracker_->ScheduleImageDecodeQueue(
+ std::move(image_decode_queue));
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(image_controller_.num_of_locked_images(), 1);
+ can_clear_decode_policy_tracking = false;
+ checker_image_tracker_->ClearTracker(can_clear_decode_policy_tracking);
+ EXPECT_EQ(image_controller_.num_of_locked_images(), 0);
+ image_decode_queue =
+ BuildImageDecodeQueue({checkerable_image}, WhichTree::PENDING_TREE);
+ EXPECT_EQ(image_decode_queue.size(), 1U);
+}
+
+TEST_F(CheckerImageTrackerTest, CheckersOnlyStaticCompletedImages) {
+ SetUpTracker(true);
- draw_images.clear();
- checkered_images.clear();
- draw_images.push_back(checkerable_image1);
- checker_image_tracker_->FilterImagesForCheckeringForTile(
- &draw_images, &checkered_images, WhichTree::ACTIVE_TREE);
- EXPECT_EQ(draw_images.size(), 1U);
- EXPECT_EQ(checkered_images.size(), 0U);
+ PaintImage static_image = CreateImage(ImageType::CHECKERABLE);
+ PaintImage animated_image =
+ CreateImage(ImageType::CHECKERABLE, PaintImage::AnimationType::ANIMATED);
+ PaintImage partial_image =
+ CreateImage(ImageType::CHECKERABLE, PaintImage::AnimationType::STATIC,
+ PaintImage::CompletionState::PARTIALLY_DONE);
+ PaintImage video_image =
+ CreateImage(ImageType::CHECKERABLE, PaintImage::AnimationType::VIDEO);
+ std::vector<PaintImage> paint_images = {static_image, animated_image,
+ partial_image, video_image};
+
+ CheckerImageTracker::ImageDecodeQueue image_decode_queue =
+ BuildImageDecodeQueue(paint_images, WhichTree::PENDING_TREE);
+ EXPECT_EQ(image_decode_queue.size(), 1U);
+ EXPECT_EQ(image_decode_queue[0], static_image);
+
+ // Change the partial image to complete and try again. It should still not
+ // be checkered.
+ gfx::Size image_size = gfx::Size(partial_image.sk_image()->width(),
+ partial_image.sk_image()->height());
+ PaintImage completed_paint_image =
+ PaintImage(partial_image.stable_id(), CreateDiscardableImage(image_size));
+ EXPECT_FALSE(checker_image_tracker_->ShouldCheckerImage(
+ completed_paint_image, WhichTree::PENDING_TREE));
}
} // namespace
diff --git a/chromium/cc/tiles/gpu_image_decode_cache.cc b/chromium/cc/tiles/gpu_image_decode_cache.cc
index 39a822617db..b30d9da1c6f 100644
--- a/chromium/cc/tiles/gpu_image_decode_cache.cc
+++ b/chromium/cc/tiles/gpu_image_decode_cache.cc
@@ -110,6 +110,38 @@ gfx::Size CalculateSizeForMipLevel(const DrawImage& draw_image, int mip_level) {
return MipMapUtil::GetSizeForLevel(base_size, mip_level);
}
+// Draws and scales the provided |draw_image| into the |target_pixmap|. If the
+// draw/scale can be done directly, calls directly into SkImage::scalePixels,
+// if not, decodes to a compatible temporary pixmap and then converts that into
+// the |target_pixmap|.
+bool DrawAndScaleImage(const DrawImage& draw_image, SkPixmap* target_pixmap) {
+ const SkImage* image = draw_image.image().get();
+ if (image->dimensions() == target_pixmap->bounds().size() ||
+ target_pixmap->info().colorType() == kN32_SkColorType) {
+ // If no scaling is occurring, or if the target colortype is already N32,
+ // just scale directly.
+ return image->scalePixels(*target_pixmap,
+ CalculateUploadScaleFilterQuality(draw_image),
+ SkImage::kDisallow_CachingHint);
+ }
+
+ // If the target colortype is not N32, it may be impossible to scale
+ // directly. Instead scale into an N32 pixmap, and convert that into the
+ // |target_pixmap|.
+ SkImageInfo decode_info =
+ target_pixmap->info().makeColorType(kN32_SkColorType);
+ SkBitmap decode_bitmap;
+ if (!decode_bitmap.tryAllocPixels(decode_info))
+ return false;
+ SkPixmap decode_pixmap(decode_bitmap.info(), decode_bitmap.getPixels(),
+ decode_bitmap.rowBytes());
+ if (!image->scalePixels(decode_pixmap,
+ CalculateUploadScaleFilterQuality(draw_image),
+ SkImage::kDisallow_CachingHint))
+ return false;
+ return decode_pixmap.readPixels(*target_pixmap);
+}
+
} // namespace
// static
@@ -616,6 +648,10 @@ void GpuImageDecodeCache::ClearCache() {
}
}
+size_t GpuImageDecodeCache::GetMaximumMemoryLimitBytes() const {
+ return normal_max_cache_bytes_;
+}
+
bool GpuImageDecodeCache::OnMemoryDump(
const base::trace_event::MemoryDumpArgs& args,
base::trace_event::ProcessMemoryDump* pmd) {
@@ -1100,13 +1136,11 @@ void GpuImageDecodeCache::DecodeImageIfNecessary(const DrawImage& draw_image,
// In order to match GPU scaling quality (which uses mip-maps at high
// quality), we want to use at most medium filter quality for the
// scale.
- SkPixmap image_pixmap(image_info, backing_memory->data(),
- image_info.minRowBytes());
- // Note that scalePixels falls back to readPixels if the sale is 1x, so
+ SkPixmap image_pixmap(image_info.makeColorSpace(nullptr),
+ backing_memory->data(), image_info.minRowBytes());
+ // Note that scalePixels falls back to readPixels if the scale is 1x, so
// no need to special case that as an optimization.
- if (!draw_image.image()->scalePixels(
- image_pixmap, CalculateUploadScaleFilterQuality(draw_image),
- SkImage::kDisallow_CachingHint)) {
+ if (!DrawAndScaleImage(draw_image, &image_pixmap)) {
DLOG(ERROR) << "scalePixels failed.";
backing_memory->Unlock();
backing_memory.reset();
@@ -1119,7 +1153,8 @@ void GpuImageDecodeCache::DecodeImageIfNecessary(const DrawImage& draw_image,
// DCHECKs here to enforce this.
if (!draw_image.image()->getDeferredTextureImageData(
*context_threadsafe_proxy_.get(), &image_data->upload_params, 1,
- backing_memory->data(), nullptr)) {
+ backing_memory->data(), nullptr,
+ ResourceFormatToClosestSkColorType(format_))) {
DLOG(ERROR) << "getDeferredTextureImageData failed despite params "
<< "having validated.";
backing_memory->Unlock();
@@ -1219,7 +1254,8 @@ GpuImageDecodeCache::CreateImageData(const DrawImage& draw_image) {
draw_image.matrix(), CalculateUploadScaleFilterQuality(draw_image),
upload_scale_mip_level);
size_t data_size = draw_image.image()->getDeferredTextureImageData(
- *context_threadsafe_proxy_.get(), &params, 1, nullptr, nullptr);
+ *context_threadsafe_proxy_.get(), &params, 1, nullptr, nullptr,
+ ResourceFormatToClosestSkColorType(format_));
if (data_size == 0) {
// Can't upload image, too large or other failure. Try to use SW fallback.
diff --git a/chromium/cc/tiles/gpu_image_decode_cache.h b/chromium/cc/tiles/gpu_image_decode_cache.h
index 391f048c2e9..f60157742b4 100644
--- a/chromium/cc/tiles/gpu_image_decode_cache.h
+++ b/chromium/cc/tiles/gpu_image_decode_cache.h
@@ -125,6 +125,7 @@ class CC_EXPORT GpuImageDecodeCache
void SetShouldAggressivelyFreeResources(
bool aggressively_free_resources) override;
void ClearCache() override;
+ size_t GetMaximumMemoryLimitBytes() const override;
// MemoryDumpProvider overrides.
bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
@@ -230,7 +231,7 @@ class CC_EXPORT GpuImageDecodeCache
UsageStats usage_stats_;
};
- struct ImageData : public base::RefCounted<ImageData> {
+ struct ImageData : public base::RefCountedThreadSafe<ImageData> {
ImageData(DecodedDataMode mode,
size_t size,
const gfx::ColorSpace& target_color_space,
@@ -250,7 +251,7 @@ class CC_EXPORT GpuImageDecodeCache
UploadedImageData upload;
private:
- friend class base::RefCounted<ImageData>;
+ friend class base::RefCountedThreadSafe<ImageData>;
~ImageData();
};
@@ -347,6 +348,8 @@ class CC_EXPORT GpuImageDecodeCache
sk_sp<GrContextThreadSafeProxy> context_threadsafe_proxy_;
// All members below this point must only be accessed while holding |lock_|.
+ // The exception are const members like |normal_max_cache_bytes_| that can
+ // be accessed without a lock since they are thread safe.
base::Lock lock_;
// |persistent_cache_| represents the long-lived cache, keeping a certain
diff --git a/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc b/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc
index 91a08d1f40c..fb2f91bceaf 100644
--- a/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc
+++ b/chromium/cc/tiles/gpu_image_decode_cache_unittest.cc
@@ -8,6 +8,7 @@
#include "cc/test/test_context_provider.h"
#include "cc/test/test_tile_task_runner.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkImageGenerator.h"
#include "third_party/skia/include/core/SkRefCnt.h"
namespace cc {
@@ -17,22 +18,48 @@ gfx::ColorSpace DefaultColorSpace() {
return gfx::ColorSpace::CreateSRGB();
}
+PaintImage::Id s_paint_image_id = PaintImage::GetNextId();
+
+PaintImage CreatePaintImage(sk_sp<SkImage> image) {
+ return PaintImage(s_paint_image_id, image);
+}
+
size_t kGpuMemoryLimitBytes = 96 * 1024 * 1024;
class TestGpuImageDecodeCache : public GpuImageDecodeCache {
public:
- explicit TestGpuImageDecodeCache(ContextProvider* context)
+ explicit TestGpuImageDecodeCache(ContextProvider* context,
+ ResourceFormat format)
: GpuImageDecodeCache(context,
- ResourceFormat::RGBA_8888,
+ format,
kGpuMemoryLimitBytes,
kGpuMemoryLimitBytes) {}
};
+class TestImageGenerator : public SkImageGenerator {
+ public:
+ explicit TestImageGenerator(const SkImageInfo& info)
+ : SkImageGenerator(info),
+ image_backing_memory_(info.getSafeSize(info.minRowBytes()), 0),
+ image_pixmap_(info, image_backing_memory_.data(), info.minRowBytes()) {}
+
+ protected:
+ bool onGetPixels(const SkImageInfo& info,
+ void* pixels,
+ size_t rowBytes,
+ const Options&) override {
+ return image_pixmap_.readPixels(info, pixels, rowBytes, 0, 0);
+ }
+
+ private:
+ std::vector<uint8_t> image_backing_memory_;
+ SkPixmap image_pixmap_;
+};
+
sk_sp<SkImage> CreateImage(int width, int height) {
- SkBitmap bitmap;
gfx::ColorSpace color_space = gfx::ColorSpace::CreateSRGB();
- bitmap.allocPixels(
- SkImageInfo::MakeN32Premul(width, height, color_space.ToSkColorSpace()));
- return SkImage::MakeFromBitmap(bitmap);
+ std::unique_ptr<TestImageGenerator> generator(new TestImageGenerator(
+ SkImageInfo::MakeN32Premul(width, height, color_space.ToSkColorSpace())));
+ return SkImage::MakeFromGenerator(std::move(generator));
}
SkMatrix CreateMatrix(const SkSize& scale, bool is_decomposable) {
@@ -47,18 +74,20 @@ SkMatrix CreateMatrix(const SkSize& scale, bool is_decomposable) {
return matrix;
}
-TEST(GpuImageDecodeCacheTest, GetTaskForImageSameImage) {
+using GpuImageDecodeCacheTest = ::testing::TestWithParam<ResourceFormat>;
+
+TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSameImage) {
auto context_provider = TestContextProvider::Create();
context_provider->BindToCurrentThread();
- TestGpuImageDecodeCache cache(context_provider.get());
+ TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
sk_sp<SkImage> image = CreateImage(100, 100);
bool is_decomposable = true;
SkFilterQuality quality = kHigh_SkFilterQuality;
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable),
+ DefaultColorSpace());
scoped_refptr<TileTask> task;
bool need_unref = cache.GetTaskForImageAndRef(
draw_image, ImageDecodeCache::TracingInfo(), &task);
@@ -66,8 +95,8 @@ TEST(GpuImageDecodeCacheTest, GetTaskForImageSameImage) {
EXPECT_TRUE(task);
DrawImage another_draw_image(
- image, SkIRect::MakeWH(image->width(), image->height()), quality,
- CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable),
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable),
DefaultColorSpace());
scoped_refptr<TileTask> another_task;
need_unref = cache.GetTaskForImageAndRef(
@@ -82,18 +111,18 @@ TEST(GpuImageDecodeCacheTest, GetTaskForImageSameImage) {
cache.UnrefImage(draw_image);
}
-TEST(GpuImageDecodeCacheTest, GetTaskForImageSmallerScale) {
+TEST_P(GpuImageDecodeCacheTest, GetTaskForImageSmallerScale) {
auto context_provider = TestContextProvider::Create();
context_provider->BindToCurrentThread();
- TestGpuImageDecodeCache cache(context_provider.get());
+ TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
sk_sp<SkImage> image = CreateImage(100, 100);
bool is_decomposable = true;
SkFilterQuality quality = kHigh_SkFilterQuality;
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable),
+ DefaultColorSpace());
scoped_refptr<TileTask> task;
bool need_unref = cache.GetTaskForImageAndRef(
draw_image, ImageDecodeCache::TracingInfo(), &task);
@@ -101,8 +130,8 @@ TEST(GpuImageDecodeCacheTest, GetTaskForImageSmallerScale) {
EXPECT_TRUE(task);
DrawImage another_draw_image(
- image, SkIRect::MakeWH(image->width(), image->height()), quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
DefaultColorSpace());
scoped_refptr<TileTask> another_task;
need_unref = cache.GetTaskForImageAndRef(
@@ -117,21 +146,16 @@ TEST(GpuImageDecodeCacheTest, GetTaskForImageSmallerScale) {
cache.UnrefImage(another_draw_image);
}
-// crbug.com/709341.
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_GetTaskForImageLowerQuality DISABLED_GetTaskForImageLowerQuality
-#else
-#define MAYBE_GetTaskForImageLowerQuality GetTaskForImageLowerQuality
-#endif
-TEST(GpuImageDecodeCacheTest, MAYBE_GetTaskForImageLowerQuality) {
+TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLowerQuality) {
auto context_provider = TestContextProvider::Create();
context_provider->BindToCurrentThread();
- TestGpuImageDecodeCache cache(context_provider.get());
+ TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
sk_sp<SkImage> image = CreateImage(100, 100);
bool is_decomposable = true;
SkMatrix matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f), is_decomposable);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
+ DrawImage draw_image(CreatePaintImage(image),
+ SkIRect::MakeWH(image->width(), image->height()),
kHigh_SkFilterQuality, matrix, DefaultColorSpace());
scoped_refptr<TileTask> task;
bool need_unref = cache.GetTaskForImageAndRef(
@@ -140,7 +164,7 @@ TEST(GpuImageDecodeCacheTest, MAYBE_GetTaskForImageLowerQuality) {
EXPECT_TRUE(task);
DrawImage another_draw_image(
- image, SkIRect::MakeWH(image->width(), image->height()),
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
kLow_SkFilterQuality, matrix, DefaultColorSpace());
scoped_refptr<TileTask> another_task;
need_unref = cache.GetTaskForImageAndRef(
@@ -155,24 +179,18 @@ TEST(GpuImageDecodeCacheTest, MAYBE_GetTaskForImageLowerQuality) {
cache.UnrefImage(another_draw_image);
}
-// crbug.com/709341.
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_GetTaskForImageDifferentImage \
- DISABLED_GetTaskForImageDifferentImage
-#else
-#define MAYBE_GetTaskForImageDifferentImage GetTaskForImageDifferentImage
-#endif
-TEST(GpuImageDecodeCacheTest, MAYBE_GetTaskForImageDifferentImage) {
+TEST_P(GpuImageDecodeCacheTest, GetTaskForImageDifferentImage) {
auto context_provider = TestContextProvider::Create();
context_provider->BindToCurrentThread();
- TestGpuImageDecodeCache cache(context_provider.get());
+ TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
bool is_decomposable = true;
SkFilterQuality quality = kHigh_SkFilterQuality;
sk_sp<SkImage> first_image = CreateImage(100, 100);
DrawImage first_draw_image(
- first_image, SkIRect::MakeWH(first_image->width(), first_image->height()),
- quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ CreatePaintImage(first_image),
+ SkIRect::MakeWH(first_image->width(), first_image->height()), quality,
+ CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
DefaultColorSpace());
scoped_refptr<TileTask> first_task;
bool need_unref = cache.GetTaskForImageAndRef(
@@ -182,7 +200,7 @@ TEST(GpuImageDecodeCacheTest, MAYBE_GetTaskForImageDifferentImage) {
sk_sp<SkImage> second_image = CreateImage(100, 100);
DrawImage second_draw_image(
- second_image,
+ CreatePaintImage(second_image),
SkIRect::MakeWH(second_image->width(), second_image->height()), quality,
CreateMatrix(SkSize::Make(0.25f, 0.25f), is_decomposable),
DefaultColorSpace());
@@ -202,23 +220,18 @@ TEST(GpuImageDecodeCacheTest, MAYBE_GetTaskForImageDifferentImage) {
cache.UnrefImage(second_draw_image);
}
-// crbug.com/709341.
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_GetTaskForImageLargerScale DISABLED_GetTaskForImageLargerScale
-#else
-#define MAYBE_GetTaskForImageLargerScale GetTaskForImageLargerScale
-#endif
-TEST(GpuImageDecodeCacheTest, MAYBE_GetTaskForImageLargerScale) {
+TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScale) {
auto context_provider = TestContextProvider::Create();
context_provider->BindToCurrentThread();
- TestGpuImageDecodeCache cache(context_provider.get());
+ TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
bool is_decomposable = true;
SkFilterQuality quality = kHigh_SkFilterQuality;
sk_sp<SkImage> first_image = CreateImage(100, 100);
DrawImage first_draw_image(
- first_image, SkIRect::MakeWH(first_image->width(), first_image->height()),
- quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ CreatePaintImage(first_image),
+ SkIRect::MakeWH(first_image->width(), first_image->height()), quality,
+ CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
DefaultColorSpace());
scoped_refptr<TileTask> first_task;
bool need_unref = cache.GetTaskForImageAndRef(
@@ -232,8 +245,9 @@ TEST(GpuImageDecodeCacheTest, MAYBE_GetTaskForImageLargerScale) {
cache.UnrefImage(first_draw_image);
DrawImage second_draw_image(
- first_image, SkIRect::MakeWH(first_image->width(), first_image->height()),
- quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
+ CreatePaintImage(first_image),
+ SkIRect::MakeWH(first_image->width(), first_image->height()), quality,
+ CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
DefaultColorSpace());
scoped_refptr<TileTask> second_task;
need_unref = cache.GetTaskForImageAndRef(
@@ -243,8 +257,9 @@ TEST(GpuImageDecodeCacheTest, MAYBE_GetTaskForImageLargerScale) {
EXPECT_TRUE(first_task.get() != second_task.get());
DrawImage third_draw_image(
- first_image, SkIRect::MakeWH(first_image->width(), first_image->height()),
- quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ CreatePaintImage(first_image),
+ SkIRect::MakeWH(first_image->width(), first_image->height()), quality,
+ CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
DefaultColorSpace());
scoped_refptr<TileTask> third_task;
need_unref = cache.GetTaskForImageAndRef(
@@ -259,25 +274,18 @@ TEST(GpuImageDecodeCacheTest, MAYBE_GetTaskForImageLargerScale) {
cache.UnrefImage(third_draw_image);
}
-// crbug.com/709341.
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_GetTaskForImageLargerScaleNoReuse \
- DISABLED_GetTaskForImageLargerScaleNoReuse
-#else
-#define MAYBE_GetTaskForImageLargerScaleNoReuse \
- GetTaskForImageLargerScaleNoReuse
-#endif
-TEST(GpuImageDecodeCacheTest, MAYBE_GetTaskForImageLargerScaleNoReuse) {
+TEST_P(GpuImageDecodeCacheTest, GetTaskForImageLargerScaleNoReuse) {
auto context_provider = TestContextProvider::Create();
context_provider->BindToCurrentThread();
- TestGpuImageDecodeCache cache(context_provider.get());
+ TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
bool is_decomposable = true;
SkFilterQuality quality = kHigh_SkFilterQuality;
sk_sp<SkImage> first_image = CreateImage(100, 100);
DrawImage first_draw_image(
- first_image, SkIRect::MakeWH(first_image->width(), first_image->height()),
- quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ CreatePaintImage(first_image),
+ SkIRect::MakeWH(first_image->width(), first_image->height()), quality,
+ CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
DefaultColorSpace());
scoped_refptr<TileTask> first_task;
bool need_unref = cache.GetTaskForImageAndRef(
@@ -286,8 +294,9 @@ TEST(GpuImageDecodeCacheTest, MAYBE_GetTaskForImageLargerScaleNoReuse) {
EXPECT_TRUE(first_task);
DrawImage second_draw_image(
- first_image, SkIRect::MakeWH(first_image->width(), first_image->height()),
- quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
+ CreatePaintImage(first_image),
+ SkIRect::MakeWH(first_image->width(), first_image->height()), quality,
+ CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
DefaultColorSpace());
scoped_refptr<TileTask> second_task;
need_unref = cache.GetTaskForImageAndRef(
@@ -297,8 +306,9 @@ TEST(GpuImageDecodeCacheTest, MAYBE_GetTaskForImageLargerScaleNoReuse) {
EXPECT_TRUE(first_task.get() != second_task.get());
DrawImage third_draw_image(
- first_image, SkIRect::MakeWH(first_image->width(), first_image->height()),
- quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ CreatePaintImage(first_image),
+ SkIRect::MakeWH(first_image->width(), first_image->height()), quality,
+ CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
DefaultColorSpace());
scoped_refptr<TileTask> third_task;
need_unref = cache.GetTaskForImageAndRef(
@@ -316,22 +326,17 @@ TEST(GpuImageDecodeCacheTest, MAYBE_GetTaskForImageLargerScaleNoReuse) {
cache.UnrefImage(third_draw_image);
}
-// crbug.com/709341.
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_GetTaskForImageHigherQuality DISABLED_GetTaskForImageHigherQuality
-#else
-#define MAYBE_GetTaskForImageHigherQuality GetTaskForImageHigherQuality
-#endif
-TEST(GpuImageDecodeCacheTest, MAYBE_GetTaskForImageHigherQuality) {
+TEST_P(GpuImageDecodeCacheTest, GetTaskForImageHigherQuality) {
auto context_provider = TestContextProvider::Create();
context_provider->BindToCurrentThread();
- TestGpuImageDecodeCache cache(context_provider.get());
+ TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
bool is_decomposable = true;
SkMatrix matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f), is_decomposable);
sk_sp<SkImage> first_image = CreateImage(100, 100);
DrawImage first_draw_image(
- first_image, SkIRect::MakeWH(first_image->width(), first_image->height()),
+ CreatePaintImage(first_image),
+ SkIRect::MakeWH(first_image->width(), first_image->height()),
kLow_SkFilterQuality, matrix, DefaultColorSpace());
scoped_refptr<TileTask> first_task;
bool need_unref = cache.GetTaskForImageAndRef(
@@ -345,7 +350,8 @@ TEST(GpuImageDecodeCacheTest, MAYBE_GetTaskForImageHigherQuality) {
cache.UnrefImage(first_draw_image);
DrawImage second_draw_image(
- first_image, SkIRect::MakeWH(first_image->width(), first_image->height()),
+ CreatePaintImage(first_image),
+ SkIRect::MakeWH(first_image->width(), first_image->height()),
kHigh_SkFilterQuality, matrix, DefaultColorSpace());
scoped_refptr<TileTask> second_task;
need_unref = cache.GetTaskForImageAndRef(
@@ -360,26 +366,18 @@ TEST(GpuImageDecodeCacheTest, MAYBE_GetTaskForImageHigherQuality) {
cache.UnrefImage(second_draw_image);
}
-// crbug.com/709341.
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_GetTaskForImageAlreadyDecodedAndLocked \
- DISABLED_GetTaskForImageAlreadyDecodedAndLocked
-#else
-#define MAYBE_GetTaskForImageAlreadyDecodedAndLocked \
- GetTaskForImageAlreadyDecodedAndLocked
-#endif
-TEST(GpuImageDecodeCacheTest, MAYBE_GetTaskForImageAlreadyDecodedAndLocked) {
+TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyDecodedAndLocked) {
auto context_provider = TestContextProvider::Create();
context_provider->BindToCurrentThread();
- TestGpuImageDecodeCache cache(context_provider.get());
+ TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
bool is_decomposable = true;
SkFilterQuality quality = kHigh_SkFilterQuality;
sk_sp<SkImage> image = CreateImage(100, 100);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ DefaultColorSpace());
scoped_refptr<TileTask> task;
bool need_unref = cache.GetTaskForImageAndRef(
draw_image, ImageDecodeCache::TracingInfo(), &task);
@@ -414,26 +412,18 @@ TEST(GpuImageDecodeCacheTest, MAYBE_GetTaskForImageAlreadyDecodedAndLocked) {
cache.UnrefImage(draw_image);
}
-// crbug.com/709341.
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_GetTaskForImageAlreadyDecodedNotLocked \
- DISABLED_GetTaskForImageAlreadyDecodedNotLocked
-#else
-#define MAYBE_GetTaskForImageAlreadyDecodedNotLocked \
- GetTaskForImageAlreadyDecodedNotLocked
-#endif
-TEST(GpuImageDecodeCacheTest, MAYBE_GetTaskForImageAlreadyDecodedNotLocked) {
+TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyDecodedNotLocked) {
auto context_provider = TestContextProvider::Create();
context_provider->BindToCurrentThread();
- TestGpuImageDecodeCache cache(context_provider.get());
+ TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
bool is_decomposable = true;
SkFilterQuality quality = kHigh_SkFilterQuality;
sk_sp<SkImage> image = CreateImage(100, 100);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ DefaultColorSpace());
scoped_refptr<TileTask> task;
bool need_unref = cache.GetTaskForImageAndRef(
draw_image, ImageDecodeCache::TracingInfo(), &task);
@@ -468,25 +458,18 @@ TEST(GpuImageDecodeCacheTest, MAYBE_GetTaskForImageAlreadyDecodedNotLocked) {
cache.UnrefImage(draw_image);
}
-// crbug.com/709341.
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_GetTaskForImageAlreadyUploaded \
- DISABLED_GetTaskForImageAlreadyUploaded
-#else
-#define MAYBE_GetTaskForImageAlreadyUploaded GetTaskForImageAlreadyUploaded
-#endif
-TEST(GpuImageDecodeCacheTest, MAYBE_GetTaskForImageAlreadyUploaded) {
+TEST_P(GpuImageDecodeCacheTest, GetTaskForImageAlreadyUploaded) {
auto context_provider = TestContextProvider::Create();
context_provider->BindToCurrentThread();
- TestGpuImageDecodeCache cache(context_provider.get());
+ TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
bool is_decomposable = true;
SkFilterQuality quality = kHigh_SkFilterQuality;
sk_sp<SkImage> image = CreateImage(100, 100);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ DefaultColorSpace());
scoped_refptr<TileTask> task;
bool need_unref = cache.GetTaskForImageAndRef(
draw_image, ImageDecodeCache::TracingInfo(), &task);
@@ -511,26 +494,18 @@ TEST(GpuImageDecodeCacheTest, MAYBE_GetTaskForImageAlreadyUploaded) {
cache.UnrefImage(draw_image);
}
-// crbug.com/709341.
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_GetTaskForImageCanceledGetsNewTask \
- DISABLED_GetTaskForImageCanceledGetsNewTask
-#else
-#define MAYBE_GetTaskForImageCanceledGetsNewTask \
- GetTaskForImageCanceledGetsNewTask
-#endif
-TEST(GpuImageDecodeCacheTest, MAYBE_GetTaskForImageCanceledGetsNewTask) {
+TEST_P(GpuImageDecodeCacheTest, GetTaskForImageCanceledGetsNewTask) {
auto context_provider = TestContextProvider::Create();
context_provider->BindToCurrentThread();
- TestGpuImageDecodeCache cache(context_provider.get());
+ TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
bool is_decomposable = true;
SkFilterQuality quality = kHigh_SkFilterQuality;
sk_sp<SkImage> image = CreateImage(100, 100);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ DefaultColorSpace());
scoped_refptr<TileTask> task;
bool need_unref = cache.GetTaskForImageAndRef(
draw_image, ImageDecodeCache::TracingInfo(), &task);
@@ -567,27 +542,18 @@ TEST(GpuImageDecodeCacheTest, MAYBE_GetTaskForImageCanceledGetsNewTask) {
cache.UnrefImage(draw_image);
}
-// crbug.com/709341.
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_GetTaskForImageCanceledWhileReffedGetsNewTask \
- DISABLED_GetTaskForImageCanceledWhileReffedGetsNewTask
-#else
-#define MAYBE_GetTaskForImageCanceledWhileReffedGetsNewTask \
- GetTaskForImageCanceledWhileReffedGetsNewTask
-#endif
-TEST(GpuImageDecodeCacheTest,
- MAYBE_GetTaskForImageCanceledWhileReffedGetsNewTask) {
+TEST_P(GpuImageDecodeCacheTest, GetTaskForImageCanceledWhileReffedGetsNewTask) {
auto context_provider = TestContextProvider::Create();
context_provider->BindToCurrentThread();
- TestGpuImageDecodeCache cache(context_provider.get());
+ TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
bool is_decomposable = true;
SkFilterQuality quality = kHigh_SkFilterQuality;
sk_sp<SkImage> image = CreateImage(100, 100);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ DefaultColorSpace());
scoped_refptr<TileTask> task;
bool need_unref = cache.GetTaskForImageAndRef(
draw_image, ImageDecodeCache::TracingInfo(), &task);
@@ -628,26 +594,18 @@ TEST(GpuImageDecodeCacheTest,
cache.UnrefImage(draw_image);
}
-// crbug.com/709341.
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_NoTaskForImageAlreadyFailedDecoding \
- DISABLED_NoTaskForImageAlreadyFailedDecoding
-#else
-#define MAYBE_NoTaskForImageAlreadyFailedDecoding \
- NoTaskForImageAlreadyFailedDecoding
-#endif
-TEST(GpuImageDecodeCacheTest, MAYBE_NoTaskForImageAlreadyFailedDecoding) {
+TEST_P(GpuImageDecodeCacheTest, NoTaskForImageAlreadyFailedDecoding) {
auto context_provider = TestContextProvider::Create();
context_provider->BindToCurrentThread();
- TestGpuImageDecodeCache cache(context_provider.get());
+ TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
bool is_decomposable = true;
SkFilterQuality quality = kHigh_SkFilterQuality;
sk_sp<SkImage> image = CreateImage(100, 100);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ DefaultColorSpace());
scoped_refptr<TileTask> task;
bool need_unref = cache.GetTaskForImageAndRef(
draw_image, ImageDecodeCache::TracingInfo(), &task);
@@ -670,24 +628,18 @@ TEST(GpuImageDecodeCacheTest, MAYBE_NoTaskForImageAlreadyFailedDecoding) {
cache.UnrefImage(draw_image);
}
-// crbug.com/709341.
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_GetDecodedImageForDraw DISABLED_GetDecodedImageForDraw
-#else
-#define MAYBE_GetDecodedImageForDraw GetDecodedImageForDraw
-#endif
-TEST(GpuImageDecodeCacheTest, MAYBE_GetDecodedImageForDraw) {
+TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDraw) {
auto context_provider = TestContextProvider::Create();
context_provider->BindToCurrentThread();
- TestGpuImageDecodeCache cache(context_provider.get());
+ TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
bool is_decomposable = true;
SkFilterQuality quality = kHigh_SkFilterQuality;
sk_sp<SkImage> image = CreateImage(100, 100);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ DefaultColorSpace());
scoped_refptr<TileTask> task;
bool need_unref = cache.GetTaskForImageAndRef(
draw_image, ImageDecodeCache::TracingInfo(), &task);
@@ -711,18 +663,18 @@ TEST(GpuImageDecodeCacheTest, MAYBE_GetDecodedImageForDraw) {
cache.UnrefImage(draw_image);
}
-TEST(GpuImageDecodeCacheTest, GetLargeDecodedImageForDraw) {
+TEST_P(GpuImageDecodeCacheTest, GetLargeDecodedImageForDraw) {
auto context_provider = TestContextProvider::Create();
context_provider->BindToCurrentThread();
- TestGpuImageDecodeCache cache(context_provider.get());
+ TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
bool is_decomposable = true;
SkFilterQuality quality = kHigh_SkFilterQuality;
sk_sp<SkImage> image = CreateImage(1, 24000);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
+ DefaultColorSpace());
scoped_refptr<TileTask> task;
bool need_unref = cache.GetTaskForImageAndRef(
draw_image, ImageDecodeCache::TracingInfo(), &task);
@@ -747,20 +699,20 @@ TEST(GpuImageDecodeCacheTest, GetLargeDecodedImageForDraw) {
EXPECT_FALSE(cache.DiscardableIsLockedForTesting(draw_image));
}
-TEST(GpuImageDecodeCacheTest, GetDecodedImageForDrawAtRasterDecode) {
+TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawAtRasterDecode) {
auto context_provider = TestContextProvider::Create();
context_provider->BindToCurrentThread();
- TestGpuImageDecodeCache cache(context_provider.get());
+ TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
bool is_decomposable = true;
SkFilterQuality quality = kHigh_SkFilterQuality;
cache.SetAllByteLimitsForTesting(0);
sk_sp<SkImage> image = CreateImage(100, 100);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
+ DefaultColorSpace());
scoped_refptr<TileTask> task;
bool need_unref = cache.GetTaskForImageAndRef(
@@ -781,26 +733,18 @@ TEST(GpuImageDecodeCacheTest, GetDecodedImageForDrawAtRasterDecode) {
cache.DrawWithImageFinished(draw_image, decoded_draw_image);
}
-// crbug.com/709341.
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_GetDecodedImageForDrawLargerScale \
- DISABLED_GetDecodedImageForDrawLargerScale
-#else
-#define MAYBE_GetDecodedImageForDrawLargerScale \
- GetDecodedImageForDrawLargerScale
-#endif
-TEST(GpuImageDecodeCacheTest, MAYBE_GetDecodedImageForDrawLargerScale) {
+TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawLargerScale) {
auto context_provider = TestContextProvider::Create();
context_provider->BindToCurrentThread();
- TestGpuImageDecodeCache cache(context_provider.get());
+ TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
bool is_decomposable = true;
SkFilterQuality quality = kHigh_SkFilterQuality;
sk_sp<SkImage> image = CreateImage(100, 100);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ DefaultColorSpace());
scoped_refptr<TileTask> task;
bool need_unref = cache.GetTaskForImageAndRef(
draw_image, ImageDecodeCache::TracingInfo(), &task);
@@ -811,8 +755,8 @@ TEST(GpuImageDecodeCacheTest, MAYBE_GetDecodedImageForDrawLargerScale) {
TestTileTaskRunner::ProcessTask(task.get());
DrawImage larger_draw_image(
- image, SkIRect::MakeWH(image->width(), image->height()), quality,
- CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable),
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable),
DefaultColorSpace());
scoped_refptr<TileTask> larger_task;
bool larger_need_unref = cache.GetTaskForImageAndRef(
@@ -848,23 +792,16 @@ TEST(GpuImageDecodeCacheTest, MAYBE_GetDecodedImageForDrawLargerScale) {
cache.UnrefImage(larger_draw_image);
}
-// crbug.com/709341.
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_GetDecodedImageForDrawHigherQuality \
- DISABLED_GetDecodedImageForDrawHigherQuality
-#else
-#define MAYBE_GetDecodedImageForDrawHigherQuality \
- GetDecodedImageForDrawHigherQuality
-#endif
-TEST(GpuImageDecodeCacheTest, MAYBE_GetDecodedImageForDrawHigherQuality) {
+TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawHigherQuality) {
auto context_provider = TestContextProvider::Create();
context_provider->BindToCurrentThread();
- TestGpuImageDecodeCache cache(context_provider.get());
+ TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
bool is_decomposable = true;
SkMatrix matrix = CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable);
sk_sp<SkImage> image = CreateImage(100, 100);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
+ DrawImage draw_image(CreatePaintImage(image),
+ SkIRect::MakeWH(image->width(), image->height()),
kLow_SkFilterQuality, matrix, DefaultColorSpace());
scoped_refptr<TileTask> task;
bool need_unref = cache.GetTaskForImageAndRef(
@@ -876,7 +813,7 @@ TEST(GpuImageDecodeCacheTest, MAYBE_GetDecodedImageForDrawHigherQuality) {
TestTileTaskRunner::ProcessTask(task.get());
DrawImage higher_quality_draw_image(
- image, SkIRect::MakeWH(image->width(), image->height()),
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
kHigh_SkFilterQuality, matrix, DefaultColorSpace());
scoped_refptr<TileTask> hq_task;
bool hq_needs_unref = cache.GetTaskForImageAndRef(
@@ -913,25 +850,18 @@ TEST(GpuImageDecodeCacheTest, MAYBE_GetDecodedImageForDrawHigherQuality) {
cache.UnrefImage(higher_quality_draw_image);
}
-// crbug.com/709341.
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_GetDecodedImageForDrawNegative \
- DISABLED_GetDecodedImageForDrawNegative
-#else
-#define MAYBE_GetDecodedImageForDrawNegative GetDecodedImageForDrawNegative
-#endif
-TEST(GpuImageDecodeCacheTest, MAYBE_GetDecodedImageForDrawNegative) {
+TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawNegative) {
auto context_provider = TestContextProvider::Create();
context_provider->BindToCurrentThread();
- TestGpuImageDecodeCache cache(context_provider.get());
+ TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
bool is_decomposable = true;
SkFilterQuality quality = kHigh_SkFilterQuality;
sk_sp<SkImage> image = CreateImage(100, 100);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(-0.5f, 0.5f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(-0.5f, 0.5f), is_decomposable),
+ DefaultColorSpace());
scoped_refptr<TileTask> task;
bool need_unref = cache.GetTaskForImageAndRef(
draw_image, ImageDecodeCache::TracingInfo(), &task);
@@ -957,26 +887,18 @@ TEST(GpuImageDecodeCacheTest, MAYBE_GetDecodedImageForDrawNegative) {
cache.UnrefImage(draw_image);
}
-// crbug.com/709341.
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_GetLargeScaledDecodedImageForDraw \
- DISABLED_GetLargeScaledDecodedImageForDraw
-#else
-#define MAYBE_GetLargeScaledDecodedImageForDraw \
- GetLargeScaledDecodedImageForDraw
-#endif
-TEST(GpuImageDecodeCacheTest, MAYBE_GetLargeScaledDecodedImageForDraw) {
+TEST_P(GpuImageDecodeCacheTest, GetLargeScaledDecodedImageForDraw) {
auto context_provider = TestContextProvider::Create();
context_provider->BindToCurrentThread();
- TestGpuImageDecodeCache cache(context_provider.get());
+ TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
bool is_decomposable = true;
SkFilterQuality quality = kHigh_SkFilterQuality;
sk_sp<SkImage> image = CreateImage(1, 48000);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ DefaultColorSpace());
scoped_refptr<TileTask> task;
bool need_unref = cache.GetTaskForImageAndRef(
draw_image, ImageDecodeCache::TracingInfo(), &task);
@@ -1004,28 +926,20 @@ TEST(GpuImageDecodeCacheTest, MAYBE_GetLargeScaledDecodedImageForDraw) {
EXPECT_FALSE(cache.DiscardableIsLockedForTesting(draw_image));
}
-// crbug.com/709341.
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_AtRasterUsedDirectlyIfSpaceAllows \
- DISABLED_AtRasterUsedDirectlyIfSpaceAllows
-#else
-#define MAYBE_AtRasterUsedDirectlyIfSpaceAllows \
- AtRasterUsedDirectlyIfSpaceAllows
-#endif
-TEST(GpuImageDecodeCacheTest, MAYBE_AtRasterUsedDirectlyIfSpaceAllows) {
+TEST_P(GpuImageDecodeCacheTest, AtRasterUsedDirectlyIfSpaceAllows) {
auto context_provider = TestContextProvider::Create();
context_provider->BindToCurrentThread();
- TestGpuImageDecodeCache cache(context_provider.get());
+ TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
bool is_decomposable = true;
SkFilterQuality quality = kHigh_SkFilterQuality;
cache.SetAllByteLimitsForTesting(0);
sk_sp<SkImage> image = CreateImage(100, 100);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ DefaultColorSpace());
scoped_refptr<TileTask> task;
bool need_unref = cache.GetTaskForImageAndRef(
@@ -1057,29 +971,21 @@ TEST(GpuImageDecodeCacheTest, MAYBE_AtRasterUsedDirectlyIfSpaceAllows) {
cache.UnrefImage(draw_image);
}
-// crbug.com/709341.
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_GetDecodedImageForDrawAtRasterDecodeMultipleTimes \
- DISABLED_GetDecodedImageForDrawAtRasterDecodeMultipleTimes
-#else
-#define MAYBE_GetDecodedImageForDrawAtRasterDecodeMultipleTimes \
- GetDecodedImageForDrawAtRasterDecodeMultipleTimes
-#endif
-TEST(GpuImageDecodeCacheTest,
- MAYBE_GetDecodedImageForDrawAtRasterDecodeMultipleTimes) {
+TEST_P(GpuImageDecodeCacheTest,
+ GetDecodedImageForDrawAtRasterDecodeMultipleTimes) {
auto context_provider = TestContextProvider::Create();
context_provider->BindToCurrentThread();
- TestGpuImageDecodeCache cache(context_provider.get());
+ TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
bool is_decomposable = true;
SkFilterQuality quality = kHigh_SkFilterQuality;
cache.SetAllByteLimitsForTesting(0);
sk_sp<SkImage> image = CreateImage(100, 100);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ DefaultColorSpace());
// Must hold context lock before calling GetDecodedImageForDraw /
// DrawWithImageFinished.
@@ -1100,19 +1006,19 @@ TEST(GpuImageDecodeCacheTest,
cache.DrawWithImageFinished(draw_image, another_decoded_draw_image);
}
-TEST(GpuImageDecodeCacheTest,
- GetLargeDecodedImageForDrawAtRasterDecodeMultipleTimes) {
+TEST_P(GpuImageDecodeCacheTest,
+ GetLargeDecodedImageForDrawAtRasterDecodeMultipleTimes) {
auto context_provider = TestContextProvider::Create();
context_provider->BindToCurrentThread();
- TestGpuImageDecodeCache cache(context_provider.get());
+ TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
bool is_decomposable = true;
SkFilterQuality quality = kHigh_SkFilterQuality;
sk_sp<SkImage> image = CreateImage(1, 24000);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
+ DefaultColorSpace());
// Must hold context lock before calling GetDecodedImageForDraw /
// DrawWithImageFinished.
@@ -1138,18 +1044,18 @@ TEST(GpuImageDecodeCacheTest,
EXPECT_FALSE(cache.DiscardableIsLockedForTesting(draw_image));
}
-TEST(GpuImageDecodeCacheTest, ZeroSizedImagesAreSkipped) {
+TEST_P(GpuImageDecodeCacheTest, ZeroSizedImagesAreSkipped) {
auto context_provider = TestContextProvider::Create();
context_provider->BindToCurrentThread();
- TestGpuImageDecodeCache cache(context_provider.get());
+ TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
bool is_decomposable = true;
SkFilterQuality quality = kHigh_SkFilterQuality;
sk_sp<SkImage> image = CreateImage(100, 100);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(0.f, 0.f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.f, 0.f), is_decomposable),
+ DefaultColorSpace());
scoped_refptr<TileTask> task;
bool need_unref = cache.GetTaskForImageAndRef(
@@ -1167,17 +1073,18 @@ TEST(GpuImageDecodeCacheTest, ZeroSizedImagesAreSkipped) {
cache.DrawWithImageFinished(draw_image, decoded_draw_image);
}
-TEST(GpuImageDecodeCacheTest, NonOverlappingSrcRectImagesAreSkipped) {
+TEST_P(GpuImageDecodeCacheTest, NonOverlappingSrcRectImagesAreSkipped) {
auto context_provider = TestContextProvider::Create();
context_provider->BindToCurrentThread();
- TestGpuImageDecodeCache cache(context_provider.get());
+ TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
bool is_decomposable = true;
SkFilterQuality quality = kHigh_SkFilterQuality;
sk_sp<SkImage> image = CreateImage(100, 100);
DrawImage draw_image(
- image, SkIRect::MakeXYWH(150, 150, image->width(), image->height()),
- quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
+ CreatePaintImage(image),
+ SkIRect::MakeXYWH(150, 150, image->width(), image->height()), quality,
+ CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
DefaultColorSpace());
scoped_refptr<TileTask> task;
@@ -1196,18 +1103,19 @@ TEST(GpuImageDecodeCacheTest, NonOverlappingSrcRectImagesAreSkipped) {
cache.DrawWithImageFinished(draw_image, decoded_draw_image);
}
-TEST(GpuImageDecodeCacheTest, CanceledTasksDoNotCountAgainstBudget) {
+TEST_P(GpuImageDecodeCacheTest, CanceledTasksDoNotCountAgainstBudget) {
auto context_provider = TestContextProvider::Create();
context_provider->BindToCurrentThread();
- TestGpuImageDecodeCache cache(context_provider.get());
+ TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
bool is_decomposable = true;
SkFilterQuality quality = kHigh_SkFilterQuality;
sk_sp<SkImage> image = CreateImage(100, 100);
- DrawImage draw_image(
- image, SkIRect::MakeXYWH(0, 0, image->width(), image->height()), quality,
- CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(CreatePaintImage(image),
+ SkIRect::MakeXYWH(0, 0, image->width(), image->height()),
+ quality,
+ CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
+ DefaultColorSpace());
scoped_refptr<TileTask> task;
bool need_unref = cache.GetTaskForImageAndRef(
@@ -1225,25 +1133,18 @@ TEST(GpuImageDecodeCacheTest, CanceledTasksDoNotCountAgainstBudget) {
EXPECT_EQ(0u, cache.GetBytesUsedForTesting());
}
-// crbug.com/709341.
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_ShouldAggressivelyFreeResources \
- DISABLED_ShouldAggressivelyFreeResources
-#else
-#define MAYBE_ShouldAggressivelyFreeResources ShouldAggressivelyFreeResources
-#endif
-TEST(GpuImageDecodeCacheTest, MAYBE_ShouldAggressivelyFreeResources) {
+TEST_P(GpuImageDecodeCacheTest, ShouldAggressivelyFreeResources) {
auto context_provider = TestContextProvider::Create();
context_provider->BindToCurrentThread();
- TestGpuImageDecodeCache cache(context_provider.get());
+ TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
bool is_decomposable = true;
SkFilterQuality quality = kHigh_SkFilterQuality;
sk_sp<SkImage> image = CreateImage(100, 100);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ DefaultColorSpace());
scoped_refptr<TileTask> task;
{
bool need_unref = cache.GetTaskForImageAndRef(
@@ -1296,26 +1197,19 @@ TEST(GpuImageDecodeCacheTest, MAYBE_ShouldAggressivelyFreeResources) {
}
}
-// crbug.com/709341.
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_OrphanedImagesFreeOnReachingZeroRefs \
- DISABLED_OrphanedImagesFreeOnReachingZeroRefs
-#else
-#define MAYBE_OrphanedImagesFreeOnReachingZeroRefs \
- OrphanedImagesFreeOnReachingZeroRefs
-#endif
-TEST(GpuImageDecodeCacheTest, MAYBE_OrphanedImagesFreeOnReachingZeroRefs) {
+TEST_P(GpuImageDecodeCacheTest, OrphanedImagesFreeOnReachingZeroRefs) {
auto context_provider = TestContextProvider::Create();
context_provider->BindToCurrentThread();
- TestGpuImageDecodeCache cache(context_provider.get());
+ TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
bool is_decomposable = true;
SkFilterQuality quality = kHigh_SkFilterQuality;
// Create a downscaled image.
sk_sp<SkImage> first_image = CreateImage(100, 100);
DrawImage first_draw_image(
- first_image, SkIRect::MakeWH(first_image->width(), first_image->height()),
- quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ CreatePaintImage(first_image),
+ SkIRect::MakeWH(first_image->width(), first_image->height()), quality,
+ CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
DefaultColorSpace());
scoped_refptr<TileTask> first_task;
bool need_unref = cache.GetTaskForImageAndRef(
@@ -1330,8 +1224,9 @@ TEST(GpuImageDecodeCacheTest, MAYBE_OrphanedImagesFreeOnReachingZeroRefs) {
// Create a larger version of |first_image|, this should immediately free the
// memory used by |first_image| for the smaller scale.
DrawImage second_draw_image(
- first_image, SkIRect::MakeWH(first_image->width(), first_image->height()),
- quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
+ CreatePaintImage(first_image),
+ SkIRect::MakeWH(first_image->width(), first_image->height()), quality,
+ CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
DefaultColorSpace());
scoped_refptr<TileTask> second_task;
need_unref = cache.GetTaskForImageAndRef(
@@ -1361,26 +1256,19 @@ TEST(GpuImageDecodeCacheTest, MAYBE_OrphanedImagesFreeOnReachingZeroRefs) {
cache.GetDrawImageSizeForTesting(second_draw_image));
}
-// crbug.com/709341.
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_OrphanedZeroRefImagesImmediatelyDeleted \
- DISABLED_OrphanedZeroRefImagesImmediatelyDeleted
-#else
-#define MAYBE_OrphanedZeroRefImagesImmediatelyDeleted \
- OrphanedZeroRefImagesImmediatelyDeleted
-#endif
-TEST(GpuImageDecodeCacheTest, MAYBE_OrphanedZeroRefImagesImmediatelyDeleted) {
+TEST_P(GpuImageDecodeCacheTest, OrphanedZeroRefImagesImmediatelyDeleted) {
auto context_provider = TestContextProvider::Create();
context_provider->BindToCurrentThread();
- TestGpuImageDecodeCache cache(context_provider.get());
+ TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
bool is_decomposable = true;
SkFilterQuality quality = kHigh_SkFilterQuality;
// Create a downscaled image.
sk_sp<SkImage> first_image = CreateImage(100, 100);
DrawImage first_draw_image(
- first_image, SkIRect::MakeWH(first_image->width(), first_image->height()),
- quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ CreatePaintImage(first_image),
+ SkIRect::MakeWH(first_image->width(), first_image->height()), quality,
+ CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
DefaultColorSpace());
scoped_refptr<TileTask> first_task;
bool need_unref = cache.GetTaskForImageAndRef(
@@ -1399,8 +1287,9 @@ TEST(GpuImageDecodeCacheTest, MAYBE_OrphanedZeroRefImagesImmediatelyDeleted) {
// Create a larger version of |first_image|, this should immediately free the
// memory used by |first_image| for the smaller scale.
DrawImage second_draw_image(
- first_image, SkIRect::MakeWH(first_image->width(), first_image->height()),
- quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
+ CreatePaintImage(first_image),
+ SkIRect::MakeWH(first_image->width(), first_image->height()), quality,
+ CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
DefaultColorSpace());
scoped_refptr<TileTask> second_task;
need_unref = cache.GetTaskForImageAndRef(
@@ -1419,22 +1308,16 @@ TEST(GpuImageDecodeCacheTest, MAYBE_OrphanedZeroRefImagesImmediatelyDeleted) {
cache.GetDrawImageSizeForTesting(second_draw_image));
}
-// crbug.com/709341.
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_QualityCappedAtMedium DISABLED_QualityCappedAtMedium
-#else
-#define MAYBE_QualityCappedAtMedium QualityCappedAtMedium
-#endif
-TEST(GpuImageDecodeCacheTest, MAYBE_QualityCappedAtMedium) {
+TEST_P(GpuImageDecodeCacheTest, QualityCappedAtMedium) {
auto context_provider = TestContextProvider::Create();
context_provider->BindToCurrentThread();
- TestGpuImageDecodeCache cache(context_provider.get());
+ TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
sk_sp<SkImage> image = CreateImage(100, 100);
bool is_decomposable = true;
SkMatrix matrix = CreateMatrix(SkSize::Make(0.4f, 0.4f), is_decomposable);
// Create an image with kLow_FilterQuality.
- DrawImage low_draw_image(image,
+ DrawImage low_draw_image(CreatePaintImage(image),
SkIRect::MakeWH(image->width(), image->height()),
kLow_SkFilterQuality, matrix, DefaultColorSpace());
scoped_refptr<TileTask> low_task;
@@ -1446,7 +1329,7 @@ TEST(GpuImageDecodeCacheTest, MAYBE_QualityCappedAtMedium) {
// Get the same image at kMedium_FilterQuality. We can't re-use low, so we
// should get a new task/ref.
DrawImage medium_draw_image(
- image, SkIRect::MakeWH(image->width(), image->height()),
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
kMedium_SkFilterQuality, matrix, DefaultColorSpace());
scoped_refptr<TileTask> medium_task;
need_unref = cache.GetTaskForImageAndRef(
@@ -1457,7 +1340,7 @@ TEST(GpuImageDecodeCacheTest, MAYBE_QualityCappedAtMedium) {
// Get the same image at kHigh_FilterQuality. We should re-use medium.
DrawImage large_draw_image(
- image, SkIRect::MakeWH(image->width(), image->height()),
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
kHigh_SkFilterQuality, matrix, DefaultColorSpace());
scoped_refptr<TileTask> large_task;
need_unref = cache.GetTaskForImageAndRef(
@@ -1477,19 +1360,19 @@ TEST(GpuImageDecodeCacheTest, MAYBE_QualityCappedAtMedium) {
// Ensure that switching to a mipped version of an image after the initial
// cache entry creation doesn't cause a buffer overflow/crash.
-TEST(GpuImageDecodeCacheTest, GetDecodedImageForDrawMipUsageChange) {
+TEST_P(GpuImageDecodeCacheTest, GetDecodedImageForDrawMipUsageChange) {
auto context_provider = TestContextProvider::Create();
context_provider->BindToCurrentThread();
- TestGpuImageDecodeCache cache(context_provider.get());
+ TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
bool is_decomposable = true;
SkFilterQuality quality = kHigh_SkFilterQuality;
// Create an image decode task and cache entry that does not need mips.
sk_sp<SkImage> image = CreateImage(4000, 4000);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
+ DefaultColorSpace());
scoped_refptr<TileTask> task;
bool need_unref = cache.GetTaskForImageAndRef(
draw_image, ImageDecodeCache::TracingInfo(), &task);
@@ -1510,24 +1393,25 @@ TEST(GpuImageDecodeCacheTest, GetDecodedImageForDrawMipUsageChange) {
// Do an at-raster decode of the above image that *does* require mips.
DrawImage draw_image_mips(
- image, SkIRect::MakeWH(image->width(), image->height()), quality,
- CreateMatrix(SkSize::Make(0.6f, 0.6f), is_decomposable),
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.6f, 0.6f), is_decomposable),
DefaultColorSpace());
DecodedDrawImage decoded_draw_image =
cache.GetDecodedImageForDraw(draw_image_mips);
cache.DrawWithImageFinished(draw_image_mips, decoded_draw_image);
}
-TEST(GpuImageDecodeCacheTest, MemoryStateSuspended) {
+TEST_P(GpuImageDecodeCacheTest, MemoryStateSuspended) {
auto context_provider = TestContextProvider::Create();
context_provider->BindToCurrentThread();
- TestGpuImageDecodeCache cache(context_provider.get());
+ TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
// First Insert an image into our cache.
sk_sp<SkImage> image = CreateImage(1, 1);
bool is_decomposable = true;
SkMatrix matrix = CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
+ DrawImage draw_image(CreatePaintImage(image),
+ SkIRect::MakeWH(image->width(), image->height()),
kLow_SkFilterQuality, matrix, DefaultColorSpace());
scoped_refptr<TileTask> task;
bool need_unref = cache.GetTaskForImageAndRef(
@@ -1588,15 +1472,16 @@ TEST(GpuImageDecodeCacheTest, MemoryStateSuspended) {
cache.UnrefImage(draw_image);
}
-TEST(GpuImageDecodeCacheTest, OutOfRasterDecodeTask) {
+TEST_P(GpuImageDecodeCacheTest, OutOfRasterDecodeTask) {
auto context_provider = TestContextProvider::Create();
context_provider->BindToCurrentThread();
- TestGpuImageDecodeCache cache(context_provider.get());
+ TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
sk_sp<SkImage> image = CreateImage(1, 1);
bool is_decomposable = true;
SkMatrix matrix = CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
+ DrawImage draw_image(CreatePaintImage(image),
+ SkIRect::MakeWH(image->width(), image->height()),
kLow_SkFilterQuality, matrix, DefaultColorSpace());
scoped_refptr<TileTask> task;
@@ -1614,7 +1499,7 @@ TEST(GpuImageDecodeCacheTest, OutOfRasterDecodeTask) {
cache.UnrefImage(draw_image);
}
-TEST(GpuImageDecodeCacheTest, ZeroCacheNormalWorkingSet) {
+TEST_P(GpuImageDecodeCacheTest, ZeroCacheNormalWorkingSet) {
// Setup - Image cache has a normal working set, but zero cache size.
auto context_provider = TestContextProvider::Create();
context_provider->BindToCurrentThread();
@@ -1626,10 +1511,10 @@ TEST(GpuImageDecodeCacheTest, ZeroCacheNormalWorkingSet) {
// Add an image to the cache. Due to normal working set, this should produce
// a task and a ref.
sk_sp<SkImage> image = CreateImage(100, 100);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
+ DefaultColorSpace());
scoped_refptr<TileTask> task;
bool need_unref = cache.GetTaskForImageAndRef(
draw_image, ImageDecodeCache::TracingInfo(), &task);
@@ -1669,7 +1554,7 @@ TEST(GpuImageDecodeCacheTest, ZeroCacheNormalWorkingSet) {
cache.UnrefImage(draw_image);
}
-TEST(GpuImageDecodeCacheTest, SmallCacheNormalWorkingSet) {
+TEST_P(GpuImageDecodeCacheTest, SmallCacheNormalWorkingSet) {
// Cache will fit one (but not two) 100x100 images.
size_t cache_size = 190 * 100 * 4;
@@ -1681,16 +1566,17 @@ TEST(GpuImageDecodeCacheTest, SmallCacheNormalWorkingSet) {
SkFilterQuality quality = kHigh_SkFilterQuality;
sk_sp<SkImage> image = CreateImage(100, 100);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
+ DefaultColorSpace());
sk_sp<SkImage> image2 = CreateImage(100, 100);
- DrawImage draw_image2(
- image2, SkIRect::MakeWH(image2->width(), image2->height()), quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image2(CreatePaintImage(image2),
+ SkIRect::MakeWH(image2->width(), image2->height()),
+ quality,
+ CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
+ DefaultColorSpace());
// Add an image to the cache and un-ref it.
{
@@ -1762,17 +1648,18 @@ TEST(GpuImageDecodeCacheTest, SmallCacheNormalWorkingSet) {
}
}
-TEST(GpuImageDecodeCacheTest, ClearCache) {
+TEST_P(GpuImageDecodeCacheTest, ClearCache) {
auto context_provider = TestContextProvider::Create();
context_provider->BindToCurrentThread();
- TestGpuImageDecodeCache cache(context_provider.get());
+ TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
bool is_decomposable = true;
SkFilterQuality quality = kHigh_SkFilterQuality;
for (int i = 0; i < 10; ++i) {
sk_sp<SkImage> image = CreateImage(100, 100);
DrawImage draw_image(
- image, SkIRect::MakeWH(image->width(), image->height()), quality,
+ CreatePaintImage(image),
+ SkIRect::MakeWH(image->width(), image->height()), quality,
CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
DefaultColorSpace());
scoped_refptr<TileTask> task;
@@ -1797,10 +1684,10 @@ TEST(GpuImageDecodeCacheTest, ClearCache) {
EXPECT_EQ(cache.GetNumCacheEntriesForTesting(), 0u);
}
-TEST(GpuImageDecodeCacheTest, GetTaskForImageDifferentColorSpace) {
+TEST_P(GpuImageDecodeCacheTest, GetTaskForImageDifferentColorSpace) {
auto context_provider = TestContextProvider::Create();
context_provider->BindToCurrentThread();
- TestGpuImageDecodeCache cache(context_provider.get());
+ TestGpuImageDecodeCache cache(context_provider.get(), GetParam());
bool is_decomposable = true;
SkFilterQuality quality = kHigh_SkFilterQuality;
@@ -1809,9 +1696,9 @@ TEST(GpuImageDecodeCacheTest, GetTaskForImageDifferentColorSpace) {
sk_sp<SkImage> first_image = CreateImage(100, 100);
DrawImage first_draw_image(
- first_image, SkIRect::MakeWH(first_image->width(), first_image->height()),
- quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- color_space_a);
+ CreatePaintImage(first_image),
+ SkIRect::MakeWH(first_image->width(), first_image->height()), quality,
+ CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), color_space_a);
scoped_refptr<TileTask> first_task;
bool need_unref = cache.GetTaskForImageAndRef(
first_draw_image, ImageDecodeCache::TracingInfo(), &first_task);
@@ -1819,9 +1706,9 @@ TEST(GpuImageDecodeCacheTest, GetTaskForImageDifferentColorSpace) {
EXPECT_TRUE(first_task);
DrawImage second_draw_image(
- first_image, SkIRect::MakeWH(first_image->width(), first_image->height()),
- quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- color_space_b);
+ CreatePaintImage(first_image),
+ SkIRect::MakeWH(first_image->width(), first_image->height()), quality,
+ CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), color_space_b);
scoped_refptr<TileTask> second_task;
need_unref = cache.GetTaskForImageAndRef(
second_draw_image, ImageDecodeCache::TracingInfo(), &second_task);
@@ -1830,9 +1717,9 @@ TEST(GpuImageDecodeCacheTest, GetTaskForImageDifferentColorSpace) {
EXPECT_TRUE(first_task.get() != second_task.get());
DrawImage third_draw_image(
- first_image, SkIRect::MakeWH(first_image->width(), first_image->height()),
- quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
- color_space_a);
+ CreatePaintImage(first_image),
+ SkIRect::MakeWH(first_image->width(), first_image->height()), quality,
+ CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), color_space_a);
scoped_refptr<TileTask> third_task;
need_unref = cache.GetTaskForImageAndRef(
third_draw_image, ImageDecodeCache::TracingInfo(), &third_task);
@@ -1849,5 +1736,10 @@ TEST(GpuImageDecodeCacheTest, GetTaskForImageDifferentColorSpace) {
cache.UnrefImage(third_draw_image);
}
+INSTANTIATE_TEST_CASE_P(GpuImageDecodeCacheTests,
+ GpuImageDecodeCacheTest,
+ ::testing::Values(ResourceFormat::RGBA_8888,
+ ResourceFormat::RGBA_4444));
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/tiles/image_controller.cc b/chromium/cc/tiles/image_controller.cc
index ae81e64f96d..e8021e4264e 100644
--- a/chromium/cc/tiles/image_controller.cc
+++ b/chromium/cc/tiles/image_controller.cc
@@ -127,12 +127,15 @@ void ImageController::SetImageDecodeCache(ImageDecodeCache* cache) {
SetPredecodeImages(std::vector<DrawImage>(),
ImageDecodeCache::TracingInfo());
StopWorkerTasks();
+ image_cache_max_limit_bytes_ = 0u;
}
cache_ = cache;
- if (cache_)
+ if (cache_) {
+ image_cache_max_limit_bytes_ = cache_->GetMaximumMemoryLimitBytes();
GenerateTasksForOrphanedRequests();
+ }
}
void ImageController::GetTasksForImagesAndRef(
@@ -192,8 +195,12 @@ ImageController::ImageDecodeRequestId ImageController::QueueImageDecode(
DCHECK(image);
bool is_image_lazy = image->isLazyGenerated();
auto image_bounds = image->bounds();
- DrawImage draw_image(std::move(image), image_bounds, kNone_SkFilterQuality,
- SkMatrix::I(), target_color_space);
+ // TODO(khushalsagar): Eliminate the use of an incorrect id here and have all
+ // call-sites provide PaintImage to the ImageController.
+ DrawImage draw_image(
+ PaintImage(PaintImage::kUnknownStableId,
+ sk_sp<SkImage>(const_cast<SkImage*>(image.release()))),
+ image_bounds, kNone_SkFilterQuality, SkMatrix::I(), target_color_space);
// Get the tasks for this decode.
scoped_refptr<TileTask> task;
diff --git a/chromium/cc/tiles/image_controller.h b/chromium/cc/tiles/image_controller.h
index d9253368bb8..30e93f68b18 100644
--- a/chromium/cc/tiles/image_controller.h
+++ b/chromium/cc/tiles/image_controller.h
@@ -9,9 +9,11 @@
#include <vector>
#include "base/callback.h"
+#include "base/containers/flat_map.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
+#include "base/sequenced_task_runner.h"
#include "base/threading/simple_thread.h"
#include "cc/base/unique_notifier.h"
#include "cc/cc_export.h"
@@ -55,6 +57,13 @@ class CC_EXPORT ImageController {
virtual ImageDecodeRequestId QueueImageDecode(
sk_sp<const SkImage> image,
const ImageDecodedCallback& callback);
+ size_t image_cache_max_limit_bytes() const {
+ return image_cache_max_limit_bytes_;
+ }
+
+ void SetMaxImageCacheLimitBytesForTesting(size_t bytes) {
+ image_cache_max_limit_bytes_ = bytes;
+ }
protected:
scoped_refptr<base::SequencedTaskRunner> worker_task_runner_;
@@ -93,9 +102,10 @@ class CC_EXPORT ImageController {
std::vector<DrawImage> predecode_locked_images_;
static ImageDecodeRequestId s_next_image_decode_queue_id_;
- std::unordered_map<ImageDecodeRequestId, DrawImage> requested_locked_images_;
+ base::flat_map<ImageDecodeRequestId, DrawImage> requested_locked_images_;
base::SequencedTaskRunner* origin_task_runner_ = nullptr;
+ size_t image_cache_max_limit_bytes_ = 0u;
// The variables defined below this lock (aside from weak_ptr_factory_) can
// only be accessed when the lock is acquired.
diff --git a/chromium/cc/tiles/image_controller_unittest.cc b/chromium/cc/tiles/image_controller_unittest.cc
index 3a89afb2b64..a4a565774a4 100644
--- a/chromium/cc/tiles/image_controller_unittest.cc
+++ b/chromium/cc/tiles/image_controller_unittest.cc
@@ -80,7 +80,7 @@ class WorkerTaskRunner : public base::SequencedTaskRunner {
return true;
}
- bool RunsTasksOnCurrentThread() const override { return false; }
+ bool RunsTasksInCurrentSequence() const override { return false; }
protected:
~WorkerTaskRunner() override {
@@ -129,6 +129,9 @@ class TestableCache : public ImageDecodeCache {
void SetShouldAggressivelyFreeResources(
bool aggressively_free_resources) override {}
void ClearCache() override {}
+ size_t GetMaximumMemoryLimitBytes() const override {
+ return 256 * 1024 * 1024;
+ }
int number_of_refs() const { return number_of_refs_; }
void SetTaskToUse(scoped_refptr<TileTask> task) { task_to_use_ = task; }
diff --git a/chromium/cc/tiles/image_decode_cache.h b/chromium/cc/tiles/image_decode_cache.h
index ca1f41e4cd9..1b550a6b06e 100644
--- a/chromium/cc/tiles/image_decode_cache.h
+++ b/chromium/cc/tiles/image_decode_cache.h
@@ -96,6 +96,12 @@ class CC_EXPORT ImageDecodeCache {
// Clears all elements from the cache.
virtual void ClearCache() = 0;
+
+ // Returns the maximum amount of memory we would be able to lock. This ignores
+ // any temporary states, such as throttled, and return the maximum possible
+ // memory. It is used as an esimate of whether an image can fit into the
+ // locked budget before creating a task.
+ virtual size_t GetMaximumMemoryLimitBytes() const = 0;
};
} // namespace cc
diff --git a/chromium/cc/tiles/picture_layer_tiling.cc b/chromium/cc/tiles/picture_layer_tiling.cc
index 344cb32b6c0..2a20ddcc2e9 100644
--- a/chromium/cc/tiles/picture_layer_tiling.cc
+++ b/chromium/cc/tiles/picture_layer_tiling.cc
@@ -11,7 +11,7 @@
#include <limits>
#include <set>
-#include "base/containers/small_map.h"
+#include "base/containers/flat_map.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/numerics/safe_conversions.h"
@@ -257,12 +257,8 @@ void PictureLayerTiling::RemoveTilesInRegion(const Region& layer_invalidation,
// twin, so it's slated for removal in the future.
if (live_tiles_rect_.IsEmpty())
return;
- // Pick 16 for the size of the SmallMap before it promotes to a unordered_map.
- // 4x4 tiles should cover most small invalidations, and walking a vector of
- // 16 is fast enough. If an invalidation is huge we will fall back to a
- // unordered_map instead of a vector in the SmallMap.
- base::SmallMap<std::unordered_map<TileMapKey, gfx::Rect, TileMapKeyHash>, 16>
- remove_tiles;
+
+ base::flat_map<TileMapKey, gfx::Rect> remove_tiles;
gfx::Rect expanded_live_tiles_rect =
tiling_data_.ExpandRectToTileBounds(live_tiles_rect_);
for (Region::Iterator iter(layer_invalidation); iter.has_rect();
@@ -380,9 +376,8 @@ PictureLayerTiling::CoverageIterator::CoverageIterator(
const gfx::Rect& coverage_rect)
: tiling_(tiling),
coverage_rect_(coverage_rect),
- coverage_to_content_(
- gfx::PreScaleAxisTransform2d(tiling->raster_transform(),
- 1.f / coverage_scale)) {
+ coverage_to_content_(tiling->raster_transform().scale() / coverage_scale,
+ tiling->raster_transform().translation()) {
DCHECK(tiling_);
// In order to avoid artifacts in geometry_rect scaling and clamping to ints,
// the |coverage_scale| should always be at least as big as the tiling's
@@ -439,25 +434,70 @@ PictureLayerTiling::CoverageIterator::operator++() {
return *this;
bool first_time = tile_i_ < left_;
- bool new_row = false;
- tile_i_++;
- if (tile_i_ > right_) {
- tile_i_ = left_;
- tile_j_++;
- new_row = true;
- if (tile_j_ > bottom_) {
- current_tile_ = NULL;
- return *this;
+ while (true) {
+ bool new_row = false;
+ tile_i_++;
+ if (tile_i_ > right_) {
+ tile_i_ = left_;
+ tile_j_++;
+ new_row = true;
+ if (tile_j_ > bottom_) {
+ current_tile_ = NULL;
+ break;
+ }
}
- }
- current_tile_ = tiling_->TileAt(tile_i_, tile_j_);
+ DCHECK_LT(tile_i_, tiling_->tiling_data_.num_tiles_x());
+ DCHECK_LT(tile_j_, tiling_->tiling_data_.num_tiles_y());
+ current_tile_ = tiling_->TileAt(tile_i_, tile_j_);
+
+ gfx::Rect geometry_rect_candidate = ComputeGeometryRect();
+
+ // This can happen due to floating point inprecision when calculating the
+ // |wanted_texels| area in the constructor.
+ if (geometry_rect_candidate.IsEmpty())
+ continue;
+
+ gfx::Rect last_geometry_rect = current_geometry_rect_;
+ current_geometry_rect_ = geometry_rect_candidate;
+
+ if (first_time)
+ break;
+
+ // Iteration happens left->right, top->bottom. Running off the bottom-right
+ // edge is handled by the intersection above with dest_rect_. Here we make
+ // sure that the new current geometry rect doesn't overlap with the last.
+ int min_left;
+ int min_top;
+ if (new_row) {
+ min_left = coverage_rect_.x();
+ min_top = last_geometry_rect.bottom();
+ } else {
+ min_left = last_geometry_rect.right();
+ min_top = last_geometry_rect.y();
+ }
+
+ int inset_left = std::max(0, min_left - current_geometry_rect_.x());
+ int inset_top = std::max(0, min_top - current_geometry_rect_.y());
+ current_geometry_rect_.Inset(inset_left, inset_top, 0, 0);
+
+#if DCHECK_IS_ON()
+ if (!new_row) {
+ DCHECK_EQ(last_geometry_rect.right(), current_geometry_rect_.x());
+ DCHECK_EQ(last_geometry_rect.bottom(), current_geometry_rect_.bottom());
+ DCHECK_EQ(last_geometry_rect.y(), current_geometry_rect_.y());
+ }
+#endif
+ break;
+ }
+ return *this;
+}
+
+gfx::Rect PictureLayerTiling::CoverageIterator::ComputeGeometryRect() const {
// Calculate the current geometry rect. As we reserved overlap between tiles
// to accommodate bilinear filtering and rounding errors in destination
// space, the geometry rect might overlap on the edges.
- gfx::Rect last_geometry_rect = current_geometry_rect_;
-
gfx::RectF texel_extent = tiling_->tiling_data_.TexelExtent(tile_i_, tile_j_);
{
// Adjust tile extent to accommodate numerical errors.
@@ -474,7 +514,7 @@ PictureLayerTiling::CoverageIterator::operator++() {
// Convert texel_extent to coverage scale, which is what we have to report
// geometry_rect in.
- current_geometry_rect_ =
+ gfx::Rect candidate =
gfx::ToEnclosedRect(coverage_to_content_.InverseMapRect(texel_extent));
{
// Adjust external edges to cover the whole layer in dest space.
@@ -486,48 +526,18 @@ PictureLayerTiling::CoverageIterator::operator++() {
// sampled as the AA fragment shader clamps sample coordinate and
// antialiasing itself.
const TilingData& data = tiling_->tiling_data_;
- current_geometry_rect_.Inset(tile_i_ ? 0 : -current_geometry_rect_.x(),
- tile_j_ ? 0 : -current_geometry_rect_.y(),
- (tile_i_ != data.num_tiles_x() - 1)
- ? 0
- : current_geometry_rect_.right() -
- coverage_rect_max_bounds_.width(),
- (tile_j_ != data.num_tiles_y() - 1)
- ? 0
- : current_geometry_rect_.bottom() -
- coverage_rect_max_bounds_.height());
+ candidate.Inset(
+ tile_i_ ? 0 : -candidate.x(), tile_j_ ? 0 : -candidate.y(),
+ (tile_i_ != data.num_tiles_x() - 1)
+ ? 0
+ : candidate.right() - coverage_rect_max_bounds_.width(),
+ (tile_j_ != data.num_tiles_y() - 1)
+ ? 0
+ : candidate.bottom() - coverage_rect_max_bounds_.height());
}
- current_geometry_rect_.Intersect(coverage_rect_);
- DCHECK(!current_geometry_rect_.IsEmpty());
-
- if (first_time)
- return *this;
-
- // Iteration happens left->right, top->bottom. Running off the bottom-right
- // edge is handled by the intersection above with dest_rect_. Here we make
- // sure that the new current geometry rect doesn't overlap with the last.
- int min_left;
- int min_top;
- if (new_row) {
- min_left = coverage_rect_.x();
- min_top = last_geometry_rect.bottom();
- } else {
- min_left = last_geometry_rect.right();
- min_top = last_geometry_rect.y();
- }
-
- int inset_left = std::max(0, min_left - current_geometry_rect_.x());
- int inset_top = std::max(0, min_top - current_geometry_rect_.y());
- current_geometry_rect_.Inset(inset_left, inset_top, 0, 0);
-
- if (!new_row) {
- DCHECK_EQ(last_geometry_rect.right(), current_geometry_rect_.x());
- DCHECK_EQ(last_geometry_rect.bottom(), current_geometry_rect_.bottom());
- DCHECK_EQ(last_geometry_rect.y(), current_geometry_rect_.y());
- }
-
- return *this;
+ candidate.Intersect(coverage_rect_);
+ return candidate;
}
gfx::Rect PictureLayerTiling::CoverageIterator::geometry_rect() const {
@@ -808,6 +818,39 @@ bool PictureLayerTiling::IsTileRequiredForDraw(const Tile* tile) const {
return true;
}
+bool PictureLayerTiling::ShouldDecodeCheckeredImagesForTile(
+ const Tile* tile) const {
+ // If this is the pending tree and the tile is not occluded, any checkered
+ // images on this tile should be decoded.
+ if (tree_ == PENDING_TREE)
+ return !IsTileOccludedOnCurrentTree(tile);
+
+ DCHECK_EQ(tree_, ACTIVE_TREE);
+ const PictureLayerTiling* pending_twin =
+ client_->GetPendingOrActiveTwinTiling(this);
+
+ // If we don't have a pending twin, then 2 cases are possible. Either we don't
+ // have a pending tree, in which case we should be decoding images for tiles
+ // which are unoccluded.
+ // If we do have a pending tree, then not having a twin implies that this
+ // tiling will be evicted upon activation. TODO(khushalsagar): Plumb this
+ // information here and return false for this case.
+ if (!pending_twin)
+ return !IsTileOccludedOnCurrentTree(tile);
+
+ // If the tile will be replaced upon activation, then we don't need to process
+ // it for checkered images. Since once the pending tree is activated, it is
+ // the new active tree's content that we will invalidate and replace once the
+ // decode finishes.
+ if (!TilingMatchesTileIndices(pending_twin) ||
+ pending_twin->TileAt(tile->tiling_i_index(), tile->tiling_j_index())) {
+ return false;
+ }
+
+ // Ask the pending twin if this tile will become occluded upon activation.
+ return !pending_twin->IsTileOccludedOnCurrentTree(tile);
+}
+
void PictureLayerTiling::UpdateRequiredStatesOnTile(Tile* tile) const {
tile->set_required_for_activation(IsTileRequiredForActivation(tile));
tile->set_required_for_draw(IsTileRequiredForDraw(tile));
@@ -836,7 +879,8 @@ PrioritizedTile PictureLayerTiling::MakePrioritizedTile(
tile_priority.distance_to_visible >
0.5f * max_skewport_extent_in_screen_space_);
return PrioritizedTile(tile, this, tile_priority, IsTileOccluded(tile),
- process_for_images_only);
+ process_for_images_only,
+ ShouldDecodeCheckeredImagesForTile(tile));
}
std::map<const Tile*, PrioritizedTile>
diff --git a/chromium/cc/tiles/picture_layer_tiling.h b/chromium/cc/tiles/picture_layer_tiling.h
index ecf1974efa8..d49d22ed23f 100644
--- a/chromium/cc/tiles/picture_layer_tiling.h
+++ b/chromium/cc/tiles/picture_layer_tiling.h
@@ -63,6 +63,9 @@ struct TileMapKey {
bool operator==(const TileMapKey& other) const {
return index_x == other.index_x && index_y == other.index_y;
}
+ bool operator<(const TileMapKey& other) const {
+ return std::tie(index_x, index_y) < std::tie(other.index_x, other.index_y);
+ }
int index_x;
int index_y;
@@ -105,6 +108,10 @@ class CC_EXPORT PictureLayerTiling {
bool IsTileRequiredForActivation(const Tile* tile) const;
bool IsTileRequiredForDraw(const Tile* tile) const;
+ // Returns true if the tile should be processed for decoding images skipped
+ // during rasterization.
+ bool ShouldDecodeCheckeredImagesForTile(const Tile* tile) const;
+
void set_resolution(TileResolution resolution) {
resolution_ = resolution;
may_contain_low_resolution_tiles_ |= resolution == LOW_RESOLUTION;
@@ -230,6 +237,8 @@ class CC_EXPORT PictureLayerTiling {
int j() const { return tile_j_; }
private:
+ gfx::Rect ComputeGeometryRect() const;
+
const PictureLayerTiling* tiling_ = nullptr;
gfx::Size coverage_rect_max_bounds_;
gfx::Rect coverage_rect_;
diff --git a/chromium/cc/tiles/picture_layer_tiling_set.h b/chromium/cc/tiles/picture_layer_tiling_set.h
index 30c1d2967d7..ed71afa177d 100644
--- a/chromium/cc/tiles/picture_layer_tiling_set.h
+++ b/chromium/cc/tiles/picture_layer_tiling_set.h
@@ -107,6 +107,9 @@ class CC_EXPORT PictureLayerTilingSet {
// the aspect ratio.
float GetMaximumContentsScale() const;
+ // Remove one tiling.
+ void Remove(PictureLayerTiling* tiling);
+
// Removes all tilings with a contents scale key < |minimum_scale_key|.
void RemoveTilingsBelowScaleKey(float minimum_scale_key);
@@ -226,8 +229,6 @@ class CC_EXPORT PictureLayerTilingSet {
scoped_refptr<RasterSource> raster_source,
const Region& layer_invalidation);
- // Remove one tiling.
- void Remove(PictureLayerTiling* tiling);
void VerifyTilings(const PictureLayerTilingSet* pending_twin_set) const;
bool TilingsNeedUpdate(const gfx::Rect& required_rect_in_layer_space,
diff --git a/chromium/cc/tiles/picture_layer_tiling_unittest.cc b/chromium/cc/tiles/picture_layer_tiling_unittest.cc
index f6185bf3638..39d5867a0a9 100644
--- a/chromium/cc/tiles/picture_layer_tiling_unittest.cc
+++ b/chromium/cc/tiles/picture_layer_tiling_unittest.cc
@@ -1255,5 +1255,33 @@ TEST_F(PictureLayerTilingIteratorTest, FractionalTranslatedTilingOverflow) {
EXPECT_FALSE(++iter);
}
+TEST_F(PictureLayerTilingIteratorTest, EdgeCaseLargeIntBounds) {
+ gfx::Size tile_size(256, 256);
+ float scale = 7352.331055f;
+ gfx::Size layer_bounds(292082, 26910);
+ gfx::Rect coverage_rect(2104641536, 522015, 29440, 66172);
+ Initialize(tile_size, scale, layer_bounds);
+ int count = 0;
+ for (PictureLayerTiling::CoverageIterator
+ iter(tiling_.get(), scale, coverage_rect);
+ iter && count < 200; ++count, ++iter) {
+ EXPECT_FALSE(iter.geometry_rect().IsEmpty());
+ }
+}
+
+TEST_F(PictureLayerTilingIteratorTest, EdgeCaseLargeIntBounds2) {
+ gfx::RectF rect(2104670720.f, 522014.5f, 192.f, 1.f);
+ gfx::Size tile_size(256, 256);
+ float scale = 7352.331055f;
+ gfx::Size layer_bounds(292082, 26910);
+ gfx::Rect coverage_rect(2104670720, 522015, 192, 1);
+ Initialize(tile_size, scale, layer_bounds);
+ for (PictureLayerTiling::CoverageIterator iter(tiling_.get(), scale,
+ coverage_rect);
+ iter; ++iter) {
+ EXPECT_FALSE(iter.geometry_rect().IsEmpty());
+ }
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/tiles/prioritized_tile.cc b/chromium/cc/tiles/prioritized_tile.cc
index a76963d340e..cd6e901959d 100644
--- a/chromium/cc/tiles/prioritized_tile.cc
+++ b/chromium/cc/tiles/prioritized_tile.cc
@@ -15,12 +15,15 @@ PrioritizedTile::PrioritizedTile(Tile* tile,
const PictureLayerTiling* source_tiling,
const TilePriority& priority,
bool is_occluded,
- bool is_process_for_images_only)
+ bool is_process_for_images_only,
+ bool should_decode_checkered_images_for_tile)
: tile_(tile),
source_tiling_(source_tiling),
priority_(priority),
is_occluded_(is_occluded),
- is_process_for_images_only_(is_process_for_images_only) {}
+ is_process_for_images_only_(is_process_for_images_only),
+ should_decode_checkered_images_for_tile_(
+ should_decode_checkered_images_for_tile) {}
PrioritizedTile::~PrioritizedTile() = default;
diff --git a/chromium/cc/tiles/prioritized_tile.h b/chromium/cc/tiles/prioritized_tile.h
index 7decc73cca1..a2996602c7f 100644
--- a/chromium/cc/tiles/prioritized_tile.h
+++ b/chromium/cc/tiles/prioritized_tile.h
@@ -24,7 +24,8 @@ class CC_EXPORT PrioritizedTile {
const PictureLayerTiling* source_tiling,
const TilePriority& priority,
bool is_occluded,
- bool is_process_for_images_only);
+ bool is_process_for_images_only,
+ bool should_decode_checkered_images_for_tile);
~PrioritizedTile();
Tile* tile() const { return tile_; }
@@ -36,6 +37,9 @@ class CC_EXPORT PrioritizedTile {
bool is_process_for_images_only() const {
return is_process_for_images_only_;
}
+ bool should_decode_checkered_images_for_tile() const {
+ return should_decode_checkered_images_for_tile_;
+ }
void AsValueInto(base::trace_event::TracedValue* value) const;
@@ -45,6 +49,7 @@ class CC_EXPORT PrioritizedTile {
TilePriority priority_;
bool is_occluded_ = false;
bool is_process_for_images_only_ = false;
+ bool should_decode_checkered_images_for_tile_ = false;
};
} // namespace cc
diff --git a/chromium/cc/tiles/software_image_decode_cache.cc b/chromium/cc/tiles/software_image_decode_cache.cc
index 716d1f45ef3..c3b6eb7d4f0 100644
--- a/chromium/cc/tiles/software_image_decode_cache.cc
+++ b/chromium/cc/tiles/software_image_decode_cache.cc
@@ -250,7 +250,7 @@ bool SoftwareImageDecodeCache::GetTaskForImageAndRefInternal(
// image does not fit into the budget, then we don't ref this image, since it
// will be decoded at raster time which is when it will be temporarily put in
// the cache.
- ImageKey key = ImageKey::FromDrawImage(image);
+ ImageKey key = ImageKey::FromDrawImage(image, format_);
TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"SoftwareImageDecodeCache::GetTaskForImageAndRef", "key",
key.ToString());
@@ -345,7 +345,7 @@ void SoftwareImageDecodeCache::UnrefImage(const DrawImage& image) {
// 2a. The image isn't in the locked cache because we didn't get to decode
// it yet (or failed to decode it).
// 2b. Unlock the image but keep it in list.
- const ImageKey& key = ImageKey::FromDrawImage(image);
+ const ImageKey& key = ImageKey::FromDrawImage(image, format_);
TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"SoftwareImageDecodeCache::UnrefImage", "key", key.ToString());
@@ -445,11 +445,11 @@ SoftwareImageDecodeCache::DecodeImageInternal(const ImageKey& key,
case kNone_SkFilterQuality:
case kLow_SkFilterQuality:
if (key.should_use_subrect())
- return GetSubrectImageDecode(key, std::move(image));
+ return GetSubrectImageDecode(key, draw_image.paint_image());
return GetOriginalSizeImageDecode(key, std::move(image));
case kMedium_SkFilterQuality:
case kHigh_SkFilterQuality:
- return GetScaledImageDecode(key, std::move(image));
+ return GetScaledImageDecode(key, draw_image.paint_image());
default:
NOTREACHED();
return nullptr;
@@ -458,7 +458,7 @@ SoftwareImageDecodeCache::DecodeImageInternal(const ImageKey& key,
DecodedDrawImage SoftwareImageDecodeCache::GetDecodedImageForDraw(
const DrawImage& draw_image) {
- ImageKey key = ImageKey::FromDrawImage(draw_image);
+ ImageKey key = ImageKey::FromDrawImage(draw_image, format_);
TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"SoftwareImageDecodeCache::GetDecodedImageForDraw", "key",
key.ToString());
@@ -611,15 +611,16 @@ SoftwareImageDecodeCache::GetOriginalSizeImageDecode(
std::unique_ptr<SoftwareImageDecodeCache::DecodedImage>
SoftwareImageDecodeCache::GetSubrectImageDecode(const ImageKey& key,
- sk_sp<const SkImage> image) {
+ const PaintImage& image) {
// Construct a key to use in GetDecodedImageForDrawInternal().
// This allows us to reuse an image in any cache if available.
- gfx::Rect full_image_rect(image->width(), image->height());
- DrawImage original_size_draw_image(
- std::move(image), gfx::RectToSkIRect(full_image_rect),
- kNone_SkFilterQuality, SkMatrix::I(), key.target_color_space());
+ gfx::Rect full_image_rect(image.sk_image()->width(),
+ image.sk_image()->height());
+ DrawImage original_size_draw_image(image, gfx::RectToSkIRect(full_image_rect),
+ kNone_SkFilterQuality, SkMatrix::I(),
+ key.target_color_space());
ImageKey original_size_key =
- ImageKey::FromDrawImage(original_size_draw_image);
+ ImageKey::FromDrawImage(original_size_draw_image, format_);
sk_sp<SkColorSpace> target_color_space =
key.target_color_space().ToSkColorSpace();
@@ -674,15 +675,16 @@ SoftwareImageDecodeCache::GetSubrectImageDecode(const ImageKey& key,
std::unique_ptr<SoftwareImageDecodeCache::DecodedImage>
SoftwareImageDecodeCache::GetScaledImageDecode(const ImageKey& key,
- sk_sp<const SkImage> image) {
+ const PaintImage& image) {
// Construct a key to use in GetDecodedImageForDrawInternal().
// This allows us to reuse an image in any cache if available.
- gfx::Rect full_image_rect(image->width(), image->height());
- DrawImage original_size_draw_image(
- std::move(image), gfx::RectToSkIRect(full_image_rect),
- kNone_SkFilterQuality, SkMatrix::I(), key.target_color_space());
+ gfx::Rect full_image_rect(image.sk_image()->width(),
+ image.sk_image()->height());
+ DrawImage original_size_draw_image(image, gfx::RectToSkIRect(full_image_rect),
+ kNone_SkFilterQuality, SkMatrix::I(),
+ key.target_color_space());
ImageKey original_size_key =
- ImageKey::FromDrawImage(original_size_draw_image);
+ ImageKey::FromDrawImage(original_size_draw_image, format_);
sk_sp<SkColorSpace> target_color_space =
key.target_color_space().ToSkColorSpace();
@@ -745,8 +747,8 @@ void SoftwareImageDecodeCache::DrawWithImageFinished(
const DecodedDrawImage& decoded_image) {
TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"SoftwareImageDecodeCache::DrawWithImageFinished", "key",
- ImageKey::FromDrawImage(image).ToString());
- ImageKey key = ImageKey::FromDrawImage(image);
+ ImageKey::FromDrawImage(image, format_).ToString());
+ ImageKey key = ImageKey::FromDrawImage(image, format_);
if (!decoded_image.image())
return;
@@ -839,6 +841,10 @@ void SoftwareImageDecodeCache::ClearCache() {
ReduceCacheUsageUntilWithinLimit(0);
}
+size_t SoftwareImageDecodeCache::GetMaximumMemoryLimitBytes() const {
+ return locked_images_budget_.total_limit_bytes();
+}
+
void SoftwareImageDecodeCache::RemovePendingTask(const ImageKey& key,
DecodeTaskType task_type) {
base::AutoLock lock(lock_);
@@ -898,7 +904,8 @@ void SoftwareImageDecodeCache::DumpImageMemoryForCache(
}
// SoftwareImageDecodeCacheKey
-ImageDecodeCacheKey ImageDecodeCacheKey::FromDrawImage(const DrawImage& image) {
+ImageDecodeCacheKey ImageDecodeCacheKey::FromDrawImage(const DrawImage& image,
+ ResourceFormat format) {
const SkSize& scale = image.scale();
// If the src_rect falls outside of the image, we need to clip it since
// otherwise we might end up with uninitialized memory in the decode process.
@@ -915,16 +922,22 @@ ImageDecodeCacheKey ImageDecodeCacheKey::FromDrawImage(const DrawImage& image) {
// If we're not going to do a scale, we can use low filter quality. Note that
// checking if the sizes are the same is better than checking if scale is 1.f,
// because even non-1 scale can result in the same (rounded) width/height.
- // If either dimension is a downscale, then use mipmaps (medium filter
- // quality).
+ // If either dimension is a downscale, and the quality is not None (in which
+ // case we need to preserve the pixelated scale), then use mipmaps (medium
+ // filter quality).
if (target_size.width() == src_rect.width() &&
target_size.height() == src_rect.height()) {
quality = std::min(quality, kLow_SkFilterQuality);
- } else if (target_size.width() < src_rect.width() ||
- target_size.height() < src_rect.height()) {
- quality = std::min(quality, kMedium_SkFilterQuality);
+ } else if (quality != kNone_SkFilterQuality &&
+ (target_size.width() < src_rect.width() ||
+ target_size.height() < src_rect.height())) {
+ quality = kMedium_SkFilterQuality;
}
+ // Skia doesn't scale an RGBA_4444 format, so always use the original decode.
+ if (format == RGBA_4444)
+ quality = std::min(quality, kLow_SkFilterQuality);
+
// Drop from high to medium if the the matrix we applied wasn't decomposable,
// or if the scaled image will be too large.
if (quality == kHigh_SkFilterQuality) {
diff --git a/chromium/cc/tiles/software_image_decode_cache.h b/chromium/cc/tiles/software_image_decode_cache.h
index 1d3e2ac75c4..755770b4bce 100644
--- a/chromium/cc/tiles/software_image_decode_cache.h
+++ b/chromium/cc/tiles/software_image_decode_cache.h
@@ -36,7 +36,8 @@ namespace cc {
// in the cache multiple times at different scales and filter qualities.
class CC_EXPORT ImageDecodeCacheKey {
public:
- static ImageDecodeCacheKey FromDrawImage(const DrawImage& image);
+ static ImageDecodeCacheKey FromDrawImage(const DrawImage& image,
+ ResourceFormat format);
ImageDecodeCacheKey(const ImageDecodeCacheKey& other);
@@ -140,6 +141,7 @@ class CC_EXPORT SoftwareImageDecodeCache
void SetShouldAggressivelyFreeResources(
bool aggressively_free_resources) override {}
void ClearCache() override;
+ size_t GetMaximumMemoryLimitBytes() const override;
// Decode the given image and store it in the cache. This is only called by an
// image decode task from a worker thread.
@@ -220,7 +222,7 @@ class CC_EXPORT SoftwareImageDecodeCache
size_t GetCurrentUsageSafe() const;
private:
- size_t limit_bytes_;
+ const size_t limit_bytes_;
base::CheckedNumeric<size_t> current_usage_bytes_;
};
@@ -263,17 +265,15 @@ class CC_EXPORT SoftwareImageDecodeCache
// data, which ensures that we cache an unlocked version of the original image
// in case we need to extract multiple subrects (as would be the case in an
// atlas).
- std::unique_ptr<DecodedImage> GetSubrectImageDecode(
- const ImageKey& key,
- sk_sp<const SkImage> image);
+ std::unique_ptr<DecodedImage> GetSubrectImageDecode(const ImageKey& key,
+ const PaintImage& image);
// GetScaledImageDecode is called by DecodeImageInternal when the quality
// requires the image be scaled. Like DecodeImageInternal, it should be
// called with no lock acquired and it returns nullptr if the decoding or
// scaling failed.
- std::unique_ptr<DecodedImage> GetScaledImageDecode(
- const ImageKey& key,
- sk_sp<const SkImage> image);
+ std::unique_ptr<DecodedImage> GetScaledImageDecode(const ImageKey& key,
+ const PaintImage& image);
void RefImage(const ImageKey& key);
void RefAtRasterImage(const ImageKey& key);
@@ -306,6 +306,8 @@ class CC_EXPORT SoftwareImageDecodeCache
// The members below this comment can only be accessed if the lock is held to
// ensure that they are safe to access on multiple threads.
+ // The exception is accessing |locked_images_budget_.total_limit_bytes()|,
+ // which is const and thread safe.
base::Lock lock_;
// Decoded images and ref counts (predecode path).
diff --git a/chromium/cc/tiles/software_image_decode_cache_perftest.cc b/chromium/cc/tiles/software_image_decode_cache_perftest.cc
index 0267f20d4f4..3a4b93ff28a 100644
--- a/chromium/cc/tiles/software_image_decode_cache_perftest.cc
+++ b/chromium/cc/tiles/software_image_decode_cache_perftest.cc
@@ -56,7 +56,9 @@ class SoftwareImageDecodeCachePerfTest : public testing::Test {
auto& subrect = rect_subrect.second;
for (auto& scale : scales) {
images.emplace_back(
- CreateImage(rect.width(), rect.height()), subrect, quality,
+ PaintImage(PaintImage::GetNextId(),
+ CreateImage(rect.width(), rect.height())),
+ subrect, quality,
CreateMatrix(SkSize::Make(scale.first, scale.second)),
gfx::ColorSpace());
}
@@ -66,7 +68,7 @@ class SoftwareImageDecodeCachePerfTest : public testing::Test {
timer_.Reset();
do {
for (auto& image : images)
- ImageDecodeCacheKey::FromDrawImage(image);
+ ImageDecodeCacheKey::FromDrawImage(image, RGBA_8888);
timer_.NextLap();
} while (!timer_.HasTimeLimitExpired());
diff --git a/chromium/cc/tiles/software_image_decode_cache_unittest.cc b/chromium/cc/tiles/software_image_decode_cache_unittest.cc
index 7d26359ba3d..90aa66e48a2 100644
--- a/chromium/cc/tiles/software_image_decode_cache_unittest.cc
+++ b/chromium/cc/tiles/software_image_decode_cache_unittest.cc
@@ -50,39 +50,116 @@ SkMatrix CreateMatrix(const SkSize& scale, bool is_decomposable) {
return matrix;
}
-TEST(SoftwareImageDecodeCacheTest, ImageKeyLowQuality) {
+PaintImage::Id s_paint_image_id = PaintImage::GetNextId();
+
+PaintImage CreatePaintImage(sk_sp<SkImage> image) {
+ return PaintImage(s_paint_image_id, image);
+}
+
+TEST(SoftwareImageDecodeCacheTest, ImageKeyNoneQuality) {
sk_sp<SkImage> image = CreateImage(100, 100);
bool is_decomposable = true;
- SkFilterQuality qualities[] = {kNone_SkFilterQuality, kLow_SkFilterQuality};
- for (auto quality : qualities) {
- DrawImage draw_image(
- image, SkIRect::MakeWH(image->width(), image->height()), quality,
- CreateMatrix(SkSize::Make(0.5f, 1.5f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(CreatePaintImage(image),
+ SkIRect::MakeWH(image->width(), image->height()),
+ kNone_SkFilterQuality,
+ CreateMatrix(SkSize::Make(0.5f, 1.5f), is_decomposable),
+ DefaultColorSpace());
- auto key = ImageDecodeCacheKey::FromDrawImage(draw_image);
- EXPECT_EQ(image->uniqueID(), key.image_id());
- EXPECT_EQ(quality, key.filter_quality());
- EXPECT_EQ(100, key.target_size().width());
- EXPECT_EQ(100, key.target_size().height());
- EXPECT_TRUE(key.can_use_original_size_decode());
- // Since the original decode will be used, the locked_bytes is that of the
- // original image.
- EXPECT_EQ(100u * 100u * 4u, key.locked_bytes());
- }
+ auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, RGBA_8888);
+ EXPECT_EQ(image->uniqueID(), key.image_id());
+ EXPECT_EQ(kNone_SkFilterQuality, key.filter_quality());
+ EXPECT_EQ(100, key.target_size().width());
+ EXPECT_EQ(100, key.target_size().height());
+ EXPECT_TRUE(key.can_use_original_size_decode());
+ // Since the original decode will be used, the locked_bytes is that of the
+ // original image.
+ EXPECT_EQ(100u * 100u * 4u, key.locked_bytes());
}
-TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQuality) {
+TEST(SoftwareImageDecodeCacheTest,
+ ImageKeyLowQualityIncreasedToMediumIfDownscale) {
sk_sp<SkImage> image = CreateImage(100, 100);
bool is_decomposable = true;
- SkFilterQuality quality = kMedium_SkFilterQuality;
+ DrawImage draw_image(CreatePaintImage(image),
+ SkIRect::MakeWH(image->width(), image->height()),
+ kLow_SkFilterQuality,
+ CreateMatrix(SkSize::Make(0.5f, 1.5f), is_decomposable),
+ DefaultColorSpace());
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
+ auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, RGBA_8888);
+ EXPECT_EQ(image->uniqueID(), key.image_id());
+ EXPECT_EQ(kMedium_SkFilterQuality, key.filter_quality());
+ EXPECT_EQ(100, key.target_size().width());
+ EXPECT_EQ(100, key.target_size().height());
+ EXPECT_FALSE(key.can_use_original_size_decode());
+ EXPECT_EQ(100u * 100u * 4u, key.locked_bytes());
+}
+
+TEST(SoftwareImageDecodeCacheTest, LowUnscalableFormatStaysLow) {
+ sk_sp<SkImage> image = CreateImage(100, 100);
+ bool is_decomposable = true;
+ DrawImage draw_image(CreatePaintImage(image),
+ SkIRect::MakeWH(image->width(), image->height()),
+ kLow_SkFilterQuality,
CreateMatrix(SkSize::Make(0.5f, 1.5f), is_decomposable),
DefaultColorSpace());
- auto key = ImageDecodeCacheKey::FromDrawImage(draw_image);
+ auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, RGBA_4444);
+ EXPECT_EQ(image->uniqueID(), key.image_id());
+ EXPECT_EQ(kLow_SkFilterQuality, key.filter_quality());
+ EXPECT_EQ(100, key.target_size().width());
+ EXPECT_EQ(100, key.target_size().height());
+ EXPECT_TRUE(key.can_use_original_size_decode());
+ EXPECT_EQ(100u * 100u * 4u, key.locked_bytes());
+}
+
+TEST(SoftwareImageDecodeCacheTest, HighUnscalableFormatBecomesLow) {
+ sk_sp<SkImage> image = CreateImage(100, 100);
+ bool is_decomposable = true;
+ DrawImage draw_image(CreatePaintImage(image),
+ SkIRect::MakeWH(image->width(), image->height()),
+ kHigh_SkFilterQuality,
+ CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable),
+ DefaultColorSpace());
+
+ auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, RGBA_4444);
+ EXPECT_EQ(image->uniqueID(), key.image_id());
+ EXPECT_EQ(kLow_SkFilterQuality, key.filter_quality());
+ EXPECT_EQ(100, key.target_size().width());
+ EXPECT_EQ(100, key.target_size().height());
+ EXPECT_TRUE(key.can_use_original_size_decode());
+ EXPECT_EQ(100u * 100u * 4u, key.locked_bytes());
+}
+
+TEST(SoftwareImageDecodeCacheTest, ImageKeyLowQualityKeptLowIfUpscale) {
+ sk_sp<SkImage> image = CreateImage(100, 100);
+ bool is_decomposable = true;
+ DrawImage draw_image(CreatePaintImage(image),
+ SkIRect::MakeWH(image->width(), image->height()),
+ kLow_SkFilterQuality,
+ CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable),
+ DefaultColorSpace());
+
+ auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, RGBA_8888);
+ EXPECT_EQ(image->uniqueID(), key.image_id());
+ EXPECT_EQ(kLow_SkFilterQuality, key.filter_quality());
+ EXPECT_EQ(100, key.target_size().width());
+ EXPECT_EQ(100, key.target_size().height());
+ EXPECT_TRUE(key.can_use_original_size_decode());
+ EXPECT_EQ(100u * 100u * 4u, key.locked_bytes());
+}
+
+TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQuality) {
+ sk_sp<SkImage> image = CreateImage(100, 100);
+ bool is_decomposable = true;
+ SkFilterQuality quality = kMedium_SkFilterQuality;
+
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.5f, 1.5f), is_decomposable),
+ DefaultColorSpace());
+
+ auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, RGBA_8888);
EXPECT_EQ(image->uniqueID(), key.image_id());
EXPECT_EQ(quality, key.filter_quality());
EXPECT_EQ(100, key.target_size().width());
@@ -96,12 +173,12 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityDropToLowIfEnlarging) {
bool is_decomposable = true;
SkFilterQuality quality = kMedium_SkFilterQuality;
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable),
+ DefaultColorSpace());
- auto key = ImageDecodeCacheKey::FromDrawImage(draw_image);
+ auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, RGBA_8888);
EXPECT_EQ(image->uniqueID(), key.image_id());
EXPECT_EQ(kLow_SkFilterQuality, key.filter_quality());
EXPECT_EQ(100, key.target_size().width());
@@ -115,12 +192,12 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityDropToLowIfIdentity) {
bool is_decomposable = true;
SkFilterQuality quality = kMedium_SkFilterQuality;
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
+ DefaultColorSpace());
- auto key = ImageDecodeCacheKey::FromDrawImage(draw_image);
+ auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, RGBA_8888);
EXPECT_EQ(image->uniqueID(), key.image_id());
EXPECT_EQ(kLow_SkFilterQuality, key.filter_quality());
EXPECT_EQ(100, key.target_size().width());
@@ -136,11 +213,11 @@ TEST(SoftwareImageDecodeCacheTest,
SkFilterQuality quality = kMedium_SkFilterQuality;
DrawImage draw_image(
- image, SkIRect::MakeWH(image->width(), image->height()), quality,
- CreateMatrix(SkSize::Make(1.001f, 1.001f), is_decomposable),
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(1.001f, 1.001f), is_decomposable),
DefaultColorSpace());
- auto key = ImageDecodeCacheKey::FromDrawImage(draw_image);
+ auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, RGBA_8888);
EXPECT_EQ(image->uniqueID(), key.image_id());
EXPECT_EQ(kLow_SkFilterQuality, key.filter_quality());
EXPECT_EQ(100, key.target_size().width());
@@ -156,11 +233,11 @@ TEST(SoftwareImageDecodeCacheTest,
SkFilterQuality quality = kMedium_SkFilterQuality;
DrawImage draw_image(
- image, SkIRect::MakeWH(image->width(), image->height()), quality,
- CreateMatrix(SkSize::Make(0.999f, 0.999f), is_decomposable),
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.999f, 0.999f), is_decomposable),
DefaultColorSpace());
- auto key = ImageDecodeCacheKey::FromDrawImage(draw_image);
+ auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, RGBA_8888);
EXPECT_EQ(image->uniqueID(), key.image_id());
EXPECT_EQ(kLow_SkFilterQuality, key.filter_quality());
EXPECT_EQ(100, key.target_size().width());
@@ -175,12 +252,12 @@ TEST(SoftwareImageDecodeCacheTest,
bool is_decomposable = false;
SkFilterQuality quality = kMedium_SkFilterQuality;
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 1.5f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.5f, 1.5f), is_decomposable),
+ DefaultColorSpace());
- auto key = ImageDecodeCacheKey::FromDrawImage(draw_image);
+ auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, RGBA_8888);
EXPECT_EQ(image->uniqueID(), key.image_id());
EXPECT_EQ(kLow_SkFilterQuality, key.filter_quality());
EXPECT_EQ(100, key.target_size().width());
@@ -194,12 +271,12 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt1_5Scale) {
bool is_decomposable = true;
SkFilterQuality quality = kMedium_SkFilterQuality;
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable),
+ DefaultColorSpace());
- auto key = ImageDecodeCacheKey::FromDrawImage(draw_image);
+ auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, RGBA_8888);
EXPECT_EQ(image->uniqueID(), key.image_id());
EXPECT_EQ(kLow_SkFilterQuality, key.filter_quality());
EXPECT_EQ(500, key.target_size().width());
@@ -213,12 +290,12 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt1_0cale) {
bool is_decomposable = true;
SkFilterQuality quality = kMedium_SkFilterQuality;
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
+ DefaultColorSpace());
- auto key = ImageDecodeCacheKey::FromDrawImage(draw_image);
+ auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, RGBA_8888);
EXPECT_EQ(image->uniqueID(), key.image_id());
EXPECT_EQ(kLow_SkFilterQuality, key.filter_quality());
EXPECT_EQ(500, key.target_size().width());
@@ -233,11 +310,11 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt0_75Scale) {
SkFilterQuality quality = kMedium_SkFilterQuality;
DrawImage draw_image(
- image, SkIRect::MakeWH(image->width(), image->height()), quality,
- CreateMatrix(SkSize::Make(0.75f, 0.75f), is_decomposable),
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.75f, 0.75f), is_decomposable),
DefaultColorSpace());
- auto key = ImageDecodeCacheKey::FromDrawImage(draw_image);
+ auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, RGBA_8888);
EXPECT_EQ(image->uniqueID(), key.image_id());
EXPECT_EQ(quality, key.filter_quality());
EXPECT_EQ(500, key.target_size().width());
@@ -251,12 +328,12 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt0_5Scale) {
bool is_decomposable = true;
SkFilterQuality quality = kMedium_SkFilterQuality;
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ DefaultColorSpace());
- auto key = ImageDecodeCacheKey::FromDrawImage(draw_image);
+ auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, RGBA_8888);
EXPECT_EQ(image->uniqueID(), key.image_id());
EXPECT_EQ(quality, key.filter_quality());
EXPECT_EQ(250, key.target_size().width());
@@ -271,11 +348,11 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt0_49Scale) {
SkFilterQuality quality = kMedium_SkFilterQuality;
DrawImage draw_image(
- image, SkIRect::MakeWH(image->width(), image->height()), quality,
- CreateMatrix(SkSize::Make(0.49f, 0.49f), is_decomposable),
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.49f, 0.49f), is_decomposable),
DefaultColorSpace());
- auto key = ImageDecodeCacheKey::FromDrawImage(draw_image);
+ auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, RGBA_8888);
EXPECT_EQ(image->uniqueID(), key.image_id());
EXPECT_EQ(quality, key.filter_quality());
EXPECT_EQ(250, key.target_size().width());
@@ -289,12 +366,12 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt0_1Scale) {
bool is_decomposable = true;
SkFilterQuality quality = kMedium_SkFilterQuality;
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(0.1f, 0.1f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.1f, 0.1f), is_decomposable),
+ DefaultColorSpace());
- auto key = ImageDecodeCacheKey::FromDrawImage(draw_image);
+ auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, RGBA_8888);
EXPECT_EQ(image->uniqueID(), key.image_id());
EXPECT_EQ(quality, key.filter_quality());
EXPECT_EQ(62, key.target_size().width());
@@ -309,11 +386,11 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyMediumQualityAt0_01Scale) {
SkFilterQuality quality = kMedium_SkFilterQuality;
DrawImage draw_image(
- image, SkIRect::MakeWH(image->width(), image->height()), quality,
- CreateMatrix(SkSize::Make(0.01f, 0.01f), is_decomposable),
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.01f, 0.01f), is_decomposable),
DefaultColorSpace());
- auto key = ImageDecodeCacheKey::FromDrawImage(draw_image);
+ auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, RGBA_8888);
EXPECT_EQ(image->uniqueID(), key.image_id());
EXPECT_EQ(quality, key.filter_quality());
EXPECT_EQ(7, key.target_size().width());
@@ -328,12 +405,12 @@ TEST(SoftwareImageDecodeCacheTest,
bool is_decomposable = true;
SkFilterQuality quality = kHigh_SkFilterQuality;
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 1.5f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.5f, 1.5f), is_decomposable),
+ DefaultColorSpace());
- auto key = ImageDecodeCacheKey::FromDrawImage(draw_image);
+ auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, RGBA_8888);
EXPECT_EQ(image->uniqueID(), key.image_id());
EXPECT_EQ(kMedium_SkFilterQuality, key.filter_quality());
EXPECT_EQ(100, key.target_size().width());
@@ -348,12 +425,12 @@ TEST(SoftwareImageDecodeCacheTest,
bool is_decomposable = true;
SkFilterQuality quality = kHigh_SkFilterQuality;
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.2f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.5f, 0.2f), is_decomposable),
+ DefaultColorSpace());
- auto key = ImageDecodeCacheKey::FromDrawImage(draw_image);
+ auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, RGBA_8888);
EXPECT_EQ(image->uniqueID(), key.image_id());
EXPECT_EQ(kMedium_SkFilterQuality, key.filter_quality());
EXPECT_EQ(50, key.target_size().width());
@@ -367,12 +444,12 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyDowscalesHighQuality) {
bool is_decomposable = true;
SkFilterQuality quality = kHigh_SkFilterQuality;
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(2.5f, 1.5f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(2.5f, 1.5f), is_decomposable),
+ DefaultColorSpace());
- auto key = ImageDecodeCacheKey::FromDrawImage(draw_image);
+ auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, RGBA_8888);
EXPECT_EQ(image->uniqueID(), key.image_id());
EXPECT_EQ(quality, key.filter_quality());
EXPECT_EQ(250, key.target_size().width());
@@ -389,12 +466,12 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyHighQualityDropToMediumIfTooLarge) {
// At least one dimension should scale down, so that medium quality doesn't
// become low.
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(0.9f, 2.f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.9f, 2.f), is_decomposable),
+ DefaultColorSpace());
- auto key = ImageDecodeCacheKey::FromDrawImage(draw_image);
+ auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, RGBA_8888);
EXPECT_EQ(image->uniqueID(), key.image_id());
EXPECT_EQ(kMedium_SkFilterQuality, key.filter_quality());
EXPECT_EQ(4555, key.target_size().width());
@@ -409,12 +486,12 @@ TEST(SoftwareImageDecodeCacheTest,
bool is_decomposable = false;
SkFilterQuality quality = kHigh_SkFilterQuality;
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 1.5f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.5f, 1.5f), is_decomposable),
+ DefaultColorSpace());
- auto key = ImageDecodeCacheKey::FromDrawImage(draw_image);
+ auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, RGBA_8888);
EXPECT_EQ(image->uniqueID(), key.image_id());
EXPECT_EQ(kLow_SkFilterQuality, key.filter_quality());
EXPECT_EQ(100, key.target_size().width());
@@ -428,12 +505,12 @@ TEST(SoftwareImageDecodeCacheTest, ImageKeyHighQualityDropToLowIfIdentity) {
bool is_decomposable = true;
SkFilterQuality quality = kHigh_SkFilterQuality;
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
+ DefaultColorSpace());
- auto key = ImageDecodeCacheKey::FromDrawImage(draw_image);
+ auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, RGBA_8888);
EXPECT_EQ(image->uniqueID(), key.image_id());
EXPECT_EQ(kLow_SkFilterQuality, key.filter_quality());
EXPECT_EQ(100, key.target_size().width());
@@ -449,11 +526,11 @@ TEST(SoftwareImageDecodeCacheTest,
SkFilterQuality quality = kHigh_SkFilterQuality;
DrawImage draw_image(
- image, SkIRect::MakeWH(image->width(), image->height()), quality,
- CreateMatrix(SkSize::Make(1.001f, 1.001f), is_decomposable),
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(1.001f, 1.001f), is_decomposable),
DefaultColorSpace());
- auto key = ImageDecodeCacheKey::FromDrawImage(draw_image);
+ auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, RGBA_8888);
EXPECT_EQ(image->uniqueID(), key.image_id());
EXPECT_EQ(kLow_SkFilterQuality, key.filter_quality());
EXPECT_EQ(100, key.target_size().width());
@@ -469,11 +546,11 @@ TEST(SoftwareImageDecodeCacheTest,
SkFilterQuality quality = kHigh_SkFilterQuality;
DrawImage draw_image(
- image, SkIRect::MakeWH(image->width(), image->height()), quality,
- CreateMatrix(SkSize::Make(0.999f, 0.999f), is_decomposable),
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.999f, 0.999f), is_decomposable),
DefaultColorSpace());
- auto key = ImageDecodeCacheKey::FromDrawImage(draw_image);
+ auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, RGBA_8888);
EXPECT_EQ(image->uniqueID(), key.image_id());
EXPECT_EQ(kLow_SkFilterQuality, key.filter_quality());
EXPECT_EQ(100, key.target_size().width());
@@ -485,29 +562,30 @@ TEST(SoftwareImageDecodeCacheTest,
TEST(SoftwareImageDecodeCacheTest, OriginalDecodesAreEqual) {
sk_sp<SkImage> image = CreateImage(100, 100);
bool is_decomposable = true;
- SkFilterQuality quality = kLow_SkFilterQuality;
+ SkFilterQuality quality = kNone_SkFilterQuality;
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.5f, 0.5), is_decomposable),
+ DefaultColorSpace());
- auto key = ImageDecodeCacheKey::FromDrawImage(draw_image);
+ auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, RGBA_8888);
EXPECT_EQ(image->uniqueID(), key.image_id());
- EXPECT_EQ(kLow_SkFilterQuality, key.filter_quality());
+ EXPECT_EQ(kNone_SkFilterQuality, key.filter_quality());
EXPECT_EQ(100, key.target_size().width());
EXPECT_EQ(100, key.target_size().height());
EXPECT_TRUE(key.can_use_original_size_decode());
EXPECT_EQ(100u * 100u * 4u, key.locked_bytes());
DrawImage another_draw_image(
- image, SkIRect::MakeWH(image->width(), image->height()), quality,
- CreateMatrix(SkSize::Make(1.5f, 1.5), is_decomposable),
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(1.5f, 1.5), is_decomposable),
DefaultColorSpace());
- auto another_key = ImageDecodeCacheKey::FromDrawImage(another_draw_image);
+ auto another_key =
+ ImageDecodeCacheKey::FromDrawImage(another_draw_image, RGBA_8888);
EXPECT_EQ(image->uniqueID(), another_key.image_id());
- EXPECT_EQ(kLow_SkFilterQuality, another_key.filter_quality());
+ EXPECT_EQ(kNone_SkFilterQuality, another_key.filter_quality());
EXPECT_EQ(100, another_key.target_size().width());
EXPECT_EQ(100, another_key.target_size().height());
EXPECT_TRUE(another_key.can_use_original_size_decode());
@@ -522,11 +600,12 @@ TEST(SoftwareImageDecodeCacheTest, ImageRectDoesNotContainSrcRect) {
SkFilterQuality quality = kHigh_SkFilterQuality;
DrawImage draw_image(
- image, SkIRect::MakeXYWH(25, 35, image->width(), image->height()),
- quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
+ CreatePaintImage(image),
+ SkIRect::MakeXYWH(25, 35, image->width(), image->height()), quality,
+ CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
DefaultColorSpace());
- auto key = ImageDecodeCacheKey::FromDrawImage(draw_image);
+ auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, RGBA_8888);
EXPECT_EQ(image->uniqueID(), key.image_id());
EXPECT_EQ(kLow_SkFilterQuality, key.filter_quality());
EXPECT_EQ(100, key.target_size().width());
@@ -541,11 +620,12 @@ TEST(SoftwareImageDecodeCacheTest, ImageRectDoesNotContainSrcRectWithScale) {
SkFilterQuality quality = kHigh_SkFilterQuality;
DrawImage draw_image(
- image, SkIRect::MakeXYWH(20, 30, image->width(), image->height()),
- quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ CreatePaintImage(image),
+ SkIRect::MakeXYWH(20, 30, image->width(), image->height()), quality,
+ CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
DefaultColorSpace());
- auto key = ImageDecodeCacheKey::FromDrawImage(draw_image);
+ auto key = ImageDecodeCacheKey::FromDrawImage(draw_image, RGBA_8888);
EXPECT_EQ(image->uniqueID(), key.image_id());
EXPECT_EQ(kMedium_SkFilterQuality, key.filter_quality());
EXPECT_EQ(40, key.target_size().width());
@@ -560,10 +640,10 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageSameImage) {
bool is_decomposable = true;
SkFilterQuality quality = kHigh_SkFilterQuality;
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ DefaultColorSpace());
scoped_refptr<TileTask> task;
bool need_unref = cache.GetTaskForImageAndRef(
draw_image, ImageDecodeCache::TracingInfo(), &task);
@@ -571,8 +651,8 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageSameImage) {
EXPECT_TRUE(task);
DrawImage another_draw_image(
- image, SkIRect::MakeWH(image->width(), image->height()), quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
DefaultColorSpace());
scoped_refptr<TileTask> another_task;
need_unref = cache.GetTaskForImageAndRef(
@@ -592,7 +672,7 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageSameImageDifferentQuality) {
bool is_decomposable = true;
DrawImage high_quality_draw_image(
- image, SkIRect::MakeWH(image->width(), image->height()),
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
kHigh_SkFilterQuality,
CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
DefaultColorSpace());
@@ -603,24 +683,24 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageSameImageDifferentQuality) {
EXPECT_TRUE(need_unref);
EXPECT_TRUE(high_quality_task);
- DrawImage low_quality_draw_image(
- image, SkIRect::MakeWH(image->width(), image->height()),
- kLow_SkFilterQuality,
+ DrawImage none_quality_draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ kNone_SkFilterQuality,
CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
DefaultColorSpace());
- scoped_refptr<TileTask> low_quality_task;
- need_unref = cache.GetTaskForImageAndRef(low_quality_draw_image,
+ scoped_refptr<TileTask> none_quality_task;
+ need_unref = cache.GetTaskForImageAndRef(none_quality_draw_image,
ImageDecodeCache::TracingInfo(),
- &low_quality_task);
+ &none_quality_task);
EXPECT_TRUE(need_unref);
- EXPECT_TRUE(low_quality_task);
- EXPECT_TRUE(high_quality_task.get() != low_quality_task.get());
+ EXPECT_TRUE(none_quality_task);
+ EXPECT_TRUE(high_quality_task.get() != none_quality_task.get());
TestTileTaskRunner::ProcessTask(high_quality_task.get());
- TestTileTaskRunner::ProcessTask(low_quality_task.get());
+ TestTileTaskRunner::ProcessTask(none_quality_task.get());
cache.UnrefImage(high_quality_draw_image);
- cache.UnrefImage(low_quality_draw_image);
+ cache.UnrefImage(none_quality_draw_image);
}
TEST(SoftwareImageDecodeCacheTest, GetTaskForImageSameImageDifferentSize) {
@@ -630,8 +710,8 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageSameImageDifferentSize) {
SkFilterQuality quality = kHigh_SkFilterQuality;
DrawImage half_size_draw_image(
- image, SkIRect::MakeWH(image->width(), image->height()), quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
DefaultColorSpace());
scoped_refptr<TileTask> half_size_task;
bool need_unref = cache.GetTaskForImageAndRef(
@@ -640,8 +720,8 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageSameImageDifferentSize) {
EXPECT_TRUE(half_size_task);
DrawImage quarter_size_draw_image(
- image, SkIRect::MakeWH(image->width(), image->height()), quality,
- CreateMatrix(SkSize::Make(0.25f, 0.25f), is_decomposable),
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.25f, 0.25f), is_decomposable),
DefaultColorSpace());
scoped_refptr<TileTask> quarter_size_task;
need_unref = cache.GetTaskForImageAndRef(quarter_size_draw_image,
@@ -665,8 +745,9 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageDifferentImage) {
sk_sp<SkImage> first_image = CreateImage(100, 100);
DrawImage first_draw_image(
- first_image, SkIRect::MakeWH(first_image->width(), first_image->height()),
- quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ CreatePaintImage(first_image),
+ SkIRect::MakeWH(first_image->width(), first_image->height()), quality,
+ CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
DefaultColorSpace());
scoped_refptr<TileTask> first_task;
bool need_unref = cache.GetTaskForImageAndRef(
@@ -676,7 +757,7 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageDifferentImage) {
sk_sp<SkImage> second_image = CreateImage(100, 100);
DrawImage second_draw_image(
- second_image,
+ CreatePaintImage(second_image),
SkIRect::MakeWH(second_image->width(), second_image->height()), quality,
CreateMatrix(SkSize::Make(0.25f, 0.25f), is_decomposable),
DefaultColorSpace());
@@ -694,7 +775,15 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageDifferentImage) {
cache.UnrefImage(second_draw_image);
}
-TEST(SoftwareImageDecodeCacheTest, GetTaskForImageDifferentColorSpace) {
+// crbug.com/709341
+#if defined(MEMORY_SANITIZER)
+#define MAYBE_GetTaskForImageDifferentColorSpace \
+ DISABLED_GetTaskForImageDifferentColorSpace
+#else
+#define MAYBE_GetTaskForImageDifferentColorSpace \
+ GetTaskForImageDifferentColorSpace
+#endif
+TEST(SoftwareImageDecodeCacheTest, MAYBE_GetTaskForImageDifferentColorSpace) {
TestSoftwareImageDecodeCache cache;
bool is_decomposable = true;
SkFilterQuality quality = kHigh_SkFilterQuality;
@@ -707,8 +796,9 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageDifferentColorSpace) {
sk_sp<SkImage> image = CreateImageWithColorSpace(100, 100, color_space_a);
DrawImage first_draw_image(
- image, SkIRect::MakeWH(image->width(), image->height()), quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), color_space_b);
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
+ color_space_b);
scoped_refptr<TileTask> first_task;
bool need_unref = cache.GetTaskForImageAndRef(
first_draw_image, ImageDecodeCache::TracingInfo(), &first_task);
@@ -716,8 +806,9 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageDifferentColorSpace) {
EXPECT_TRUE(first_task);
DrawImage second_draw_image(
- image, SkIRect::MakeWH(image->width(), image->height()), quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), color_space_c);
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
+ color_space_c);
scoped_refptr<TileTask> second_task;
need_unref = cache.GetTaskForImageAndRef(
second_draw_image, ImageDecodeCache::TracingInfo(), &second_task);
@@ -726,8 +817,9 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageDifferentColorSpace) {
EXPECT_TRUE(first_task.get() != second_task.get());
DrawImage third_draw_image(
- image, SkIRect::MakeWH(image->width(), image->height()), quality,
- CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable), color_space_b);
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
+ color_space_b);
scoped_refptr<TileTask> third_task;
need_unref = cache.GetTaskForImageAndRef(
third_draw_image, ImageDecodeCache::TracingInfo(), &third_task);
@@ -749,10 +841,10 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageAlreadyDecoded) {
SkFilterQuality quality = kHigh_SkFilterQuality;
sk_sp<SkImage> image = CreateImage(100, 100);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ DefaultColorSpace());
scoped_refptr<TileTask> task;
bool need_unref = cache.GetTaskForImageAndRef(
draw_image, ImageDecodeCache::TracingInfo(), &task);
@@ -780,10 +872,10 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageAlreadyPrerolled) {
SkFilterQuality quality = kLow_SkFilterQuality;
sk_sp<SkImage> image = CreateImage(100, 100);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
+ DefaultColorSpace());
scoped_refptr<TileTask> task;
bool need_unref = cache.GetTaskForImageAndRef(
draw_image, ImageDecodeCache::TracingInfo(), &task);
@@ -818,10 +910,10 @@ TEST(SoftwareImageDecodeCacheTest, GetTaskForImageCanceledGetsNewTask) {
SkFilterQuality quality = kHigh_SkFilterQuality;
sk_sp<SkImage> image = CreateImage(100, 100);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ DefaultColorSpace());
scoped_refptr<TileTask> task;
bool need_unref = cache.GetTaskForImageAndRef(
draw_image, ImageDecodeCache::TracingInfo(), &task);
@@ -862,10 +954,10 @@ TEST(SoftwareImageDecodeCacheTest,
SkFilterQuality quality = kHigh_SkFilterQuality;
sk_sp<SkImage> image = CreateImage(100, 100);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ DefaultColorSpace());
scoped_refptr<TileTask> task;
bool need_unref = cache.GetTaskForImageAndRef(
draw_image, ImageDecodeCache::TracingInfo(), &task);
@@ -905,10 +997,10 @@ TEST(SoftwareImageDecodeCacheTest, GetDecodedImageForDraw) {
SkFilterQuality quality = kHigh_SkFilterQuality;
sk_sp<SkImage> image = CreateImage(100, 100);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ DefaultColorSpace());
scoped_refptr<TileTask> task;
bool need_unref = cache.GetTaskForImageAndRef(
draw_image, ImageDecodeCache::TracingInfo(), &task);
@@ -940,8 +1032,9 @@ TEST(SoftwareImageDecodeCacheTest,
sk_sp<SkImage> image = CreateImage(100, 100);
DrawImage draw_image(
- image, SkIRect::MakeXYWH(20, 30, image->width(), image->height()),
- quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ CreatePaintImage(image),
+ SkIRect::MakeXYWH(20, 30, image->width(), image->height()), quality,
+ CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
DefaultColorSpace());
scoped_refptr<TileTask> task;
bool need_unref = cache.GetTaskForImageAndRef(
@@ -972,10 +1065,10 @@ TEST(SoftwareImageDecodeCacheTest, GetDecodedImageForDrawAtRasterDecode) {
SkFilterQuality quality = kHigh_SkFilterQuality;
sk_sp<SkImage> image = CreateImage(100, 100);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ DefaultColorSpace());
DecodedDrawImage decoded_draw_image =
cache.GetDecodedImageForDraw(draw_image);
@@ -998,10 +1091,10 @@ TEST(SoftwareImageDecodeCacheTest,
SkFilterQuality quality = kHigh_SkFilterQuality;
sk_sp<SkImage> image = CreateImage(100, 100);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ DefaultColorSpace());
DecodedDrawImage decoded_draw_image =
cache.GetDecodedImageForDraw(draw_image);
@@ -1030,10 +1123,10 @@ TEST(SoftwareImageDecodeCacheTest,
SkFilterQuality quality = kHigh_SkFilterQuality;
sk_sp<SkImage> image = CreateImage(100, 100);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ DefaultColorSpace());
DecodedDrawImage decoded_draw_image =
cache.GetDecodedImageForDraw(draw_image);
@@ -1076,10 +1169,10 @@ TEST(SoftwareImageDecodeCacheTest,
SkFilterQuality quality = kHigh_SkFilterQuality;
sk_sp<SkImage> image = CreateImage(100, 100);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ DefaultColorSpace());
DecodedDrawImage decoded_draw_image =
cache.GetDecodedImageForDraw(draw_image);
@@ -1122,10 +1215,10 @@ TEST(SoftwareImageDecodeCacheTest, ZeroSizedImagesAreSkipped) {
SkFilterQuality quality = kHigh_SkFilterQuality;
sk_sp<SkImage> image = CreateImage(100, 100);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(0.f, 0.f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.f, 0.f), is_decomposable),
+ DefaultColorSpace());
scoped_refptr<TileTask> task;
bool need_unref = cache.GetTaskForImageAndRef(
@@ -1147,8 +1240,9 @@ TEST(SoftwareImageDecodeCacheTest, NonOverlappingSrcRectImagesAreSkipped) {
sk_sp<SkImage> image = CreateImage(100, 100);
DrawImage draw_image(
- image, SkIRect::MakeXYWH(150, 150, image->width(), image->height()),
- quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
+ CreatePaintImage(image),
+ SkIRect::MakeXYWH(150, 150, image->width(), image->height()), quality,
+ CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
DefaultColorSpace());
scoped_refptr<TileTask> task;
@@ -1170,10 +1264,10 @@ TEST(SoftwareImageDecodeCacheTest, LowQualityFilterIsHandled) {
SkFilterQuality quality = kLow_SkFilterQuality;
sk_sp<SkImage> image = CreateImage(100, 100);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
+ DefaultColorSpace());
scoped_refptr<TileTask> task;
bool need_unref = cache.GetTaskForImageAndRef(
@@ -1200,7 +1294,8 @@ TEST(SoftwareImageDecodeCacheTest, LowQualityScaledSubrectIsHandled) {
SkFilterQuality quality = kLow_SkFilterQuality;
sk_sp<SkImage> image = CreateImage(100, 100);
- DrawImage draw_image(image, SkIRect::MakeXYWH(10, 10, 80, 80), quality,
+ DrawImage draw_image(CreatePaintImage(image),
+ SkIRect::MakeXYWH(10, 10, 80, 80), quality,
CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
DefaultColorSpace());
@@ -1219,7 +1314,10 @@ TEST(SoftwareImageDecodeCacheTest, LowQualityScaledSubrectIsHandled) {
// SkImage object.
EXPECT_TRUE(decoded_draw_image.image() != image);
EXPECT_EQ(kLow_SkFilterQuality, decoded_draw_image.filter_quality());
- EXPECT_TRUE(decoded_draw_image.is_scale_adjustment_identity());
+ // Low quality will be upgraded to medium and mip-mapped.
+ EXPECT_FALSE(decoded_draw_image.is_scale_adjustment_identity());
+ 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);
@@ -1231,7 +1329,8 @@ TEST(SoftwareImageDecodeCacheTest, NoneQualityScaledSubrectIsHandled) {
SkFilterQuality quality = kNone_SkFilterQuality;
sk_sp<SkImage> image = CreateImage(100, 100);
- DrawImage draw_image(image, SkIRect::MakeXYWH(10, 10, 80, 80), quality,
+ DrawImage draw_image(CreatePaintImage(image),
+ SkIRect::MakeXYWH(10, 10, 80, 80), quality,
CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
DefaultColorSpace());
@@ -1262,10 +1361,10 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt01_5ScaleIsHandled) {
SkFilterQuality quality = kMedium_SkFilterQuality;
sk_sp<SkImage> image = CreateImage(500, 200);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(1.5f, 1.5f), is_decomposable),
+ DefaultColorSpace());
scoped_refptr<TileTask> task;
bool need_unref = cache.GetTaskForImageAndRef(
@@ -1295,10 +1394,10 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt1_0ScaleIsHandled) {
SkFilterQuality quality = kMedium_SkFilterQuality;
sk_sp<SkImage> image = CreateImage(500, 200);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(1.f, 1.f), is_decomposable),
+ DefaultColorSpace());
scoped_refptr<TileTask> task;
bool need_unref = cache.GetTaskForImageAndRef(
@@ -1329,8 +1428,8 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_75ScaleIsHandled) {
sk_sp<SkImage> image = CreateImage(500, 200);
DrawImage draw_image(
- image, SkIRect::MakeWH(image->width(), image->height()), quality,
- CreateMatrix(SkSize::Make(0.75f, 0.75f), is_decomposable),
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.75f, 0.75f), is_decomposable),
DefaultColorSpace());
scoped_refptr<TileTask> task;
@@ -1361,10 +1460,10 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_5ScaleIsHandled) {
SkFilterQuality quality = kMedium_SkFilterQuality;
sk_sp<SkImage> image = CreateImage(500, 200);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ DefaultColorSpace());
scoped_refptr<TileTask> task;
bool need_unref = cache.GetTaskForImageAndRef(
@@ -1395,8 +1494,8 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_49ScaleIsHandled) {
sk_sp<SkImage> image = CreateImage(500, 200);
DrawImage draw_image(
- image, SkIRect::MakeWH(image->width(), image->height()), quality,
- CreateMatrix(SkSize::Make(0.49f, 0.49f), is_decomposable),
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.49f, 0.49f), is_decomposable),
DefaultColorSpace());
scoped_refptr<TileTask> task;
@@ -1427,10 +1526,10 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_1ScaleIsHandled) {
SkFilterQuality quality = kMedium_SkFilterQuality;
sk_sp<SkImage> image = CreateImage(500, 200);
- DrawImage draw_image(image, SkIRect::MakeWH(image->width(), image->height()),
- quality,
- CreateMatrix(SkSize::Make(0.1f, 0.1f), is_decomposable),
- DefaultColorSpace());
+ DrawImage draw_image(
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.1f, 0.1f), is_decomposable),
+ DefaultColorSpace());
scoped_refptr<TileTask> task;
bool need_unref = cache.GetTaskForImageAndRef(
@@ -1461,8 +1560,8 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_01ScaleIsHandled) {
sk_sp<SkImage> image = CreateImage(500, 200);
DrawImage draw_image(
- image, SkIRect::MakeWH(image->width(), image->height()), quality,
- CreateMatrix(SkSize::Make(0.01f, 0.01f), is_decomposable),
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.01f, 0.01f), is_decomposable),
DefaultColorSpace());
scoped_refptr<TileTask> task;
@@ -1494,8 +1593,8 @@ TEST(SoftwareImageDecodeCacheTest, MediumQualityAt0_001ScaleIsHandled) {
sk_sp<SkImage> image = CreateImage(500, 200);
DrawImage draw_image(
- image, SkIRect::MakeWH(image->width(), image->height()), quality,
- CreateMatrix(SkSize::Make(0.001f, 0.001f), is_decomposable),
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.001f, 0.001f), is_decomposable),
DefaultColorSpace());
scoped_refptr<TileTask> task;
@@ -1519,12 +1618,12 @@ TEST(SoftwareImageDecodeCacheTest,
sk_sp<SkImage> image = CreateImage(500, 200);
DrawImage draw_image_50(
- image, SkIRect::MakeWH(image->width(), image->height()), quality,
- CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.5f, 0.5f), is_decomposable),
DefaultColorSpace());
DrawImage draw_image_49(
- image, SkIRect::MakeWH(image->width(), image->height()), quality,
- CreateMatrix(SkSize::Make(0.49f, 0.49f), is_decomposable),
+ CreatePaintImage(image), SkIRect::MakeWH(image->width(), image->height()),
+ quality, CreateMatrix(SkSize::Make(0.49f, 0.49f), is_decomposable),
DefaultColorSpace());
scoped_refptr<TileTask> task_50;
@@ -1573,7 +1672,8 @@ TEST(SoftwareImageDecodeCacheTest, ClearCache) {
for (int i = 0; i < 10; ++i) {
sk_sp<SkImage> image = CreateImage(100, 100);
DrawImage draw_image(
- image, SkIRect::MakeWH(image->width(), image->height()), quality,
+ CreatePaintImage(image),
+ SkIRect::MakeWH(image->width(), image->height()), quality,
CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
DefaultColorSpace());
scoped_refptr<TileTask> task;
diff --git a/chromium/cc/tiles/tile.h b/chromium/cc/tiles/tile.h
index 435d5f0552e..66dfadae0a6 100644
--- a/chromium/cc/tiles/tile.h
+++ b/chromium/cc/tiles/tile.h
@@ -10,6 +10,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "cc/paint/draw_image.h"
#include "cc/raster/tile_task.h"
#include "cc/tiles/tile_draw_info.h"
#include "ui/gfx/geometry/axis_transform2d.h"
@@ -117,6 +118,15 @@ class CC_EXPORT Tile {
return is_solid_color_analysis_performed_;
}
+ bool set_raster_task_scheduled_with_checker_images(bool has_checker_images) {
+ bool previous_value = raster_task_scheduled_with_checker_images_;
+ raster_task_scheduled_with_checker_images_ = has_checker_images;
+ return previous_value;
+ }
+ bool raster_task_scheduled_with_checker_images() const {
+ return raster_task_scheduled_with_checker_images_;
+ }
+
const PictureLayerTiling* tiling() const { return tiling_; }
void set_tiling(const PictureLayerTiling* tiling) { tiling_ = tiling; }
@@ -158,6 +168,10 @@ class CC_EXPORT Tile {
Id invalidated_id_;
unsigned scheduled_priority_;
+
+ // Set to true if there is a raster task scheduled for this tile that will
+ // rasterize a resource with checker images.
+ bool raster_task_scheduled_with_checker_images_ = false;
scoped_refptr<TileTask> raster_task_;
DISALLOW_COPY_AND_ASSIGN(Tile);
diff --git a/chromium/cc/tiles/tile_draw_info.cc b/chromium/cc/tiles/tile_draw_info.cc
index 2e4eebb726c..d27059f5949 100644
--- a/chromium/cc/tiles/tile_draw_info.cc
+++ b/chromium/cc/tiles/tile_draw_info.cc
@@ -22,7 +22,7 @@ void TileDrawInfo::AsValueInto(base::trace_event::TracedValue* state) const {
Resource* TileDrawInfo::TakeResource() {
Resource* resource = resource_;
- set_resource(nullptr);
+ set_resource(nullptr, false);
return resource;
}
diff --git a/chromium/cc/tiles/tile_draw_info.h b/chromium/cc/tiles/tile_draw_info.h
index 8ba08857dd2..dc1a8855506 100644
--- a/chromium/cc/tiles/tile_draw_info.h
+++ b/chromium/cc/tiles/tile_draw_info.h
@@ -77,6 +77,11 @@ class CC_EXPORT TileDrawInfo {
return resource_ ? IsResourceFormatCompressed(resource_->format()) : false;
}
+ bool is_checker_imaged() const {
+ DCHECK(!resource_is_checker_imaged_ || resource_);
+ return resource_is_checker_imaged_;
+ }
+
void SetSolidColorForTesting(SkColor color) { set_solid_color(color); }
void AsValueInto(base::trace_event::TracedValue* state) const;
@@ -87,9 +92,13 @@ class CC_EXPORT TileDrawInfo {
const Resource* resource() const { return resource_; }
- void set_resource(Resource* resource) {
+ void set_resource(Resource* resource, bool resource_is_checker_imaged) {
+ DCHECK(!resource_is_checker_imaged || resource)
+ << "Need to have a resource for it to be checker-imaged";
+
mode_ = RESOURCE_MODE;
is_resource_ready_to_draw_ = false;
+ resource_is_checker_imaged_ = resource_is_checker_imaged;
resource_ = resource;
}
@@ -111,6 +120,10 @@ class CC_EXPORT TileDrawInfo {
Resource* resource_ = nullptr;
bool contents_swizzled_ = false;
bool is_resource_ready_to_draw_ = false;
+
+ // Set to true if |resource_| was rasterized with checker-imaged content. The
+ // flag can only be true iff we have a valid |resource_|.
+ bool resource_is_checker_imaged_ = false;
};
} // namespace cc
diff --git a/chromium/cc/tiles/tile_manager.cc b/chromium/cc/tiles/tile_manager.cc
index 5639661f713..b34cbb8f2e4 100644
--- a/chromium/cc/tiles/tile_manager.cc
+++ b/chromium/cc/tiles/tile_manager.cc
@@ -425,6 +425,10 @@ void TileManager::SetResources(ResourcePool* resource_pool,
}
void TileManager::Release(Tile* tile) {
+ if (tile->raster_task_scheduled_with_checker_images())
+ num_of_tiles_with_checker_images_--;
+ DCHECK_GE(num_of_tiles_with_checker_images_, 0);
+
FreeResourcesForTile(tile);
tiles_.erase(tile->id());
}
@@ -522,6 +526,10 @@ void TileManager::Flush() {
tile_task_manager_->CheckForCompletedTasks();
did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
+
+ // Actually flush.
+ raster_buffer_provider_->Flush();
+
CheckPendingGpuWorkTiles(true /* issue_signals */);
TRACE_EVENT_INSTANT1("cc", "DidFlush", TRACE_EVENT_SCOPE_THREAD, "stats",
@@ -639,6 +647,8 @@ TileManager::PrioritizedWorkToSchedule TileManager::AssignGpuMemoryToTiles() {
MemoryUsage memory_usage(resource_pool_->memory_usage_bytes(),
resource_pool_->resource_count());
+ gfx::ColorSpace raster_color_space = client_->GetRasterColorSpace();
+
std::unique_ptr<RasterTilePriorityQueue> raster_priority_queue(
client_->BuildRasterQueue(global_state_.tree_priority,
RasterTilePriorityQueue::Type::ALL));
@@ -684,6 +694,21 @@ TileManager::PrioritizedWorkToSchedule TileManager::AssignGpuMemoryToTiles() {
continue;
}
+ // Tiles in the raster queue should either require raster or decode for
+ // checker-images. If this tile does not need raster, process it only to
+ // build the decode queue for checkered images.
+ // Note that performing this check after the solid color analysis is not
+ // necessary for correctness.
+ if (!tile->draw_info().NeedsRaster()) {
+ DCHECK(tile->draw_info().is_checker_imaged());
+ DCHECK(prioritized_tile.should_decode_checkered_images_for_tile());
+
+ AddCheckeredImagesToDecodeQueue(
+ prioritized_tile, raster_color_space,
+ &work_to_schedule.checker_image_decode_queue);
+ continue;
+ }
+
// We won't be able to schedule this tile, so break out early.
if (work_to_schedule.tiles_to_raster.size() >=
scheduled_raster_task_limit_) {
@@ -729,6 +754,25 @@ TileManager::PrioritizedWorkToSchedule TileManager::AssignGpuMemoryToTiles() {
break;
}
+ // If the tile has a scheduled task that will rasterize a resource with
+ // checker-imaged content, add those images to the decode queue. Note that
+ // we add all images as we process the raster priority queue to ensure that
+ // images are added to the decode queue in raster priority order.
+ if (tile->HasRasterTask()) {
+ if (tile->raster_task_scheduled_with_checker_images() &&
+ prioritized_tile.should_decode_checkered_images_for_tile()) {
+ AddCheckeredImagesToDecodeQueue(
+ prioritized_tile, raster_color_space,
+ &work_to_schedule.checker_image_decode_queue);
+ }
+ } else {
+ // Creating the raster task here will acquire resources, but
+ // this resource usage has already been accounted for above.
+ tile->raster_task_ =
+ CreateRasterTask(prioritized_tile, client_->GetRasterColorSpace(),
+ &work_to_schedule.checker_image_decode_queue);
+ }
+
memory_usage += memory_required_by_tile_to_be_scheduled;
work_to_schedule.tiles_to_raster.push_back(prioritized_tile);
}
@@ -739,6 +783,33 @@ TileManager::PrioritizedWorkToSchedule TileManager::AssignGpuMemoryToTiles() {
eviction_priority_queue = FreeTileResourcesUntilUsageIsWithinLimit(
std::move(eviction_priority_queue), hard_memory_limit, &memory_usage);
+ // At this point, if we ran out of memory when allocating resources and we
+ // couldn't go past even the NOW bin, this means we have evicted resources
+ // from all tiles with a lower priority while we still might have resources
+ // holding checker-imaged content. The invalidations for these resources will
+ // be generated only if the skipped images are decoded. So we must schedule
+ // decodes for these tiles to update their content.
+ if (!had_enough_memory_to_schedule_tiles_needed_now &&
+ num_of_tiles_with_checker_images_ > 0) {
+ for (; !raster_priority_queue->IsEmpty(); raster_priority_queue->Pop()) {
+ const PrioritizedTile& prioritized_tile = raster_priority_queue->Top();
+
+ if (prioritized_tile.priority().priority_bin > TilePriority::NOW)
+ break;
+
+ if (!prioritized_tile.should_decode_checkered_images_for_tile())
+ continue;
+
+ Tile* tile = prioritized_tile.tile();
+ if (tile->draw_info().is_checker_imaged() ||
+ tile->raster_task_scheduled_with_checker_images()) {
+ AddCheckeredImagesToDecodeQueue(
+ prioritized_tile, raster_color_space,
+ &work_to_schedule.checker_image_decode_queue);
+ }
+ }
+ }
+
UMA_HISTOGRAM_BOOLEAN("TileManager.ExceededMemoryBudget",
!had_enough_memory_to_schedule_tiles_needed_now);
did_oom_on_last_assign_ = !had_enough_memory_to_schedule_tiles_needed_now;
@@ -760,6 +831,11 @@ TileManager::PrioritizedWorkToSchedule TileManager::AssignGpuMemoryToTiles() {
void TileManager::FreeResourcesForTile(Tile* tile) {
TileDrawInfo& draw_info = tile->draw_info();
+
+ if (draw_info.is_checker_imaged())
+ num_of_tiles_with_checker_images_--;
+ DCHECK_GE(num_of_tiles_with_checker_images_, 0);
+
Resource* resource = draw_info.TakeResource();
if (resource) {
resource_pool_->ReleaseResource(resource);
@@ -775,6 +851,45 @@ void TileManager::FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(
client_->NotifyTileStateChanged(tile);
}
+void TileManager::PartitionImagesForCheckering(
+ const PrioritizedTile& prioritized_tile,
+ const gfx::ColorSpace& raster_color_space,
+ std::vector<DrawImage>* sync_decoded_images,
+ std::vector<PaintImage>* checkered_images) {
+ Tile* tile = prioritized_tile.tile();
+ std::vector<DrawImage> images_in_tile;
+ prioritized_tile.raster_source()->GetDiscardableImagesInRect(
+ tile->enclosing_layer_rect(), tile->raster_transform().scale(),
+ raster_color_space, &images_in_tile);
+ WhichTree tree = tile->tiling()->tree();
+
+ for (auto& draw_image : images_in_tile) {
+ if (checker_image_tracker_.ShouldCheckerImage(draw_image.paint_image(),
+ tree))
+ checkered_images->push_back(draw_image.paint_image());
+ else
+ sync_decoded_images->push_back(draw_image);
+ }
+}
+
+void TileManager::AddCheckeredImagesToDecodeQueue(
+ const PrioritizedTile& prioritized_tile,
+ const gfx::ColorSpace& raster_color_space,
+ CheckerImageTracker::ImageDecodeQueue* image_decode_queue) {
+ Tile* tile = prioritized_tile.tile();
+ std::vector<DrawImage> images_in_tile;
+ prioritized_tile.raster_source()->GetDiscardableImagesInRect(
+ tile->enclosing_layer_rect(), tile->raster_transform().scale(),
+ raster_color_space, &images_in_tile);
+ WhichTree tree = tile->tiling()->tree();
+
+ for (auto& draw_image : images_in_tile) {
+ if (checker_image_tracker_.ShouldCheckerImage(draw_image.paint_image(),
+ tree))
+ image_decode_queue->push_back(draw_image.paint_image());
+ }
+}
+
void TileManager::ScheduleTasks(
const PrioritizedWorkToSchedule& work_to_schedule) {
const std::vector<PrioritizedTile>& tiles_that_need_to_be_rasterized =
@@ -823,11 +938,7 @@ void TileManager::ScheduleTasks(
DCHECK(tile->draw_info().requires_resource());
DCHECK(!tile->draw_info().resource());
-
- if (!tile->raster_task_) {
- tile->raster_task_ =
- CreateRasterTask(prioritized_tile, raster_color_space);
- }
+ DCHECK(tile->HasRasterTask());
TileTask* task = tile->raster_task_.get();
@@ -880,7 +991,6 @@ void TileManager::ScheduleTasks(
std::vector<scoped_refptr<TileTask>> new_locked_image_tasks =
image_controller_.SetPredecodeImages(std::move(new_locked_images),
tracing_info);
-
for (auto& task : new_locked_image_tasks) {
auto decode_it = std::find_if(graph_.nodes.begin(), graph_.nodes.end(),
[&task](const TaskGraph::Node& node) {
@@ -929,6 +1039,12 @@ void TileManager::ScheduleTasks(
// in |raster_queue_|.
tile_task_manager_->ScheduleTasks(&graph_);
+ // Schedule running of the checker-image decode queue. This replaces the
+ // previously scheduled queue and effectively cancels image decodes from the
+ // previous queue, if not already started.
+ checker_image_tracker_.ScheduleImageDecodeQueue(
+ std::move(work_to_schedule.checker_image_decode_queue));
+
did_check_for_completed_tasks_since_last_schedule_tasks_ = false;
TRACE_EVENT_ASYNC_STEP_INTO1("cc", "ScheduledTasks", this, "running", "state",
@@ -937,8 +1053,13 @@ void TileManager::ScheduleTasks(
scoped_refptr<TileTask> TileManager::CreateRasterTask(
const PrioritizedTile& prioritized_tile,
- const gfx::ColorSpace& color_space) {
+ const gfx::ColorSpace& color_space,
+ CheckerImageTracker::ImageDecodeQueue* checker_image_decode_queue) {
+ TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
+ "TileManager::CreateRasterTask");
Tile* tile = prioritized_tile.tile();
+ TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
+ "TileManager::CreateRasterTask", "Tile", tile->id());
// Get the resource.
uint64_t resource_content_id = 0;
@@ -964,29 +1085,44 @@ scoped_refptr<TileTask> TileManager::CreateRasterTask(
playback_settings.skip_images =
prioritized_tile.priority().resolution == LOW_RESOLUTION;
- // Create and queue all image decode tasks that this tile depends on.
+ // Create and queue all image decode tasks that this tile depends on. Note
+ // that we need to store the images for decode tasks in
+ // |scheduled_draw_images_| since the tile might have been destroyed by the
+ // time the raster task finishes.
TileTask::Vector decode_tasks;
- std::vector<DrawImage>& images = scheduled_draw_images_[tile->id()];
- ImageIdFlatSet images_to_skip;
- images.clear();
+ std::vector<DrawImage>& sync_decoded_images =
+ scheduled_draw_images_[tile->id()];
+ sync_decoded_images.clear();
if (!playback_settings.skip_images) {
- prioritized_tile.raster_source()->GetDiscardableImagesInRect(
- tile->enclosing_layer_rect(), tile->raster_transform().scale(),
- color_space, &images);
- checker_image_tracker_.FilterImagesForCheckeringForTile(
- &images, &images_to_skip, prioritized_tile.tile()->tiling()->tree());
+ std::vector<PaintImage> checkered_images;
+ PartitionImagesForCheckering(prioritized_tile, color_space,
+ &sync_decoded_images, &checkered_images);
+ for (const auto& image : checkered_images) {
+ playback_settings.images_to_skip.insert(image.sk_image()->uniqueID());
+
+ // This can be the case for tiles on the active tree that will be replaced
+ // or are occluded on the pending tree. While we still need to continue
+ // skipping images for these tiles, we don't need to decode them since
+ // they will not be required on the next active tree.
+ if (prioritized_tile.should_decode_checkered_images_for_tile())
+ checker_image_decode_queue->push_back(image);
+ }
}
// We can skip the image hijack canvas if we have no images, or no images to
// skip during raster.
playback_settings.use_image_hijack_canvas =
- !images.empty() || !images_to_skip.empty();
- playback_settings.images_to_skip = std::move(images_to_skip);
+ !sync_decoded_images.empty() || !playback_settings.images_to_skip.empty();
+
+ bool has_checker_images = !playback_settings.images_to_skip.empty();
+ tile->set_raster_task_scheduled_with_checker_images(has_checker_images);
+ if (has_checker_images)
+ num_of_tiles_with_checker_images_++;
// Get the tasks for the required images.
ImageDecodeCache::TracingInfo tracing_info(
prepare_tiles_count_, prioritized_tile.priority().priority_bin);
- image_controller_.GetTasksForImagesAndRef(&images, &decode_tasks,
+ image_controller_.GetTasksForImagesAndRef(&sync_decoded_images, &decode_tasks,
tracing_info);
std::unique_ptr<RasterBuffer> raster_buffer =
@@ -1012,10 +1148,15 @@ void TileManager::OnRasterTaskCompleted(
auto found = tiles_.find(tile_id);
Tile* tile = nullptr;
+ bool raster_task_was_scheduled_with_checker_images = false;
if (found != tiles_.end()) {
tile = found->second;
DCHECK(tile->raster_task_.get());
tile->raster_task_ = nullptr;
+ raster_task_was_scheduled_with_checker_images =
+ tile->set_raster_task_scheduled_with_checker_images(false);
+ if (raster_task_was_scheduled_with_checker_images)
+ num_of_tiles_with_checker_images_--;
}
// Unref all the images.
@@ -1038,8 +1179,11 @@ void TileManager::OnRasterTaskCompleted(
}
TileDrawInfo& draw_info = tile->draw_info();
- draw_info.set_resource(resource);
+ draw_info.set_resource(resource,
+ raster_task_was_scheduled_with_checker_images);
draw_info.contents_swizzled_ = DetermineResourceRequiresSwizzle(tile);
+ if (raster_task_was_scheduled_with_checker_images)
+ num_of_tiles_with_checker_images_++;
// In SMOOTHNESS_TAKES_PRIORITY mode, we wait for GPU work to complete for a
// tile before setting it as ready to draw.
@@ -1248,7 +1392,7 @@ void TileManager::MarkTilesOutOfMemory(
}
}
-const ImageIdFlatSet& TileManager::TakeImagesToInvalidateOnSyncTree() {
+const PaintImageIdFlatSet& TileManager::TakeImagesToInvalidateOnSyncTree() {
return checker_image_tracker_.TakeImagesToInvalidateOnSyncTree();
}
@@ -1256,6 +1400,11 @@ void TileManager::DidActivateSyncTree() {
checker_image_tracker_.DidActivateSyncTree();
}
+void TileManager::ClearCheckerImageTracking(
+ bool can_clear_decode_policy_tracking) {
+ checker_image_tracker_.ClearTracker(can_clear_decode_policy_tracking);
+}
+
void TileManager::NeedsInvalidationForCheckerImagedTiles() {
client_->RequestImplSideInvalidation();
}
@@ -1287,6 +1436,11 @@ bool TileManager::UsePartialRaster() const {
}
void TileManager::CheckPendingGpuWorkTiles(bool issue_signals) {
+ TRACE_EVENT2("cc", "TileManager::CheckPendingGpuWorkTiles",
+ "pending_gpu_work_tiles", pending_gpu_work_tiles_.size(),
+ "tree_priority",
+ TreePriorityToString(global_state_.tree_priority));
+
ResourceProvider::ResourceIdArray required_for_activation_ids;
ResourceProvider::ResourceIdArray required_for_draw_ids;
@@ -1364,6 +1518,12 @@ scoped_refptr<TileTask> TileManager::CreateTaskSetFinishedTask(
std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
TileManager::ActivationStateAsValue() {
auto state = base::MakeUnique<base::trace_event::TracedValue>();
+ ActivationStateAsValueInto(state.get());
+ return std::move(state);
+}
+
+void TileManager::ActivationStateAsValueInto(
+ base::trace_event::TracedValue* state) {
state->SetString("tree_priority",
TreePriorityToString(global_state_.tree_priority));
state->SetInteger("soft_memory_limit",
@@ -1402,7 +1562,7 @@ TileManager::ActivationStateAsValue() {
state->BeginArray("raster_tiles");
for (; !raster_priority_queue->IsEmpty(); raster_priority_queue->Pop()) {
state->BeginDictionary();
- tile_as_value(raster_priority_queue->Top(), state.get());
+ tile_as_value(raster_priority_queue->Top(), state);
state->EndDictionary();
}
state->EndArray();
@@ -1414,12 +1574,10 @@ TileManager::ActivationStateAsValue() {
state->BeginArray("activation_tiles");
for (; !required_priority_queue->IsEmpty(); required_priority_queue->Pop()) {
state->BeginDictionary();
- tile_as_value(required_priority_queue->Top(), state.get());
+ tile_as_value(required_priority_queue->Top(), state);
state->EndDictionary();
}
state->EndArray();
-
- return std::move(state);
}
TileManager::MemoryUsage::MemoryUsage()
diff --git a/chromium/cc/tiles/tile_manager.h b/chromium/cc/tiles/tile_manager.h
index 3327cf1bf99..9b503e6af37 100644
--- a/chromium/cc/tiles/tile_manager.h
+++ b/chromium/cc/tiles/tile_manager.h
@@ -15,6 +15,7 @@
#include <vector>
#include "base/macros.h"
+#include "base/sequenced_task_runner.h"
#include "base/values.h"
#include "cc/base/unique_notifier.h"
#include "cc/raster/raster_buffer_provider.h"
@@ -150,8 +151,9 @@ class CC_EXPORT TileManager : CheckerImageTrackerClient {
bool IsReadyToActivate() const;
bool IsReadyToDraw() const;
- const ImageIdFlatSet& TakeImagesToInvalidateOnSyncTree();
+ const PaintImageIdFlatSet& TakeImagesToInvalidateOnSyncTree();
void DidActivateSyncTree();
+ void ClearCheckerImageTracking(bool can_clear_decode_policy_tracking);
std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
BasicStateAsValue() const;
@@ -164,10 +166,12 @@ class CC_EXPORT TileManager : CheckerImageTrackerClient {
void InitializeTilesWithResourcesForTesting(const std::vector<Tile*>& tiles) {
for (size_t i = 0; i < tiles.size(); ++i) {
TileDrawInfo& draw_info = tiles[i]->draw_info();
- draw_info.set_resource(resource_pool_->AcquireResource(
- tiles[i]->desired_texture_size(),
- raster_buffer_provider_->GetResourceFormat(false),
- client_->GetRasterColorSpace()));
+ draw_info.set_resource(
+ resource_pool_->AcquireResource(
+ tiles[i]->desired_texture_size(),
+ raster_buffer_provider_->GetResourceFormat(false),
+ client_->GetRasterColorSpace()),
+ false);
draw_info.set_resource_ready_for_draw();
}
}
@@ -234,6 +238,11 @@ class CC_EXPORT TileManager : CheckerImageTrackerClient {
std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
ActivationStateAsValue();
+ void ActivationStateAsValueInto(base::trace_event::TracedValue* state);
+ int num_of_tiles_with_checker_images() const {
+ return num_of_tiles_with_checker_images_;
+ }
+
protected:
friend class Tile;
// Must be called by tile during destruction.
@@ -281,13 +290,15 @@ class CC_EXPORT TileManager : CheckerImageTrackerClient {
std::vector<PrioritizedTile> tiles_to_raster;
std::vector<PrioritizedTile> tiles_to_process_for_images;
+ CheckerImageTracker::ImageDecodeQueue checker_image_decode_queue;
};
void FreeResourcesForTile(Tile* tile);
void FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(Tile* tile);
scoped_refptr<TileTask> CreateRasterTask(
const PrioritizedTile& prioritized_tile,
- const gfx::ColorSpace& color_space);
+ const gfx::ColorSpace& color_space,
+ CheckerImageTracker::ImageDecodeQueue* checker_image_decode_queue);
std::unique_ptr<EvictionTilePriorityQueue>
FreeTileResourcesUntilUsageIsWithinLimit(
@@ -319,6 +330,15 @@ class CC_EXPORT TileManager : CheckerImageTrackerClient {
PrioritizedWorkToSchedule AssignGpuMemoryToTiles();
void ScheduleTasks(const PrioritizedWorkToSchedule& work_to_schedule);
+ void PartitionImagesForCheckering(const PrioritizedTile& prioritized_tile,
+ const gfx::ColorSpace& raster_color_space,
+ std::vector<DrawImage>* sync_decoded_images,
+ std::vector<PaintImage>* checkered_images);
+ void AddCheckeredImagesToDecodeQueue(
+ const PrioritizedTile& prioritized_tile,
+ const gfx::ColorSpace& raster_color_space,
+ CheckerImageTracker::ImageDecodeQueue* image_decode_queue);
+
std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
ScheduledTasksStateAsValue() const;
@@ -373,6 +393,10 @@ class CC_EXPORT TileManager : CheckerImageTrackerClient {
std::unordered_map<Tile::Id, std::vector<DrawImage>> scheduled_draw_images_;
std::vector<scoped_refptr<TileTask>> locked_image_tasks_;
+ // Number of tiles with a checker-imaged resource or active raster tasks which
+ // will create a checker-imaged resource.
+ int num_of_tiles_with_checker_images_ = 0;
+
// We need two WeakPtrFactory objects as the invalidation pattern of each is
// different. The |task_set_finished_weak_ptr_factory_| is invalidated any
// time new tasks are scheduled, preventing a race when the callback has
diff --git a/chromium/cc/tiles/tile_manager_unittest.cc b/chromium/cc/tiles/tile_manager_unittest.cc
index b410cc006af..4cfe0123e32 100644
--- a/chromium/cc/tiles/tile_manager_unittest.cc
+++ b/chromium/cc/tiles/tile_manager_unittest.cc
@@ -29,6 +29,7 @@
#include "cc/test/fake_recording_source.h"
#include "cc/test/fake_tile_manager.h"
#include "cc/test/fake_tile_task_manager.h"
+#include "cc/test/skia_common.h"
#include "cc/test/test_layer_tree_host_base.h"
#include "cc/test/test_task_graph_runner.h"
#include "cc/test/test_tile_priorities.h"
@@ -1493,7 +1494,7 @@ TEST_F(TileManagerTilePriorityQueueTest, NoRasterTasksforSolidColorTiles) {
std::unique_ptr<PictureLayerImpl> layer_impl = PictureLayerImpl::Create(
host_impl()->active_tree(), 1, Layer::LayerMaskType::NOT_MASK);
- layer_impl->set_is_drawn_render_surface_layer_list_member(true);
+ layer_impl->set_contributes_to_drawn_render_surface(true);
PictureLayerTilingSet* tiling_set = layer_impl->picture_layer_tiling_set();
PictureLayerTiling* tiling =
@@ -1698,7 +1699,7 @@ TEST_F(TileManagerTest, LowResHasNoImage) {
std::unique_ptr<PictureLayerImpl> layer = PictureLayerImpl::Create(
host_impl()->active_tree(), 1, Layer::LayerMaskType::NOT_MASK);
PictureLayerTilingSet* tiling_set = layer->picture_layer_tiling_set();
- layer->set_is_drawn_render_surface_layer_list_member(true);
+ layer->set_contributes_to_drawn_render_surface(true);
auto* tiling = tiling_set->AddTiling(gfx::AxisTransform2d(), raster);
tiling->set_resolution(resolutions[i]);
@@ -2320,14 +2321,14 @@ class CheckerImagingTileManagerTest : public TestLayerTreeHostBase {
SkImageInfo::MakeN32Premul(size.width(), size.height())) {}
protected:
- MOCK_METHOD5(onGetPixels,
- bool(const SkImageInfo&, void*, size_t, SkPMColor[], int*));
+ MOCK_METHOD4(onGetPixels,
+ bool(const SkImageInfo&, void*, size_t, const Options&));
};
void TearDown() override {
// Allow all tasks on the image worker to run now. Any scheduled decodes
// will be aborted.
- image_worker_task_runner()->set_run_tasks_synchronously(true);
+ task_runner_->set_run_tasks_synchronously(true);
}
LayerTreeSettings CreateSettings() override {
@@ -2351,8 +2352,11 @@ class CheckerImagingTileManagerTest : public TestLayerTreeHostBase {
return base::MakeUnique<SynchronousTaskGraphRunner>();
}
- SynchronousSimpleTaskRunner* image_worker_task_runner() const {
- return task_runner_.get();
+ void FlushDecodeTasks() {
+ while (task_runner_->HasPendingTask()) {
+ task_runner_->RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
+ }
}
private:
@@ -2366,7 +2370,7 @@ TEST_F(CheckerImagingTileManagerTest,
std::unique_ptr<FakeRecordingSource> recording_source =
FakeRecordingSource::CreateFilledRecordingSource(layer_bounds);
- recording_source->SetGenerateDiscardableImagesMetadata(true);
+ recording_source->set_fill_with_nonsolid_color(true);
sk_sp<SkImage> image = SkImage::MakeFromGenerator(
base::MakeUnique<testing::StrictMock<MockImageGenerator>>(
@@ -2379,7 +2383,7 @@ TEST_F(CheckerImagingTileManagerTest,
std::unique_ptr<PictureLayerImpl> layer_impl = PictureLayerImpl::Create(
host_impl()->active_tree(), 1, Layer::LayerMaskType::NOT_MASK);
- layer_impl->set_is_drawn_render_surface_layer_list_member(true);
+ layer_impl->set_contributes_to_drawn_render_surface(true);
PictureLayerTilingSet* tiling_set = layer_impl->picture_layer_tiling_set();
PictureLayerTiling* tiling =
@@ -2402,5 +2406,252 @@ TEST_F(CheckerImagingTileManagerTest,
EXPECT_FALSE(host_impl()->tile_manager()->HasScheduledTileTasksForTesting());
}
+TEST_F(CheckerImagingTileManagerTest, BuildsImageDecodeQueueAsExpected) {
+ const gfx::Size layer_bounds(900, 900);
+
+ std::unique_ptr<FakeRecordingSource> recording_source =
+ FakeRecordingSource::CreateFilledRecordingSource(layer_bounds);
+ recording_source->set_fill_with_nonsolid_color(true);
+
+ int dimension = 450;
+ sk_sp<SkImage> image1 =
+ CreateDiscardableImage(gfx::Size(dimension, dimension));
+ sk_sp<SkImage> image2 =
+ CreateDiscardableImage(gfx::Size(dimension, dimension));
+ sk_sp<SkImage> image3 =
+ CreateDiscardableImage(gfx::Size(dimension, dimension));
+ recording_source->add_draw_image(image1, gfx::Point(0, 0));
+ recording_source->add_draw_image(image2, gfx::Point(600, 0));
+ recording_source->add_draw_image(image3, gfx::Point(0, 600));
+
+ recording_source->Rerecord();
+ scoped_refptr<RasterSource> raster_source =
+ RasterSource::CreateFromRecordingSource(recording_source.get(), false);
+
+ gfx::Size tile_size(500, 500);
+ Region invalidation((gfx::Rect(layer_bounds)));
+ SetupPendingTree(raster_source, tile_size, invalidation);
+
+ PictureLayerTilingSet* tiling_set =
+ pending_layer()->picture_layer_tiling_set();
+ PictureLayerTiling* pending_tiling = tiling_set->tiling_at(0);
+ pending_tiling->set_resolution(HIGH_RESOLUTION);
+ pending_tiling->CreateAllTilesForTesting();
+ pending_tiling->SetTilePriorityRectsForTesting(
+ gfx::Rect(layer_bounds), // Visible rect.
+ gfx::Rect(layer_bounds), // Skewport rect.
+ gfx::Rect(layer_bounds), // Soon rect.
+ gfx::Rect(layer_bounds)); // Eventually rect.
+
+ // PrepareTiles and make sure we account correctly for tiles that have been
+ // scheduled with checkered images.
+ host_impl()->tile_manager()->PrepareTiles(host_impl()->global_tile_state());
+ EXPECT_TRUE(host_impl()->tile_manager()->HasScheduledTileTasksForTesting());
+
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 2; j++) {
+ const Tile* tile = pending_tiling->TileAt(i, j);
+ EXPECT_TRUE(tile->HasRasterTask());
+ if (i == 1 && j == 1)
+ EXPECT_FALSE(tile->raster_task_scheduled_with_checker_images());
+ else
+ EXPECT_TRUE(tile->raster_task_scheduled_with_checker_images());
+ }
+ }
+ EXPECT_EQ(host_impl()->tile_manager()->num_of_tiles_with_checker_images(), 3);
+
+ // Now raster all the tiles and make sure these tiles are still accounted for
+ // with checkered images.
+ static_cast<SynchronousTaskGraphRunner*>(task_graph_runner())->RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(host_impl()->tile_manager()->HasScheduledTileTasksForTesting());
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 2; j++) {
+ const Tile* tile = pending_tiling->TileAt(i, j);
+ EXPECT_FALSE(tile->HasRasterTask());
+ EXPECT_FALSE(tile->raster_task_scheduled_with_checker_images());
+ EXPECT_TRUE(tile->draw_info().has_resource());
+ if (i == 1 && j == 1)
+ EXPECT_FALSE(tile->draw_info().is_checker_imaged());
+ else
+ EXPECT_TRUE(tile->draw_info().is_checker_imaged());
+ }
+ }
+ EXPECT_EQ(host_impl()->tile_manager()->num_of_tiles_with_checker_images(), 3);
+
+ // Activate the pending tree.
+ ActivateTree();
+
+ // Set empty tile priority rects so an empty image decode queue is used.
+ gfx::Rect empty_rect;
+ PictureLayerTiling* active_tiling =
+ active_layer()->picture_layer_tiling_set()->tiling_at(0);
+ active_tiling->SetTilePriorityRectsForTesting(
+ gfx::Rect(empty_rect), // Visible rect.
+ gfx::Rect(empty_rect), // Skewport rect.
+ gfx::Rect(empty_rect), // Soon rect.
+ gfx::Rect(empty_rect)); // Eventually rect.
+ host_impl()->tile_manager()->PrepareTiles(host_impl()->global_tile_state());
+
+ // Run the decode tasks. Since the first decode is always scheduled, the
+ // completion for it should be triggered.
+ FlushDecodeTasks();
+
+ // Create a new pending tree to invalidate tiles for decoded images and verify
+ // that only tiles for |image1| are invalidated.
+ EXPECT_TRUE(host_impl()->client()->did_request_impl_side_invalidation());
+ PerformImplSideInvalidation();
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 2; j++) {
+ const Tile* tile = pending_tiling->TileAt(i, j);
+ if (i == 0 && j == 0)
+ EXPECT_TRUE(tile);
+ else
+ EXPECT_FALSE(tile);
+ }
+ }
+ host_impl()->client()->reset_did_request_impl_side_invalidation();
+
+ // Activating the tree replaces the checker-imaged tile.
+ EXPECT_EQ(host_impl()->tile_manager()->num_of_tiles_with_checker_images(), 3);
+ ActivateTree();
+ EXPECT_EQ(host_impl()->tile_manager()->num_of_tiles_with_checker_images(), 2);
+
+ // Set the tile priority rects such that only the tile with the second image
+ // is scheduled for decodes, since it is checker-imaged.
+ gfx::Rect rect_to_raster(600, 0, 300, 900);
+ active_tiling->SetTilePriorityRectsForTesting(
+ gfx::Rect(rect_to_raster), // Visible rect.
+ gfx::Rect(rect_to_raster), // Skewport rect.
+ gfx::Rect(rect_to_raster), // Soon rect.
+ gfx::Rect(rect_to_raster)); // Eventually rect.
+ host_impl()->tile_manager()->PrepareTiles(host_impl()->global_tile_state());
+
+ // Run decode tasks to trigger completion of any pending decodes.
+ FlushDecodeTasks();
+
+ // Create a new pending tree to invalidate tiles for decoded images and verify
+ // that only tiles for |image2| are invalidated.
+ EXPECT_TRUE(host_impl()->client()->did_request_impl_side_invalidation());
+ PerformImplSideInvalidation();
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 2; j++) {
+ const Tile* tile = pending_tiling->TileAt(i, j);
+ if (i == 1 && j == 0)
+ EXPECT_TRUE(tile);
+ else
+ EXPECT_FALSE(tile);
+ }
+ }
+ host_impl()->client()->reset_did_request_impl_side_invalidation();
+
+ // Activating the tree replaces the checker-imaged tile.
+ EXPECT_EQ(host_impl()->tile_manager()->num_of_tiles_with_checker_images(), 2);
+ ActivateTree();
+ EXPECT_EQ(host_impl()->tile_manager()->num_of_tiles_with_checker_images(), 1);
+
+ // Set the tile priority rects to cover the complete tiling and change the
+ // visibility. While |image3| has not yet been decoded, since we are
+ // invisible no decodes should have been scheduled.
+ active_tiling->SetTilePriorityRectsForTesting(
+ gfx::Rect(layer_bounds), // Visible rect.
+ gfx::Rect(layer_bounds), // Skewport rect.
+ gfx::Rect(layer_bounds), // Soon rect.
+ gfx::Rect(layer_bounds)); // Eventually rect.
+ host_impl()->SetVisible(false);
+ host_impl()->tile_manager()->PrepareTiles(host_impl()->global_tile_state());
+ FlushDecodeTasks();
+ EXPECT_FALSE(host_impl()->client()->did_request_impl_side_invalidation());
+}
+
+class CheckerImagingTileManagerMemoryTest
+ : public CheckerImagingTileManagerTest {
+ public:
+ std::unique_ptr<FakeLayerTreeHostImpl> CreateHostImpl(
+ const LayerTreeSettings& settings,
+ TaskRunnerProvider* task_runner_provider,
+ TaskGraphRunner* task_graph_runner) override {
+ LayerTreeSettings new_settings = settings;
+ new_settings.gpu_memory_policy.num_resources_limit = 4;
+ return CheckerImagingTileManagerTest::CreateHostImpl(
+ new_settings, task_runner_provider, task_graph_runner);
+ }
+};
+
+TEST_F(CheckerImagingTileManagerMemoryTest, AddsAllNowTilesToImageDecodeQueue) {
+ const gfx::Size layer_bounds(900, 1400);
+
+ std::unique_ptr<FakeRecordingSource> recording_source =
+ FakeRecordingSource::CreateFilledRecordingSource(layer_bounds);
+ recording_source->set_fill_with_nonsolid_color(true);
+
+ int dimension = 450;
+ sk_sp<SkImage> image1 =
+ CreateDiscardableImage(gfx::Size(dimension, dimension));
+ sk_sp<SkImage> image2 =
+ CreateDiscardableImage(gfx::Size(dimension, dimension));
+ recording_source->add_draw_image(image1, gfx::Point(0, 515));
+ recording_source->add_draw_image(image2, gfx::Point(515, 515));
+
+ recording_source->Rerecord();
+ scoped_refptr<RasterSource> raster_source =
+ RasterSource::CreateFromRecordingSource(recording_source.get(), false);
+
+ gfx::Size tile_size(500, 500);
+ Region invalidation((gfx::Rect(layer_bounds)));
+ SetupPendingTree(raster_source, tile_size, invalidation);
+
+ PictureLayerTilingSet* tiling_set =
+ pending_layer()->picture_layer_tiling_set();
+ PictureLayerTiling* pending_tiling = tiling_set->tiling_at(0);
+ pending_tiling->set_resolution(HIGH_RESOLUTION);
+ pending_tiling->CreateAllTilesForTesting();
+
+ // Use a rect that only rasterizes the bottom 2 rows of tiles.
+ gfx::Rect rect_to_raster(0, 500, 900, 900);
+ pending_tiling->SetTilePriorityRectsForTesting(
+ rect_to_raster, // Visible rect.
+ rect_to_raster, // Skewport rect.
+ rect_to_raster, // Soon rect.
+ rect_to_raster); // Eventually rect.
+
+ // PrepareTiles, rasterize all scheduled tiles and activate while no images
+ // have been decoded.
+ host_impl()->tile_manager()->PrepareTiles(host_impl()->global_tile_state());
+ static_cast<SynchronousTaskGraphRunner*>(task_graph_runner())->RunUntilIdle();
+ base::RunLoop().RunUntilIdle();
+ ActivateTree();
+
+ // Expand the visible rect to include the complete tiling. The tile iteration
+ // will not go beyond the first tile since there are no resources with a lower
+ // priority that can be evicted. But we should still see image decodes
+ // scheduled for all visible tiles.
+ gfx::Rect complete_tiling_rect(layer_bounds);
+ PictureLayerTiling* active_tiling =
+ active_layer()->picture_layer_tiling_set()->tiling_at(0);
+ active_tiling->SetTilePriorityRectsForTesting(
+ complete_tiling_rect, // Visible rect.
+ complete_tiling_rect, // Skewport rect.
+ complete_tiling_rect, // Soon rect.
+ complete_tiling_rect); // Eventually rect.
+ host_impl()->tile_manager()->PrepareTiles(host_impl()->global_tile_state());
+
+ // Flush all decode tasks. The tiles with checkered images should be
+ // invalidated.
+ FlushDecodeTasks();
+ EXPECT_TRUE(host_impl()->client()->did_request_impl_side_invalidation());
+ PerformImplSideInvalidation();
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 3; j++) {
+ const Tile* tile = pending_tiling->TileAt(i, j);
+ if (j == 1)
+ EXPECT_TRUE(tile);
+ else
+ EXPECT_FALSE(tile);
+ }
+ }
+ host_impl()->client()->reset_did_request_impl_side_invalidation();
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/tiles/tiling_set_raster_queue_all.cc b/chromium/cc/tiles/tiling_set_raster_queue_all.cc
index 74bf1b2f144..adae8a8dfbe 100644
--- a/chromium/cc/tiles/tiling_set_raster_queue_all.cc
+++ b/chromium/cc/tiles/tiling_set_raster_queue_all.cc
@@ -200,8 +200,23 @@ bool TilingSetRasterQueueAll::OnePriorityRectIterator::
bool TilingSetRasterQueueAll::OnePriorityRectIterator::IsTileValid(
const Tile* tile) const {
- if (!tile || !TileNeedsRaster(tile))
+ if (!tile)
return false;
+
+ // A tile is valid for raster if it needs raster and is unoccluded.
+ bool tile_is_valid_for_raster =
+ tile->draw_info().NeedsRaster() && !tiling_->IsTileOccluded(tile);
+
+ // A tile is not valid for the raster queue if it is not valid for raster or
+ // processing for checker-images.
+ if (!tile_is_valid_for_raster) {
+ bool tile_is_valid_for_checker_images =
+ tile->draw_info().is_checker_imaged() &&
+ tiling_->ShouldDecodeCheckeredImagesForTile(tile);
+ if (!tile_is_valid_for_checker_images)
+ return false;
+ }
+
// After the pending visible rect has been processed, we must return false
// for pending visible rect tiles as tiling iterators do not ignore those
// tiles.
diff --git a/chromium/cc/tiles/tiling_set_raster_queue_all.h b/chromium/cc/tiles/tiling_set_raster_queue_all.h
index 318156380a1..73bb4c9e17b 100644
--- a/chromium/cc/tiles/tiling_set_raster_queue_all.h
+++ b/chromium/cc/tiles/tiling_set_raster_queue_all.h
@@ -44,9 +44,6 @@ class CC_EXPORT TilingSetRasterQueueAll {
protected:
~OnePriorityRectIterator() = default;
- bool TileNeedsRaster(const Tile* tile) const {
- return tile->draw_info().NeedsRaster() && !tiling_->IsTileOccluded(tile);
- }
template <typename TilingIteratorType>
void AdvanceToNextTile(TilingIteratorType* iterator);
diff --git a/chromium/cc/trees/damage_tracker.cc b/chromium/cc/trees/damage_tracker.cc
index aa4a6236801..d740521408d 100644
--- a/chromium/cc/trees/damage_tracker.cc
+++ b/chromium/cc/trees/damage_tracker.cc
@@ -14,6 +14,7 @@
#include "cc/layers/heads_up_display_layer_impl.h"
#include "cc/layers/layer_impl.h"
#include "cc/layers/render_surface_impl.h"
+#include "cc/trees/effect_node.h"
#include "cc/trees/layer_tree_host_common.h"
#include "cc/trees/layer_tree_impl.h"
#include "ui/gfx/geometry/rect_conversions.h"
@@ -29,18 +30,14 @@ DamageTracker::DamageTracker()
DamageTracker::~DamageTracker() {}
-void DamageTracker::UpdateDamageTrackingState(
- const LayerImplList& layer_list,
- const RenderSurfaceImpl* target_surface,
- bool target_surface_property_changed_only_from_descendant,
- const gfx::Rect& target_surface_content_rect,
- LayerImpl* target_surface_mask_layer,
- const FilterOperations& filters) {
+void DamageTracker::UpdateDamageTracking(
+ LayerTreeImpl* layer_tree_impl,
+ const RenderSurfaceList& render_surface_list) {
//
- // This function computes the "damage rect" of a target surface, and updates
- // the state that is used to correctly track damage across frames. The damage
- // rect is the region of the surface that may have changed and needs to be
- // redrawn. This can be used to scissor what is actually drawn, to save GPU
+ // This function computes the "damage rect" of each target surface, and
+ // updates the state that is used to correctly track damage across frames. The
+ // damage rect is the region of the surface that may have changed and needs to
+ // be redrawn. This can be used to scissor what is actually drawn, to save GPU
// computation and bandwidth.
//
// The surface's damage rect is computed as the union of all possible changes
@@ -52,25 +49,30 @@ void DamageTracker::UpdateDamageTrackingState(
//
// The basic algorithm for computing the damage region is as follows:
//
- // 1. compute damage caused by changes in active/new layers
- // for each layer in the layer_list:
- // if the layer is actually a render_surface:
- // add the surface's damage to our target surface.
- // else
- // add the layer's damage to the target surface.
+ // 1. compute damage caused by changes in contributing layers or surfaces
+ // for each contributing layer or render surface:
+ // add the layer's or surface's damage to the target surface.
//
// 2. compute damage caused by the target surface's mask, if it exists.
//
// 3. compute damage caused by old layers/surfaces that no longer exist
- // for each leftover layer:
+ // for each leftover layer or render surface:
// add the old layer/surface bounds to the target surface damage.
//
// 4. combine all partial damage rects to get the full damage rect.
//
// Additional important points:
//
- // - This algorithm is implicitly recursive; it assumes that descendant
- // surfaces have already computed their damage.
+ // - This algorithm requires that descendant surfaces compute their damage
+ // before ancestor surfaces. Further, since contributing surfaces with
+ // background filters can expand the damage caused by contributors
+ // underneath them (that is, before them in draw order), the exact damage
+ // caused by these contributors must be computed before computing the damage
+ // caused by the contributing surface. This is implemented by visiting
+ // layers in draw order, computing the damage caused by each one to their
+ // target; during this walk, as soon as all of a surface's contributors have
+ // been visited, the surface's own damage is computed and then added to its
+ // target's accumulated damage.
//
// - Changes to layers/surfaces indicate "damage" to the target surface; If a
// layer is not changed, it does NOT mean that the layer can skip drawing.
@@ -104,40 +106,98 @@ void DamageTracker::UpdateDamageTrackingState(
// erased from map.
//
- PrepareRectHistoryForUpdate();
+ for (RenderSurfaceImpl* render_surface : render_surface_list) {
+ render_surface->damage_tracker()->PrepareForUpdate();
+ }
+
+ EffectTree& effect_tree = layer_tree_impl->property_trees()->effect_tree;
+ int current_target_effect_id = EffectTree::kContentsRootNodeId;
+ DCHECK(effect_tree.GetRenderSurface(current_target_effect_id));
+ for (LayerImpl* layer : *layer_tree_impl) {
+ if (!layer->contributes_to_drawn_render_surface())
+ continue;
+
+ int next_target_effect_id = layer->render_target_effect_tree_index();
+ if (next_target_effect_id != current_target_effect_id) {
+ int lowest_common_ancestor_id =
+ effect_tree.LowestCommonAncestorWithRenderSurface(
+ current_target_effect_id, next_target_effect_id);
+ while (current_target_effect_id != lowest_common_ancestor_id) {
+ // Moving to a non-descendant target surface. This implies that the
+ // current target doesn't have any more contributors, since only
+ // descendants can contribute to a target, and the each's target's
+ // content (including content contributed by descendants) is contiguous
+ // in draw order.
+ RenderSurfaceImpl* current_target =
+ effect_tree.GetRenderSurface(current_target_effect_id);
+ current_target->damage_tracker()->ComputeSurfaceDamage(current_target);
+ RenderSurfaceImpl* parent_target = current_target->render_target();
+ parent_target->damage_tracker()->AccumulateDamageFromRenderSurface(
+ current_target);
+ current_target_effect_id =
+ effect_tree.Node(current_target_effect_id)->target_id;
+ }
+ current_target_effect_id = next_target_effect_id;
+ }
+
+ RenderSurfaceImpl* target_surface = layer->render_target();
+
+ // We skip damage from the HUD layer because (a) the HUD layer damages the
+ // whole frame and (b) we don't want HUD layer damage to be shown by the
+ // HUD damage rect visualization.
+ if (layer != layer_tree_impl->hud_layer()) {
+ target_surface->damage_tracker()->AccumulateDamageFromLayer(layer);
+ }
+ }
+
+ DCHECK_GE(current_target_effect_id, EffectTree::kContentsRootNodeId);
+ RenderSurfaceImpl* current_target =
+ effect_tree.GetRenderSurface(current_target_effect_id);
+ while (true) {
+ current_target->damage_tracker()->ComputeSurfaceDamage(current_target);
+ if (current_target->EffectTreeIndex() == EffectTree::kContentsRootNodeId)
+ break;
+ RenderSurfaceImpl* next_target = current_target->render_target();
+ next_target->damage_tracker()->AccumulateDamageFromRenderSurface(
+ current_target);
+ current_target = next_target;
+ }
+}
+
+void DamageTracker::ComputeSurfaceDamage(RenderSurfaceImpl* render_surface) {
+ // All damage from contributing layers and surfaces must already have been
+ // added to damage_for_this_update_ through calls to AccumulateDamageFromLayer
+ // and AccumulateDamageFromRenderSurface.
+
// These functions cannot be bypassed with early-exits, even if we know what
// the damage will be for this frame, because we need to update the damage
// tracker state to correctly track the next frame.
- DamageAccumulator damage_from_active_layers =
- TrackDamageFromActiveLayers(layer_list, target_surface);
DamageAccumulator damage_from_surface_mask =
- TrackDamageFromSurfaceMask(target_surface_mask_layer);
+ TrackDamageFromSurfaceMask(render_surface->MaskLayer());
DamageAccumulator damage_from_leftover_rects = TrackDamageFromLeftoverRects();
- DamageAccumulator damage_for_this_update;
-
- if (target_surface_property_changed_only_from_descendant) {
- damage_for_this_update.Union(target_surface_content_rect);
+ if (render_surface->SurfacePropertyChangedOnlyFromDescendant()) {
+ damage_for_this_update_ = DamageAccumulator();
+ damage_for_this_update_.Union(render_surface->content_rect());
} else {
// TODO(shawnsingh): can we clamp this damage to the surface's content rect?
// (affects performance, but not correctness)
- damage_for_this_update.Union(damage_from_active_layers);
- damage_for_this_update.Union(damage_from_surface_mask);
- damage_for_this_update.Union(damage_from_leftover_rects);
+ damage_for_this_update_.Union(damage_from_surface_mask);
+ damage_for_this_update_.Union(damage_from_leftover_rects);
gfx::Rect damage_rect;
- bool is_rect_valid = damage_for_this_update.GetAsRect(&damage_rect);
+ bool is_rect_valid = damage_for_this_update_.GetAsRect(&damage_rect);
if (is_rect_valid) {
- damage_rect =
- filters.MapRect(damage_rect, target_surface->SurfaceScale().matrix());
- damage_for_this_update = DamageAccumulator();
- damage_for_this_update.Union(damage_rect);
+ damage_rect = render_surface->Filters().MapRect(
+ damage_rect, render_surface->SurfaceScale().matrix());
+ damage_for_this_update_ = DamageAccumulator();
+ damage_for_this_update_.Union(damage_rect);
}
}
// Damage accumulates until we are notified that we actually did draw on that
// frame.
- current_damage_.Union(damage_for_this_update);
+ current_damage_.Union(damage_for_this_update_);
}
bool DamageTracker::GetDamageRectIfValid(gfx::Rect* rect) {
@@ -177,31 +237,6 @@ DamageTracker::SurfaceRectMapData& DamageTracker::RectDataForSurface(
return *it;
}
-DamageTracker::DamageAccumulator DamageTracker::TrackDamageFromActiveLayers(
- const LayerImplList& layer_list,
- const RenderSurfaceImpl* target_surface) {
- DamageAccumulator damage;
-
- for (size_t layer_index = 0; layer_index < layer_list.size(); ++layer_index) {
- // Visit layers in back-to-front order.
- LayerImpl* layer = layer_list[layer_index];
-
- // We skip damage from the HUD layer because (a) the HUD layer damages the
- // whole frame and (b) we don't want HUD layer damage to be shown by the
- // HUD damage rect visualization.
- if (layer == layer->layer_tree_impl()->hud_layer())
- continue;
-
- RenderSurfaceImpl* render_surface = layer->GetRenderSurface();
- if (render_surface && render_surface != target_surface)
- ExtendDamageForRenderSurface(render_surface, &damage);
- else
- ExtendDamageForLayer(layer, &damage);
- }
-
- return damage;
-}
-
DamageTracker::DamageAccumulator DamageTracker::TrackDamageFromSurfaceMask(
LayerImpl* target_surface_mask_layer) {
DamageAccumulator damage;
@@ -220,8 +255,9 @@ DamageTracker::DamageAccumulator DamageTracker::TrackDamageFromSurfaceMask(
return damage;
}
-void DamageTracker::PrepareRectHistoryForUpdate() {
+void DamageTracker::PrepareForUpdate() {
mailboxId_++;
+ damage_for_this_update_ = DamageAccumulator();
}
DamageTracker::DamageAccumulator DamageTracker::TrackDamageFromLeftoverRects() {
@@ -292,12 +328,11 @@ DamageTracker::DamageAccumulator DamageTracker::TrackDamageFromLeftoverRects() {
void DamageTracker::ExpandDamageInsideRectWithFilters(
const gfx::Rect& pre_filter_rect,
- const FilterOperations& filters,
- DamageAccumulator* damage) {
+ const FilterOperations& filters) {
gfx::Rect damage_rect;
- bool is_valid_rect = damage->GetAsRect(&damage_rect);
- // If the input isn't a valid rect, then there is no point in trying to make
- // it bigger.
+ bool is_valid_rect = damage_for_this_update_.GetAsRect(&damage_rect);
+ // If the damage accumulated so far isn't a valid rect, then there is no point
+ // in trying to make it bigger.
if (!is_valid_rect)
return;
@@ -308,11 +343,10 @@ void DamageTracker::ExpandDamageInsideRectWithFilters(
// Restrict it to the rectangle in which the background filter is shown.
expanded_damage_rect.Intersect(pre_filter_rect);
- damage->Union(expanded_damage_rect);
+ damage_for_this_update_.Union(expanded_damage_rect);
}
-void DamageTracker::ExtendDamageForLayer(LayerImpl* layer,
- DamageAccumulator* target_damage) {
+void DamageTracker::AccumulateDamageFromLayer(LayerImpl* layer) {
// There are two ways that a layer can damage a region of the target surface:
// 1. Property change (e.g. opacity, position, transforms):
// - the entire region of the layer itself damages the surface.
@@ -341,11 +375,11 @@ void DamageTracker::ExtendDamageForLayer(LayerImpl* layer,
if (layer_is_new || layer->LayerPropertyChanged()) {
// If a layer is new or has changed, then its entire layer rect affects the
// target surface.
- target_damage->Union(rect_in_target_space);
+ damage_for_this_update_.Union(rect_in_target_space);
// The layer's old region is now exposed on the target surface, too.
// Note old_rect_in_target_space is already in target space.
- target_damage->Union(old_rect_in_target_space);
+ damage_for_this_update_.Union(old_rect_in_target_space);
return;
}
@@ -357,13 +391,12 @@ void DamageTracker::ExtendDamageForLayer(LayerImpl* layer,
if (!damage_rect.IsEmpty()) {
gfx::Rect damage_rect_in_target_space =
MathUtil::MapEnclosingClippedRect(layer->DrawTransform(), damage_rect);
- target_damage->Union(damage_rect_in_target_space);
+ damage_for_this_update_.Union(damage_rect_in_target_space);
}
}
-void DamageTracker::ExtendDamageForRenderSurface(
- RenderSurfaceImpl* render_surface,
- DamageAccumulator* target_damage) {
+void DamageTracker::AccumulateDamageFromRenderSurface(
+ RenderSurfaceImpl* render_surface) {
// There are two ways a "descendant surface" can damage regions of the "target
// surface":
// 1. Property change:
@@ -390,10 +423,10 @@ void DamageTracker::ExtendDamageForRenderSurface(
if (surface_is_new || render_surface->SurfacePropertyChanged()) {
// The entire surface contributes damage.
- target_damage->Union(surface_rect_in_target_space);
+ damage_for_this_update_.Union(surface_rect_in_target_space);
// The surface's old region is now exposed on the target surface, too.
- target_damage->Union(old_surface_rect);
+ damage_for_this_update_.Union(old_surface_rect);
} else {
// Only the surface's damage_rect will damage the target surface.
gfx::Rect damage_rect_in_local_space;
@@ -405,9 +438,9 @@ void DamageTracker::ExtendDamageForRenderSurface(
const gfx::Transform& draw_transform = render_surface->draw_transform();
gfx::Rect damage_rect_in_target_space = MathUtil::MapEnclosingClippedRect(
draw_transform, damage_rect_in_local_space);
- target_damage->Union(damage_rect_in_target_space);
+ damage_for_this_update_.Union(damage_rect_in_target_space);
} else if (!is_valid_rect) {
- target_damage->Union(surface_rect_in_target_space);
+ damage_for_this_update_.Union(surface_rect_in_target_space);
}
}
@@ -421,7 +454,7 @@ void DamageTracker::ExtendDamageForRenderSurface(
render_surface->BackgroundFilters();
if (background_filters.HasFilterThatMovesPixels()) {
ExpandDamageInsideRectWithFilters(surface_rect_in_target_space,
- background_filters, target_damage);
+ background_filters);
}
}
diff --git a/chromium/cc/trees/damage_tracker.h b/chromium/cc/trees/damage_tracker.h
index 6ddc504dafa..751eeb977e5 100644
--- a/chromium/cc/trees/damage_tracker.h
+++ b/chromium/cc/trees/damage_tracker.h
@@ -21,6 +21,7 @@ namespace cc {
class FilterOperations;
class LayerImpl;
+class LayerTreeImpl;
class RenderSurfaceImpl;
// Computes the region where pixels have actually changed on a
@@ -31,15 +32,12 @@ class CC_EXPORT DamageTracker {
static std::unique_ptr<DamageTracker> Create();
~DamageTracker();
+ static void UpdateDamageTracking(
+ LayerTreeImpl* layer_tree_impl,
+ const RenderSurfaceList& render_surface_list);
+
void DidDrawDamagedArea() { current_damage_ = DamageAccumulator(); }
void AddDamageNextUpdate(const gfx::Rect& dmg) { current_damage_.Union(dmg); }
- void UpdateDamageTrackingState(
- const LayerImplList& layer_list,
- const RenderSurfaceImpl* target_surface,
- bool target_surface_property_changed_only_from_descendant,
- const gfx::Rect& target_surface_content_rect,
- LayerImpl* target_surface_mask_layer,
- const FilterOperations& filters);
bool GetDamageRectIfValid(gfx::Rect* rect);
@@ -84,21 +82,17 @@ class CC_EXPORT DamageTracker {
int bottom_ = 0;
};
- DamageAccumulator TrackDamageFromActiveLayers(
- const LayerImplList& layer_list,
- const RenderSurfaceImpl* target_surface);
DamageAccumulator TrackDamageFromSurfaceMask(
LayerImpl* target_surface_mask_layer);
DamageAccumulator TrackDamageFromLeftoverRects();
- void PrepareRectHistoryForUpdate();
- // These helper functions are used only in TrackDamageFromActiveLayers().
- void ExtendDamageForLayer(LayerImpl* layer, DamageAccumulator* target_damage);
- void ExtendDamageForRenderSurface(RenderSurfaceImpl* render_surface,
- DamageAccumulator* target_damage);
+ // These helper functions are used only during UpdateDamageTracking().
+ void PrepareForUpdate();
+ void AccumulateDamageFromLayer(LayerImpl* layer);
+ void AccumulateDamageFromRenderSurface(RenderSurfaceImpl* render_surface);
+ void ComputeSurfaceDamage(RenderSurfaceImpl* render_surface);
void ExpandDamageInsideRectWithFilters(const gfx::Rect& pre_filter_rect,
- const FilterOperations& filters,
- DamageAccumulator* damage);
+ const FilterOperations& filters);
struct LayerRectMapData {
LayerRectMapData() : layer_id_(0), mailboxId_(0) {}
@@ -147,6 +141,9 @@ class CC_EXPORT DamageTracker {
unsigned int mailboxId_;
DamageAccumulator current_damage_;
+ // Damage accumulated since the last call to PrepareForUpdate().
+ DamageAccumulator damage_for_this_update_;
+
DISALLOW_COPY_AND_ASSIGN(DamageTracker);
};
diff --git a/chromium/cc/trees/damage_tracker_unittest.cc b/chromium/cc/trees/damage_tracker_unittest.cc
index 91cec6dc030..d036723038e 100644
--- a/chromium/cc/trees/damage_tracker_unittest.cc
+++ b/chromium/cc/trees/damage_tracker_unittest.cc
@@ -13,6 +13,7 @@
#include "cc/test/fake_impl_task_runner_provider.h"
#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/geometry_test_utils.h"
+#include "cc/test/layer_test_common.h"
#include "cc/test/test_task_graph_runner.h"
#include "cc/trees/layer_tree_host_common.h"
#include "cc/trees/layer_tree_impl.h"
@@ -27,22 +28,22 @@ namespace {
void ExecuteCalculateDrawProperties(LayerImpl* root,
float device_scale_factor,
- LayerImplList* render_surface_layer_list) {
+ RenderSurfaceList* render_surface_list) {
// Sanity check: The test itself should create the root layer's render
// surface, so that the surface (and its damage tracker) can
// persist across multiple calls to this function.
- ASSERT_FALSE(render_surface_layer_list->size());
+ ASSERT_FALSE(render_surface_list->size());
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root, root->bounds(), device_scale_factor, render_surface_layer_list);
+ root, root->bounds(), device_scale_factor, render_surface_list);
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
- ASSERT_TRUE(root->GetRenderSurface());
+ ASSERT_TRUE(GetRenderSurface(root));
}
void ClearDamageForAllSurfaces(LayerImpl* root) {
for (auto* layer : *root->layer_tree_impl()) {
- if (layer->GetRenderSurface())
- layer->GetRenderSurface()->damage_tracker()->DidDrawDamagedArea();
+ if (GetRenderSurface(layer))
+ GetRenderSurface(layer)->damage_tracker()->DidDrawDamagedArea();
}
}
@@ -53,23 +54,12 @@ void EmulateDrawingOneFrame(LayerImpl* root, float device_scale_factor = 1.f) {
// 3. resetting all update_rects and property_changed flags for all layers
// and surfaces.
- LayerImplList render_surface_layer_list;
+ RenderSurfaceList render_surface_list;
ExecuteCalculateDrawProperties(root, device_scale_factor,
- &render_surface_layer_list);
-
- // Iterate back-to-front, so that damage correctly propagates from descendant
- // surfaces to ancestors.
- size_t render_surface_layer_list_size = render_surface_layer_list.size();
- for (size_t i = 0; i < render_surface_layer_list_size; ++i) {
- size_t index = render_surface_layer_list_size - 1 - i;
- RenderSurfaceImpl* target_surface =
- render_surface_layer_list[index]->GetRenderSurface();
- target_surface->damage_tracker()->UpdateDamageTrackingState(
- target_surface->layer_list(), target_surface,
- target_surface->SurfacePropertyChangedOnlyFromDescendant(),
- target_surface->content_rect(), target_surface->MaskLayer(),
- target_surface->Filters());
- }
+ &render_surface_list);
+
+ DamageTracker::UpdateDamageTracking(root->layer_tree_impl(),
+ render_surface_list);
root->layer_tree_impl()->ResetAllChangeTracking();
}
@@ -185,16 +175,17 @@ class DamageTrackerTest : public testing::Test {
TEST_F(DamageTrackerTest, SanityCheckTestTreeWithOneSurface) {
// Sanity check that the simple test tree will actually produce the expected
- // render surfaces and layer lists.
+ // render surfaces.
LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface();
+ LayerImpl* child = root->test_properties()->children[0];
- EXPECT_EQ(2u, root->GetRenderSurface()->layer_list().size());
- EXPECT_EQ(1, root->GetRenderSurface()->layer_list()[0]->id());
- EXPECT_EQ(2, root->GetRenderSurface()->layer_list()[1]->id());
+ EXPECT_EQ(2, GetRenderSurface(root)->num_contributors());
+ EXPECT_TRUE(root->contributes_to_drawn_render_surface());
+ EXPECT_TRUE(child->contributes_to_drawn_render_surface());
gfx::Rect root_damage_rect;
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_EQ(gfx::Rect(500, 500).ToString(), root_damage_rect.ToString());
@@ -202,7 +193,7 @@ TEST_F(DamageTrackerTest, SanityCheckTestTreeWithOneSurface) {
TEST_F(DamageTrackerTest, SanityCheckTestTreeWithTwoSurfaces) {
// Sanity check that the complex test tree will actually produce the expected
- // render surfaces and layer lists.
+ // render surfaces.
LayerImpl* root = CreateAndSetUpTestTreeWithTwoSurfaces();
@@ -210,17 +201,16 @@ TEST_F(DamageTrackerTest, SanityCheckTestTreeWithTwoSurfaces) {
LayerImpl* child2 = root->test_properties()->children[1];
gfx::Rect child_damage_rect;
- EXPECT_TRUE(
- child1->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
- &child_damage_rect));
+ EXPECT_TRUE(GetRenderSurface(child1)->damage_tracker()->GetDamageRectIfValid(
+ &child_damage_rect));
gfx::Rect root_damage_rect;
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
- ASSERT_TRUE(child1->GetRenderSurface());
- EXPECT_FALSE(child2->GetRenderSurface());
- EXPECT_EQ(3u, root->GetRenderSurface()->layer_list().size());
- EXPECT_EQ(2u, child1->GetRenderSurface()->layer_list().size());
+ EXPECT_NE(GetRenderSurface(child1), GetRenderSurface(root));
+ EXPECT_EQ(GetRenderSurface(child2), GetRenderSurface(root));
+ EXPECT_EQ(3, GetRenderSurface(root)->num_contributors());
+ EXPECT_EQ(2, GetRenderSurface(child1)->num_contributors());
// The render surface for child1 only has a content_rect that encloses
// grand_child1 and grand_child2, because child1 does not draw content.
@@ -243,7 +233,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForUpdateRects) {
// Damage position on the surface should be: position of update_rect (10, 11)
// relative to the child (100, 100).
gfx::Rect root_damage_rect;
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_EQ(gfx::Rect(110, 111, 12, 13).ToString(),
root_damage_rect.ToString());
@@ -254,7 +244,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForUpdateRects) {
child->SetUpdateRect(gfx::Rect(10, 11, 12, 13));
root->layer_tree_impl()->property_trees()->needs_rebuild = true;
EmulateDrawingOneFrame(root);
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_EQ(gfx::Rect(110, 111, 12, 13).ToString(),
root_damage_rect.ToString());
@@ -268,7 +258,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForUpdateRects) {
// Damage position on the surface should be: position of update_rect (20, 25)
// relative to the child (100, 100).
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_EQ(gfx::Rect(120, 125, 1, 2).ToString(), root_damage_rect.ToString());
}
@@ -287,7 +277,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForLayerDamageRects) {
// Damage position on the surface should be: position of layer damage_rect
// (10, 11) relative to the child (100, 100).
gfx::Rect root_damage_rect;
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_EQ(true, root_damage_rect.Contains(gfx::Rect(110, 111, 12, 13)));
@@ -297,7 +287,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForLayerDamageRects) {
child->AddDamageRect(gfx::Rect(10, 11, 12, 13));
root->layer_tree_impl()->property_trees()->needs_rebuild = true;
EmulateDrawingOneFrame(root);
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_EQ(true, root_damage_rect.Contains(gfx::Rect(110, 111, 12, 13)));
@@ -310,7 +300,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForLayerDamageRects) {
// Damage position on the surface should be: position of layer damage_rect
// (20, 25) relative to the child (100, 100).
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_EQ(true, root_damage_rect.Contains(gfx::Rect(120, 125, 1, 2)));
@@ -324,7 +314,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForLayerDamageRects) {
// Damage position on the surface should be: position of layer damage_rect
// (20, 25) relative to the child (100, 100).
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_EQ(true, root_damage_rect.Contains(gfx::Rect(120, 125, 1, 2)));
EXPECT_EQ(true, root_damage_rect.Contains(gfx::Rect(110, 115, 3, 4)));
@@ -346,7 +336,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForLayerUpdateAndDamageRects) {
// damage_rect and update rect (5, 6)
// relative to the child (100, 100).
gfx::Rect root_damage_rect;
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_EQ(true, root_damage_rect.Contains(gfx::Rect(105, 106, 24, 20)));
@@ -357,7 +347,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForLayerUpdateAndDamageRects) {
child->SetUpdateRect(gfx::Rect(10, 11, 14, 15));
root->layer_tree_impl()->property_trees()->needs_rebuild = true;
EmulateDrawingOneFrame(root);
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_EQ(true, root_damage_rect.Contains(gfx::Rect(110, 111, 14, 15)));
@@ -371,7 +361,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForLayerUpdateAndDamageRects) {
// Damage position on the surface should be: position of unified layer damage
// rect and update rect (5, 10) relative to the child (100, 100).
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_EQ(true, root_damage_rect.Contains(gfx::Rect(105, 110, 17, 18)));
}
@@ -390,12 +380,12 @@ TEST_F(DamageTrackerTest, VerifyDamageForPropertyChanges) {
root->layer_tree_impl()->SetOpacityMutated(child->element_id(), 0.5f);
EmulateDrawingOneFrame(root);
- ASSERT_EQ(2u, root->GetRenderSurface()->layer_list().size());
+ ASSERT_EQ(2, GetRenderSurface(root)->num_contributors());
// Damage should be the entire child layer in target_surface space.
gfx::Rect expected_rect = gfx::Rect(100, 100, 30, 30);
gfx::Rect root_damage_rect;
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_EQ(expected_rect.ToString(), root_damage_rect.ToString());
@@ -408,7 +398,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForPropertyChanges) {
ClearDamageForAllSurfaces(root);
root->layer_tree_impl()->property_trees()->needs_rebuild = true;
EmulateDrawingOneFrame(root);
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_TRUE(root_damage_rect.IsEmpty());
@@ -422,7 +412,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForPropertyChanges) {
// Expect damage to be the combination of the previous one and the new one.
expected_rect.Union(gfx::Rect(200, 230, 30, 30));
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_FLOAT_RECT_EQ(expected_rect, root_damage_rect);
}
@@ -440,7 +430,7 @@ TEST_F(DamageTrackerTest, VerifyDamageWhenSurfaceRemoved) {
root->layer_tree_impl()->property_trees()->needs_rebuild = true;
EmulateDrawingOneFrame(root);
gfx::Rect root_damage_rect;
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_EQ(gfx::Rect(290, 290, 16, 18).ToString(),
root_damage_rect.ToString());
@@ -468,7 +458,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForTransformedLayer) {
// Sanity check that the layer actually moved to (85, 85), damaging its old
// location and new location.
gfx::Rect root_damage_rect;
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_EQ(gfx::Rect(85, 85, 45, 45).ToString(), root_damage_rect.ToString());
@@ -486,7 +476,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForTransformedLayer) {
float expected_position = 100.f - 0.5f * expected_width;
gfx::Rect expected_rect = gfx::ToEnclosingRect(gfx::RectF(
expected_position, expected_position, expected_width, expected_width));
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_EQ(expected_rect.ToString(), root_damage_rect.ToString());
}
@@ -539,7 +529,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForPerspectiveClippedLayer) {
// don't care whether the damage rect was clamped or is larger than the
// surface for this test.
gfx::Rect root_damage_rect;
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
gfx::Rect damage_we_care_about = gfx::Rect(gfx::Size(500, 500));
EXPECT_TRUE(root_damage_rect.Contains(damage_we_care_about));
@@ -570,7 +560,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForBlurredSurface) {
// relative to the child (300, 300), but expanded by the blur outsets
// (15, since the blur radius is 5).
gfx::Rect root_damage_rect;
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_EQ(gfx::Rect(286, 287, 33, 34), root_damage_rect);
}
@@ -594,9 +584,9 @@ TEST_F(DamageTrackerTest, VerifyDamageForImageFilter) {
EmulateDrawingOneFrame(root);
child->layer_tree_impl()->SetFilterMutated(child->element_id(), filters);
EmulateDrawingOneFrame(root);
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
- EXPECT_TRUE(child->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(child)->damage_tracker()->GetDamageRectIfValid(
&child_damage_rect));
// gfx::Rect(100, 100, 30, 30), expanded by 6px for the 2px blur filter.
@@ -610,9 +600,9 @@ TEST_F(DamageTrackerTest, VerifyDamageForImageFilter) {
child->SetUpdateRect(gfx::Rect(1, 1));
EmulateDrawingOneFrame(root);
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
- EXPECT_TRUE(child->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(child)->damage_tracker()->GetDamageRectIfValid(
&child_damage_rect));
// gfx::Rect(100, 100, 1, 1), expanded by 6px for the 2px blur filter.
@@ -644,9 +634,9 @@ TEST_F(DamageTrackerTest, VerifyDamageForTransformedImageFilter) {
EmulateDrawingOneFrame(root);
child->layer_tree_impl()->SetFilterMutated(child->element_id(), filters);
EmulateDrawingOneFrame(root);
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
- EXPECT_TRUE(child->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(child)->damage_tracker()->GetDamageRectIfValid(
&child_damage_rect));
// Blur outset is 6px for a 2px blur.
@@ -666,9 +656,9 @@ TEST_F(DamageTrackerTest, VerifyDamageForTransformedImageFilter) {
child->SetUpdateRect(gfx::Rect(30, 30));
EmulateDrawingOneFrame(root);
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
- EXPECT_TRUE(child->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(child)->damage_tracker()->GetDamageRectIfValid(
&child_damage_rect));
int expect_width = 30 + 2 * blur_outset;
@@ -699,9 +689,9 @@ TEST_F(DamageTrackerTest, VerifyDamageForHighDPIImageFilter) {
EmulateDrawingOneFrame(root, device_scale_factor);
child->layer_tree_impl()->SetFilterMutated(child->element_id(), filters);
EmulateDrawingOneFrame(root, device_scale_factor);
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
- EXPECT_TRUE(child->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(child)->damage_tracker()->GetDamageRectIfValid(
&child_damage_rect));
// Blur outset is 9px for a 3px blur, scaled up by DSF.
@@ -722,9 +712,9 @@ TEST_F(DamageTrackerTest, VerifyDamageForHighDPIImageFilter) {
child->SetUpdateRect(gfx::Rect(30, 30));
EmulateDrawingOneFrame(root, device_scale_factor);
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
- EXPECT_TRUE(child->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(child)->damage_tracker()->GetDamageRectIfValid(
&child_damage_rect));
EXPECT_EQ(expected_root_damage_rect, root_damage_rect);
@@ -759,7 +749,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForBackgroundBlurredChild) {
EmulateDrawingOneFrame(root);
gfx::Rect root_damage_rect;
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
// Damage position on the surface should be a composition of the damage on
// the root and on child2. Damage on the root should be: position of
@@ -779,7 +769,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForBackgroundBlurredChild) {
root->layer_tree_impl()->property_trees()->needs_rebuild = true;
EmulateDrawingOneFrame(root);
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
// Damage position on the surface should be a composition of the damage on
// the root and on child2. Damage on the root should be: position of
@@ -797,7 +787,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForBackgroundBlurredChild) {
root->layer_tree_impl()->property_trees()->needs_rebuild = true;
EmulateDrawingOneFrame(root);
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
// Damage on the root should be: position of update_rect (30, 30), not
// expanded.
@@ -813,7 +803,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForBackgroundBlurredChild) {
root->layer_tree_impl()->property_trees()->needs_rebuild = true;
EmulateDrawingOneFrame(root);
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
// Damage on the root should be: the originally damaged rect (99,99 1x1)
// plus the rect that can influence with a 2px blur (93,93 13x13) intersected
@@ -830,7 +820,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForBackgroundBlurredChild) {
root->layer_tree_impl()->property_trees()->needs_rebuild = true;
EmulateDrawingOneFrame(root);
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
// Damage on child2 should be: position of update_rect offset by the child's
// position (11, 11), and not expanded by anything.
@@ -846,7 +836,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForBackgroundBlurredChild) {
root->layer_tree_impl()->property_trees()->needs_rebuild = true;
EmulateDrawingOneFrame(root);
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
// Damage on child1 should be: position of update_rect offset by the child's
// position (100, 100), and expanded by the damage.
@@ -879,10 +869,10 @@ TEST_F(DamageTrackerTest, VerifyDamageForAddingAndRemovingLayer) {
// Sanity check - all 3 layers should be on the same render surface; render
// surfaces are tested elsewhere.
- ASSERT_EQ(3u, root->GetRenderSurface()->layer_list().size());
+ ASSERT_EQ(3, GetRenderSurface(root)->num_contributors());
gfx::Rect root_damage_rect;
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_EQ(gfx::Rect(400, 380, 6, 8).ToString(), root_damage_rect.ToString());
@@ -895,7 +885,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForAddingAndRemovingLayer) {
root->layer_tree_impl()->property_trees()->needs_rebuild = true;
EmulateDrawingOneFrame(root);
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_TRUE(root_damage_rect.IsEmpty());
@@ -905,7 +895,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForAddingAndRemovingLayer) {
root->layer_tree_impl()->property_trees()->needs_rebuild = true;
EmulateDrawingOneFrame(root);
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_EQ(gfx::Rect(100, 100, 30, 30).ToString(),
root_damage_rect.ToString());
@@ -939,10 +929,10 @@ TEST_F(DamageTrackerTest, VerifyDamageForNewUnchangedLayer) {
// Sanity check - all 3 layers should be on the same render surface; render
// surfaces are tested elsewhere.
- ASSERT_EQ(3u, root->GetRenderSurface()->layer_list().size());
+ ASSERT_EQ(3, GetRenderSurface(root)->num_contributors());
gfx::Rect root_damage_rect;
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_EQ(gfx::Rect(400, 380, 6, 8).ToString(), root_damage_rect.ToString());
}
@@ -975,7 +965,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForMultipleLayers) {
root->layer_tree_impl()->property_trees()->needs_rebuild = true;
EmulateDrawingOneFrame(root);
gfx::Rect root_damage_rect;
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_EQ(gfx::Rect(100, 100, 303, 284).ToString(),
root_damage_rect.ToString());
@@ -999,10 +989,9 @@ TEST_F(DamageTrackerTest, VerifyDamageForNestedSurfaces) {
ClearDamageForAllSurfaces(root);
root->layer_tree_impl()->SetOpacityMutated(grand_child1->element_id(), 0.5f);
EmulateDrawingOneFrame(root);
- EXPECT_TRUE(
- child1->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
- &child_damage_rect));
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(child1)->damage_tracker()->GetDamageRectIfValid(
+ &child_damage_rect));
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_EQ(gfx::Rect(200, 200, 6, 8).ToString(), child_damage_rect.ToString());
EXPECT_EQ(gfx::Rect(300, 300, 6, 8).ToString(), root_damage_rect.ToString());
@@ -1017,10 +1006,9 @@ TEST_F(DamageTrackerTest, VerifyDamageForNestedSurfaces) {
root->layer_tree_impl()->SetOpacityMutated(grand_child1->element_id(), 0.7f);
root->layer_tree_impl()->SetOpacityMutated(child2->element_id(), 0.7f);
EmulateDrawingOneFrame(root);
- EXPECT_TRUE(
- child1->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
- &child_damage_rect));
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(child1)->damage_tracker()->GetDamageRectIfValid(
+ &child_damage_rect));
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_EQ(gfx::Rect(200, 200, 6, 8).ToString(), child_damage_rect.ToString());
EXPECT_EQ(gfx::Rect(11, 11, 295, 297).ToString(),
@@ -1046,10 +1034,9 @@ TEST_F(DamageTrackerTest, VerifyDamageForSurfaceChangeFromDescendantLayer) {
grand_child1->SetPosition(gfx::PointF(195.f, 205.f));
root->layer_tree_impl()->property_trees()->needs_rebuild = true;
EmulateDrawingOneFrame(root);
- EXPECT_TRUE(
- child1->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
- &child_damage_rect));
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(child1)->damage_tracker()->GetDamageRectIfValid(
+ &child_damage_rect));
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
// The new surface bounds should be damaged entirely, even though only one of
@@ -1087,10 +1074,9 @@ TEST_F(DamageTrackerTest, VerifyDamageForSurfaceChangeFromAncestorLayer) {
root->layer_tree_impl()->SetTransformMutated(child1->element_id(),
translation);
EmulateDrawingOneFrame(root);
- EXPECT_TRUE(
- child1->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
- &child_damage_rect));
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(child1)->damage_tracker()->GetDamageRectIfValid(
+ &child_damage_rect));
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
// The new surface bounds should be damaged entirely.
@@ -1119,10 +1105,10 @@ TEST_F(DamageTrackerTest, VerifyDamageForAddingAndRemovingRenderSurfaces) {
EmulateDrawingOneFrame(root);
// Sanity check that there is only one surface now.
- ASSERT_FALSE(child1->GetRenderSurface());
- ASSERT_EQ(4u, root->GetRenderSurface()->layer_list().size());
+ ASSERT_EQ(GetRenderSurface(child1), GetRenderSurface(root));
+ ASSERT_EQ(4, GetRenderSurface(root)->num_contributors());
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_EQ(gfx::Rect(290, 290, 16, 18).ToString(),
root_damage_rect.ToString());
@@ -1135,7 +1121,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForAddingAndRemovingRenderSurfaces) {
ClearDamageForAllSurfaces(root);
root->layer_tree_impl()->property_trees()->needs_rebuild = true;
EmulateDrawingOneFrame(root);
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_TRUE(root_damage_rect.IsEmpty());
@@ -1147,14 +1133,13 @@ TEST_F(DamageTrackerTest, VerifyDamageForAddingAndRemovingRenderSurfaces) {
EmulateDrawingOneFrame(root);
// Sanity check that there is a new surface now.
- ASSERT_TRUE(child1->GetRenderSurface());
- EXPECT_EQ(3u, root->GetRenderSurface()->layer_list().size());
- EXPECT_EQ(2u, child1->GetRenderSurface()->layer_list().size());
+ ASSERT_TRUE(GetRenderSurface(child1));
+ EXPECT_EQ(3, GetRenderSurface(root)->num_contributors());
+ EXPECT_EQ(2, GetRenderSurface(child1)->num_contributors());
- EXPECT_TRUE(
- child1->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
- &child_damage_rect));
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(child1)->damage_tracker()->GetDamageRectIfValid(
+ &child_damage_rect));
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_EQ(gfx::Rect(190, 190, 16, 18).ToString(),
child_damage_rect.ToString());
@@ -1173,10 +1158,9 @@ TEST_F(DamageTrackerTest, VerifyNoDamageWhenNothingChanged) {
ClearDamageForAllSurfaces(root);
root->layer_tree_impl()->property_trees()->needs_rebuild = true;
EmulateDrawingOneFrame(root);
- EXPECT_TRUE(
- child1->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
- &child_damage_rect));
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(child1)->damage_tracker()->GetDamageRectIfValid(
+ &child_damage_rect));
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_TRUE(child_damage_rect.IsEmpty());
EXPECT_TRUE(root_damage_rect.IsEmpty());
@@ -1187,10 +1171,9 @@ TEST_F(DamageTrackerTest, VerifyNoDamageWhenNothingChanged) {
ClearDamageForAllSurfaces(root);
root->layer_tree_impl()->property_trees()->needs_rebuild = true;
EmulateDrawingOneFrame(root);
- EXPECT_TRUE(
- child1->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
- &child_damage_rect));
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(child1)->damage_tracker()->GetDamageRectIfValid(
+ &child_damage_rect));
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_TRUE(child_damage_rect.IsEmpty());
EXPECT_TRUE(root_damage_rect.IsEmpty());
@@ -1208,10 +1191,9 @@ TEST_F(DamageTrackerTest, VerifyNoDamageForUpdateRectThatDoesNotDrawContent) {
child1->SetUpdateRect(gfx::Rect(1, 2));
root->layer_tree_impl()->property_trees()->needs_rebuild = true;
EmulateDrawingOneFrame(root);
- EXPECT_TRUE(
- child1->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
- &child_damage_rect));
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(child1)->damage_tracker()->GetDamageRectIfValid(
+ &child_damage_rect));
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_TRUE(child_damage_rect.IsEmpty());
EXPECT_TRUE(root_damage_rect.IsEmpty());
@@ -1257,7 +1239,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForMask) {
root->layer_tree_impl()->property_trees()->needs_rebuild = true;
EmulateDrawingOneFrame(root);
gfx::Rect child_damage_rect;
- EXPECT_TRUE(child->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(child)->damage_tracker()->GetDamageRectIfValid(
&child_damage_rect));
EXPECT_EQ(gfx::Rect(30, 30).ToString(), child_damage_rect.ToString());
@@ -1269,7 +1251,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForMask) {
ClearDamageForAllSurfaces(root);
root->layer_tree_impl()->property_trees()->needs_rebuild = true;
EmulateDrawingOneFrame(root);
- EXPECT_TRUE(child->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(child)->damage_tracker()->GetDamageRectIfValid(
&child_damage_rect));
EXPECT_TRUE(child_damage_rect.IsEmpty());
@@ -1279,7 +1261,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForMask) {
root->layer_tree_impl()->property_trees()->needs_rebuild = true;
EmulateDrawingOneFrame(root);
- EXPECT_TRUE(child->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(child)->damage_tracker()->GetDamageRectIfValid(
&child_damage_rect));
EXPECT_EQ(gfx::Rect(30, 30).ToString(), child_damage_rect.ToString());
@@ -1291,7 +1273,7 @@ TEST_F(DamageTrackerTest, VerifyDamageForMask) {
ClearDamageForAllSurfaces(root);
root->layer_tree_impl()->property_trees()->needs_rebuild = true;
EmulateDrawingOneFrame(root);
- EXPECT_TRUE(child->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(child)->damage_tracker()->GetDamageRectIfValid(
&child_damage_rect));
EXPECT_TRUE(child_damage_rect.IsEmpty());
@@ -1304,9 +1286,9 @@ TEST_F(DamageTrackerTest, VerifyDamageForMask) {
EmulateDrawingOneFrame(root);
// Sanity check that a render surface still exists.
- ASSERT_TRUE(child->GetRenderSurface());
+ ASSERT_TRUE(GetRenderSurface(child));
- EXPECT_TRUE(child->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(child)->damage_tracker()->GetDamageRectIfValid(
&child_damage_rect));
EXPECT_EQ(gfx::Rect(30, 30).ToString(), child_damage_rect.ToString());
}
@@ -1320,12 +1302,12 @@ TEST_F(DamageTrackerTest, DamageWhenAddedExternally) {
//
ClearDamageForAllSurfaces(root);
child->SetUpdateRect(gfx::Rect(10, 11, 12, 13));
- root->GetRenderSurface()->damage_tracker()->AddDamageNextUpdate(
+ GetRenderSurface(root)->damage_tracker()->AddDamageNextUpdate(
gfx::Rect(15, 16, 32, 33));
root->layer_tree_impl()->property_trees()->needs_rebuild = true;
EmulateDrawingOneFrame(root);
gfx::Rect root_damage_rect;
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_EQ(gfx::UnionRects(gfx::Rect(15, 16, 32, 33),
gfx::Rect(100 + 10, 100 + 11, 12, 13)).ToString(),
@@ -1335,19 +1317,16 @@ TEST_F(DamageTrackerTest, DamageWhenAddedExternally) {
// nothing on the layer tree changed.
//
ClearDamageForAllSurfaces(root);
- root->GetRenderSurface()->damage_tracker()->AddDamageNextUpdate(
+ GetRenderSurface(root)->damage_tracker()->AddDamageNextUpdate(
gfx::Rect(30, 31, 14, 15));
root->layer_tree_impl()->property_trees()->needs_rebuild = true;
EmulateDrawingOneFrame(root);
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_EQ(gfx::Rect(30, 31, 14, 15).ToString(), root_damage_rect.ToString());
}
-TEST_F(DamageTrackerTest, VerifyDamageForEmptyLayerList) {
- // Though it should never happen, its a good idea to verify that the damage
- // tracker does not crash when it receives an empty layer_list.
-
+TEST_F(DamageTrackerTest, VerifyDamageWithNoContributingLayers) {
std::unique_ptr<LayerImpl> root =
LayerImpl::Create(host_impl_.active_tree(), 1);
root->test_properties()->force_render_surface = true;
@@ -1356,13 +1335,8 @@ TEST_F(DamageTrackerTest, VerifyDamageForEmptyLayerList) {
root_ptr->layer_tree_impl()->property_trees()->needs_rebuild = true;
EmulateDrawingOneFrame(root_ptr);
- DCHECK_EQ(root_ptr->GetRenderSurface(), root_ptr->render_target());
- RenderSurfaceImpl* target_surface = root_ptr->GetRenderSurface();
-
- LayerImplList empty_list;
- target_surface->damage_tracker()->UpdateDamageTrackingState(
- empty_list, target_surface, false, gfx::Rect(), NULL, FilterOperations());
-
+ DCHECK_EQ(GetRenderSurface(root_ptr), root_ptr->render_target());
+ RenderSurfaceImpl* target_surface = GetRenderSurface(root_ptr);
gfx::Rect damage_rect;
EXPECT_TRUE(
target_surface->damage_tracker()->GetDamageRectIfValid(&damage_rect));
@@ -1382,7 +1356,7 @@ TEST_F(DamageTrackerTest, VerifyDamageAccumulatesUntilReset) {
// Sanity check damage after the first frame; this isnt the actual test yet.
gfx::Rect root_damage_rect;
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_EQ(gfx::Rect(110, 111, 1, 2).ToString(), root_damage_rect.ToString());
@@ -1391,15 +1365,15 @@ TEST_F(DamageTrackerTest, VerifyDamageAccumulatesUntilReset) {
child->SetUpdateRect(gfx::Rect(20, 25, 1, 2));
root->layer_tree_impl()->property_trees()->needs_rebuild = true;
EmulateDrawingOneFrame(root);
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_EQ(gfx::Rect(110, 111, 11, 16).ToString(),
root_damage_rect.ToString());
// If we notify the damage tracker that we drew the damaged area, then damage
// should be emptied.
- root->GetRenderSurface()->damage_tracker()->DidDrawDamagedArea();
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ GetRenderSurface(root)->damage_tracker()->DidDrawDamagedArea();
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_TRUE(root_damage_rect.IsEmpty());
@@ -1407,7 +1381,7 @@ TEST_F(DamageTrackerTest, VerifyDamageAccumulatesUntilReset) {
// damage.
root->layer_tree_impl()->property_trees()->needs_rebuild = true;
EmulateDrawingOneFrame(root);
- EXPECT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&root_damage_rect));
EXPECT_TRUE(root_damage_rect.IsEmpty());
}
@@ -1441,9 +1415,8 @@ TEST_F(DamageTrackerTest, HugeDamageRect) {
// The expected damage should cover the visible part of the child layer,
// which is (0, 0, i, i) in the viewport.
gfx::Rect root_damage_rect;
- EXPECT_TRUE(
- root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
- &root_damage_rect));
+ EXPECT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
+ &root_damage_rect));
gfx::Rect damage_we_care_about = gfx::Rect(i, i);
EXPECT_LE(damage_we_care_about.right(), root_damage_rect.right());
EXPECT_LE(damage_we_care_about.bottom(), root_damage_rect.bottom());
@@ -1470,10 +1443,10 @@ TEST_F(DamageTrackerTest, DamageRectTooBig) {
// The expected damage would be too large to store in a gfx::Rect, so we
// should damage everything (ie, we don't have a valid rect).
gfx::Rect damage_rect;
- EXPECT_FALSE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_FALSE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&damage_rect));
- EXPECT_EQ(root->GetRenderSurface()->content_rect(),
- root->GetRenderSurface()->GetDamageRect());
+ EXPECT_EQ(GetRenderSurface(root)->content_rect(),
+ GetRenderSurface(root)->GetDamageRect());
}
TEST_F(DamageTrackerTest, DamageRectTooBigWithFilter) {
@@ -1501,10 +1474,10 @@ TEST_F(DamageTrackerTest, DamageRectTooBigWithFilter) {
// The expected damage would be too large to store in a gfx::Rect, so we
// should damage everything (ie, we don't have a valid rect).
gfx::Rect damage_rect;
- EXPECT_FALSE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ EXPECT_FALSE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&damage_rect));
- EXPECT_EQ(root->GetRenderSurface()->content_rect(),
- root->GetRenderSurface()->GetDamageRect());
+ EXPECT_EQ(GetRenderSurface(root)->content_rect(),
+ GetRenderSurface(root)->GetDamageRect());
}
TEST_F(DamageTrackerTest, DamageRectTooBigInRenderSurface) {
@@ -1527,36 +1500,31 @@ TEST_F(DamageTrackerTest, DamageRectTooBigInRenderSurface) {
root->layer_tree_impl()->property_trees()->needs_rebuild = true;
float device_scale_factor = 1.f;
- LayerImplList render_surface_layer_list;
+ RenderSurfaceList render_surface_list;
ExecuteCalculateDrawProperties(root, device_scale_factor,
- &render_surface_layer_list);
-
- auto* surface = child1->GetRenderSurface();
- surface->damage_tracker()->UpdateDamageTrackingState(
- surface->layer_list(), surface, false, surface->content_rect(),
- surface->MaskLayer(), surface->Filters());
- surface = root->GetRenderSurface();
- surface->damage_tracker()->UpdateDamageTrackingState(
- surface->layer_list(), surface, false, surface->content_rect(),
- surface->MaskLayer(), surface->Filters());
+ &render_surface_list);
+ // Avoid the descendant-only property change path that skips unioning damage
+ // from descendant layers.
+ GetRenderSurface(child1)->NoteAncestorPropertyChanged();
+ DamageTracker::UpdateDamageTracking(host_impl_.active_tree(),
+ render_surface_list);
// The expected damage would be too large to store in a gfx::Rect, so we
// should damage everything on child1.
gfx::Rect damage_rect;
- EXPECT_FALSE(
- child1->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
- &damage_rect));
- EXPECT_EQ(child1->GetRenderSurface()->content_rect(),
- child1->GetRenderSurface()->GetDamageRect());
+ EXPECT_FALSE(GetRenderSurface(child1)->damage_tracker()->GetDamageRectIfValid(
+ &damage_rect));
+ EXPECT_EQ(GetRenderSurface(child1)->content_rect(),
+ GetRenderSurface(child1)->GetDamageRect());
// However, the root should just use the child1 render surface's content rect
// as damage.
- ASSERT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ ASSERT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&damage_rect));
- EXPECT_TRUE(damage_rect.Contains(root->GetRenderSurface()->content_rect()));
+ EXPECT_TRUE(damage_rect.Contains(GetRenderSurface(root)->content_rect()));
EXPECT_TRUE(damage_rect.Contains(
- gfx::ToEnclosingRect(child1->GetRenderSurface()->DrawableContentRect())));
- EXPECT_EQ(damage_rect, root->GetRenderSurface()->GetDamageRect());
+ gfx::ToEnclosingRect(GetRenderSurface(child1)->DrawableContentRect())));
+ EXPECT_EQ(damage_rect, GetRenderSurface(root)->GetDamageRect());
// Add new damage, without changing properties, which goes down a different
// path in the damage tracker.
@@ -1565,34 +1533,27 @@ TEST_F(DamageTrackerTest, DamageRectTooBigInRenderSurface) {
grandchild2->AddDamageRect(gfx::Rect(grandchild1->bounds()));
// Recompute all damage / properties.
- render_surface_layer_list.clear();
+ render_surface_list.clear();
ExecuteCalculateDrawProperties(root, device_scale_factor,
- &render_surface_layer_list);
- surface = child1->GetRenderSurface();
- surface->damage_tracker()->UpdateDamageTrackingState(
- surface->layer_list(), surface, false, surface->content_rect(),
- surface->MaskLayer(), surface->Filters());
- surface = root->GetRenderSurface();
- surface->damage_tracker()->UpdateDamageTrackingState(
- surface->layer_list(), surface, false, surface->content_rect(),
- surface->MaskLayer(), surface->Filters());
+ &render_surface_list);
+ DamageTracker::UpdateDamageTracking(host_impl_.active_tree(),
+ render_surface_list);
// Child1 should still not have a valid rect, since the union of the damage of
// its children is not representable by a single rect.
- EXPECT_FALSE(
- child1->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
- &damage_rect));
- EXPECT_EQ(child1->GetRenderSurface()->content_rect(),
- child1->GetRenderSurface()->GetDamageRect());
+ EXPECT_FALSE(GetRenderSurface(child1)->damage_tracker()->GetDamageRectIfValid(
+ &damage_rect));
+ EXPECT_EQ(GetRenderSurface(child1)->content_rect(),
+ GetRenderSurface(child1)->GetDamageRect());
// Root should have valid damage and contain both its content rect and the
// drawable content rect of child1.
- ASSERT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ ASSERT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&damage_rect));
- EXPECT_TRUE(damage_rect.Contains(root->GetRenderSurface()->content_rect()));
+ EXPECT_TRUE(damage_rect.Contains(GetRenderSurface(root)->content_rect()));
EXPECT_TRUE(damage_rect.Contains(
- gfx::ToEnclosingRect(child1->GetRenderSurface()->DrawableContentRect())));
- EXPECT_EQ(damage_rect, root->GetRenderSurface()->GetDamageRect());
+ gfx::ToEnclosingRect(GetRenderSurface(child1)->DrawableContentRect())));
+ EXPECT_EQ(damage_rect, GetRenderSurface(root)->GetDamageRect());
}
TEST_F(DamageTrackerTest, DamageRectTooBigInRenderSurfaceWithFilter) {
@@ -1621,36 +1582,31 @@ TEST_F(DamageTrackerTest, DamageRectTooBigInRenderSurfaceWithFilter) {
root->layer_tree_impl()->property_trees()->needs_rebuild = true;
float device_scale_factor = 1.f;
- LayerImplList render_surface_layer_list;
+ RenderSurfaceList render_surface_list;
ExecuteCalculateDrawProperties(root, device_scale_factor,
- &render_surface_layer_list);
-
- auto* surface = child1->GetRenderSurface();
- surface->damage_tracker()->UpdateDamageTrackingState(
- surface->layer_list(), surface, false, surface->content_rect(),
- surface->MaskLayer(), surface->Filters());
- surface = root->GetRenderSurface();
- surface->damage_tracker()->UpdateDamageTrackingState(
- surface->layer_list(), surface, false, surface->content_rect(),
- surface->MaskLayer(), surface->Filters());
+ &render_surface_list);
+ // Avoid the descendant-only property change path that skips unioning damage
+ // from descendant layers.
+ GetRenderSurface(child1)->NoteAncestorPropertyChanged();
+ DamageTracker::UpdateDamageTracking(host_impl_.active_tree(),
+ render_surface_list);
// The expected damage would be too large to store in a gfx::Rect, so we
// should damage everything on child1.
gfx::Rect damage_rect;
- EXPECT_FALSE(
- child1->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
- &damage_rect));
- EXPECT_EQ(child1->GetRenderSurface()->content_rect(),
- child1->GetRenderSurface()->GetDamageRect());
+ EXPECT_FALSE(GetRenderSurface(child1)->damage_tracker()->GetDamageRectIfValid(
+ &damage_rect));
+ EXPECT_EQ(GetRenderSurface(child1)->content_rect(),
+ GetRenderSurface(child1)->GetDamageRect());
// However, the root should just use the child1 render surface's content rect
// as damage.
- ASSERT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ ASSERT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&damage_rect));
- EXPECT_TRUE(damage_rect.Contains(root->GetRenderSurface()->content_rect()));
+ EXPECT_TRUE(damage_rect.Contains(GetRenderSurface(root)->content_rect()));
EXPECT_TRUE(damage_rect.Contains(
- gfx::ToEnclosingRect(child1->GetRenderSurface()->DrawableContentRect())));
- EXPECT_EQ(damage_rect, root->GetRenderSurface()->GetDamageRect());
+ gfx::ToEnclosingRect(GetRenderSurface(child1)->DrawableContentRect())));
+ EXPECT_EQ(damage_rect, GetRenderSurface(root)->GetDamageRect());
// Add new damage, without changing properties, which goes down a different
// path in the damage tracker.
@@ -1659,34 +1615,27 @@ TEST_F(DamageTrackerTest, DamageRectTooBigInRenderSurfaceWithFilter) {
grandchild2->AddDamageRect(gfx::Rect(grandchild1->bounds()));
// Recompute all damage / properties.
- render_surface_layer_list.clear();
+ render_surface_list.clear();
ExecuteCalculateDrawProperties(root, device_scale_factor,
- &render_surface_layer_list);
- surface = child1->GetRenderSurface();
- surface->damage_tracker()->UpdateDamageTrackingState(
- surface->layer_list(), surface, false, surface->content_rect(),
- surface->MaskLayer(), surface->Filters());
- surface = root->GetRenderSurface();
- surface->damage_tracker()->UpdateDamageTrackingState(
- surface->layer_list(), surface, false, surface->content_rect(),
- surface->MaskLayer(), surface->Filters());
+ &render_surface_list);
+ DamageTracker::UpdateDamageTracking(host_impl_.active_tree(),
+ render_surface_list);
// Child1 should still not have a valid rect, since the union of the damage of
// its children is not representable by a single rect.
- EXPECT_FALSE(
- child1->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
- &damage_rect));
- EXPECT_EQ(child1->GetRenderSurface()->content_rect(),
- child1->GetRenderSurface()->GetDamageRect());
+ EXPECT_FALSE(GetRenderSurface(child1)->damage_tracker()->GetDamageRectIfValid(
+ &damage_rect));
+ EXPECT_EQ(GetRenderSurface(child1)->content_rect(),
+ GetRenderSurface(child1)->GetDamageRect());
// Root should have valid damage and contain both its content rect and the
// drawable content rect of child1.
- ASSERT_TRUE(root->GetRenderSurface()->damage_tracker()->GetDamageRectIfValid(
+ ASSERT_TRUE(GetRenderSurface(root)->damage_tracker()->GetDamageRectIfValid(
&damage_rect));
- EXPECT_TRUE(damage_rect.Contains(root->GetRenderSurface()->content_rect()));
+ EXPECT_TRUE(damage_rect.Contains(GetRenderSurface(root)->content_rect()));
EXPECT_TRUE(damage_rect.Contains(
- gfx::ToEnclosingRect(child1->GetRenderSurface()->DrawableContentRect())));
- EXPECT_EQ(damage_rect, root->GetRenderSurface()->GetDamageRect());
+ gfx::ToEnclosingRect(GetRenderSurface(child1)->DrawableContentRect())));
+ EXPECT_EQ(damage_rect, GetRenderSurface(root)->GetDamageRect());
}
} // namespace
diff --git a/chromium/cc/trees/debug_rect_history.cc b/chromium/cc/trees/debug_rect_history.cc
index 243c610214c..35c8db1073d 100644
--- a/chromium/cc/trees/debug_rect_history.cc
+++ b/chromium/cc/trees/debug_rect_history.cc
@@ -32,7 +32,7 @@ DebugRectHistory::~DebugRectHistory() {}
void DebugRectHistory::SaveDebugRectsForCurrentFrame(
LayerTreeImpl* tree_impl,
LayerImpl* hud_layer,
- const LayerImplList& render_surface_layer_list,
+ const RenderSurfaceList& render_surface_list,
const LayerTreeDebugState& debug_state) {
// For now, clear all rects from previous frames. In the future we may want to
// store all debug rects for a history of many frames.
@@ -54,13 +54,13 @@ void DebugRectHistory::SaveDebugRectsForCurrentFrame(
SavePaintRects(tree_impl);
if (debug_state.show_property_changed_rects)
- SavePropertyChangedRects(render_surface_layer_list, hud_layer);
+ SavePropertyChangedRects(tree_impl, hud_layer);
if (debug_state.show_surface_damage_rects)
- SaveSurfaceDamageRects(render_surface_layer_list);
+ SaveSurfaceDamageRects(render_surface_list);
if (debug_state.show_screen_space_rects)
- SaveScreenSpaceRects(render_surface_layer_list);
+ SaveScreenSpaceRects(render_surface_list);
if (debug_state.show_layer_animation_bounds_rects)
SaveLayerAnimationBoundsRects(tree_impl);
@@ -84,46 +84,27 @@ void DebugRectHistory::SavePaintRects(LayerTreeImpl* tree_impl) {
}
}
-void DebugRectHistory::SavePropertyChangedRects(
- const LayerImplList& render_surface_layer_list,
- LayerImpl* hud_layer) {
- for (size_t i = 0; i < render_surface_layer_list.size(); ++i) {
- size_t surface_index = render_surface_layer_list.size() - 1 - i;
- LayerImpl* render_surface_layer = render_surface_layer_list[surface_index];
- RenderSurfaceImpl* render_surface =
- render_surface_layer->GetRenderSurface();
- DCHECK(render_surface);
-
- const LayerImplList& layer_list = render_surface->layer_list();
- for (unsigned layer_index = 0; layer_index < layer_list.size();
- ++layer_index) {
- LayerImpl* layer = layer_list[layer_index];
-
- if (layer->GetRenderSurface() &&
- layer->GetRenderSurface() != render_surface)
- continue;
-
- if (layer == hud_layer)
- continue;
+void DebugRectHistory::SavePropertyChangedRects(LayerTreeImpl* tree_impl,
+ LayerImpl* hud_layer) {
+ for (LayerImpl* layer : *tree_impl) {
+ if (layer == hud_layer)
+ continue;
- if (!layer->LayerPropertyChanged())
- continue;
+ if (!layer->LayerPropertyChanged())
+ continue;
- debug_rects_.push_back(DebugRect(
- PROPERTY_CHANGED_RECT_TYPE,
- MathUtil::MapEnclosingClippedRect(layer->ScreenSpaceTransform(),
- gfx::Rect(layer->bounds()))));
- }
+ debug_rects_.push_back(DebugRect(
+ PROPERTY_CHANGED_RECT_TYPE,
+ MathUtil::MapEnclosingClippedRect(layer->ScreenSpaceTransform(),
+ gfx::Rect(layer->bounds()))));
}
}
void DebugRectHistory::SaveSurfaceDamageRects(
- const LayerImplList& render_surface_layer_list) {
- for (size_t i = 0; i < render_surface_layer_list.size(); ++i) {
- size_t surface_index = render_surface_layer_list.size() - 1 - i;
- LayerImpl* render_surface_layer = render_surface_layer_list[surface_index];
- RenderSurfaceImpl* render_surface =
- render_surface_layer->GetRenderSurface();
+ const RenderSurfaceList& render_surface_list) {
+ for (size_t i = 0; i < render_surface_list.size(); ++i) {
+ size_t surface_index = render_surface_list.size() - 1 - i;
+ RenderSurfaceImpl* render_surface = render_surface_list[surface_index];
DCHECK(render_surface);
debug_rects_.push_back(DebugRect(
@@ -134,12 +115,10 @@ void DebugRectHistory::SaveSurfaceDamageRects(
}
void DebugRectHistory::SaveScreenSpaceRects(
- const LayerImplList& render_surface_layer_list) {
- for (size_t i = 0; i < render_surface_layer_list.size(); ++i) {
- size_t surface_index = render_surface_layer_list.size() - 1 - i;
- LayerImpl* render_surface_layer = render_surface_layer_list[surface_index];
- RenderSurfaceImpl* render_surface =
- render_surface_layer->GetRenderSurface();
+ const RenderSurfaceList& render_surface_list) {
+ for (size_t i = 0; i < render_surface_list.size(); ++i) {
+ size_t surface_index = render_surface_list.size() - 1 - i;
+ RenderSurfaceImpl* render_surface = render_surface_list[surface_index];
DCHECK(render_surface);
debug_rects_.push_back(DebugRect(
@@ -218,7 +197,7 @@ void DebugRectHistory::SaveNonFastScrollableRectsCallback(LayerImpl* layer) {
void DebugRectHistory::SaveLayerAnimationBoundsRects(LayerTreeImpl* tree_impl) {
for (auto it = tree_impl->rbegin(); it != tree_impl->rend(); ++it) {
- if (!(*it)->is_drawn_render_surface_layer_list_member())
+ if (!(*it)->contributes_to_drawn_render_surface())
continue;
// TODO(avallee): Figure out if we should show something for a layer who's
diff --git a/chromium/cc/trees/debug_rect_history.h b/chromium/cc/trees/debug_rect_history.h
index 183cddeb775..7728237eb54 100644
--- a/chromium/cc/trees/debug_rect_history.h
+++ b/chromium/cc/trees/debug_rect_history.h
@@ -67,7 +67,7 @@ class DebugRectHistory {
void SaveDebugRectsForCurrentFrame(
LayerTreeImpl* tree_impl,
LayerImpl* hud_layer,
- const LayerImplList& render_surface_layer_list,
+ const RenderSurfaceList& render_surface_list,
const LayerTreeDebugState& debug_state);
const std::vector<DebugRect>& debug_rects() { return debug_rects_; }
@@ -76,10 +76,9 @@ class DebugRectHistory {
DebugRectHistory();
void SavePaintRects(LayerTreeImpl* tree_impl);
- void SavePropertyChangedRects(const LayerImplList& render_surface_layer_list,
- LayerImpl* hud_layer);
- void SaveSurfaceDamageRects(const LayerImplList& render_surface_layer_list);
- void SaveScreenSpaceRects(const LayerImplList& render_surface_layer_list);
+ void SavePropertyChangedRects(LayerTreeImpl* tree_impl, LayerImpl* hud_layer);
+ void SaveSurfaceDamageRects(const RenderSurfaceList& render_surface_list);
+ void SaveScreenSpaceRects(const RenderSurfaceList& render_surface_list);
void SaveTouchEventHandlerRects(LayerTreeImpl* layer);
void SaveTouchEventHandlerRectsCallback(LayerImpl* layer);
void SaveWheelEventHandlerRects(LayerTreeImpl* tree_impl);
diff --git a/chromium/cc/trees/draw_property_utils.cc b/chromium/cc/trees/draw_property_utils.cc
index 5af6686aa61..43120259e3d 100644
--- a/chromium/cc/trees/draw_property_utils.cc
+++ b/chromium/cc/trees/draw_property_utils.cc
@@ -458,14 +458,11 @@ static inline bool LayerShouldBeSkippedInternal(
transform_tree.Node(layer->transform_tree_index());
const EffectNode* effect_node = effect_tree.Node(layer->effect_tree_index());
- if (effect_node->has_render_surface &&
- effect_node->num_copy_requests_in_subtree > 0)
+ if (effect_node->has_render_surface && effect_node->subtree_has_copy_request)
return false;
- // If the layer transform is not invertible, it should be skipped.
- // TODO(ajuma): Correctly process subtrees with singular transform for the
- // case where we may animate to a non-singular transform and wish to
- // pre-raster.
+ // If the layer transform is not invertible, it should be skipped. In case the
+ // transform is animating and singular, we should not skip it.
return !transform_node->node_and_ancestors_are_animated_or_invertible ||
effect_node->hidden_by_backface_visibility || !effect_node->is_drawn;
}
@@ -672,9 +669,10 @@ static void SetSurfaceDrawTransform(const PropertyTrees* property_trees,
static gfx::Rect LayerVisibleRect(PropertyTrees* property_trees,
LayerImpl* layer) {
+ const EffectNode* effect_node =
+ property_trees->effect_tree.Node(layer->effect_tree_index());
int effect_ancestor_with_copy_request =
- property_trees->effect_tree.ClosestAncestorWithCopyRequest(
- layer->effect_tree_index());
+ effect_node->closest_ancestor_with_copy_request_id;
bool non_root_copy_request =
effect_ancestor_with_copy_request > EffectTree::kContentsRootNodeId;
gfx::Rect layer_content_rect = gfx::Rect(layer->bounds());
@@ -722,27 +720,18 @@ static ConditionalClip LayerClipRect(PropertyTrees* property_trees,
effect_node->has_render_surface
? effect_node
: effect_tree->Node(effect_node->target_id);
- // TODO(weiliangc): When effect node has up to date render surface info on
- // compositor thread, no need to check for resourceless draw mode
- if (!property_trees->non_root_surfaces_enabled) {
- target_node = effect_tree->Node(1);
- }
-
bool include_expanding_clips = false;
return ComputeAccumulatedClip(property_trees, include_expanding_clips,
layer->clip_tree_index(), target_node->id);
}
-static void UpdateRenderTarget(EffectTree* effect_tree,
- bool can_render_to_separate_surface) {
+static void UpdateRenderTarget(EffectTree* effect_tree) {
for (int i = EffectTree::kContentsRootNodeId;
i < static_cast<int>(effect_tree->size()); ++i) {
EffectNode* node = effect_tree->Node(i);
if (i == EffectTree::kContentsRootNodeId) {
// Render target of the node corresponding to root is itself.
node->target_id = EffectTree::kContentsRootNodeId;
- } else if (!can_render_to_separate_surface) {
- node->target_id = EffectTree::kContentsRootNodeId;
} else if (effect_tree->parent(node)->has_render_surface) {
node->target_id = node->parent_id;
} else {
@@ -809,15 +798,17 @@ void ConcatInverseSurfaceContentsScale(const EffectNode* effect_node,
1.0 / effect_node->surface_contents_scale.y());
}
-bool LayerShouldBeSkipped(LayerImpl* layer,
- const TransformTree& transform_tree,
- const EffectTree& effect_tree) {
+bool LayerShouldBeSkippedForDrawPropertiesComputation(
+ LayerImpl* layer,
+ const TransformTree& transform_tree,
+ const EffectTree& effect_tree) {
return LayerShouldBeSkippedInternal(layer, transform_tree, effect_tree);
}
-bool LayerShouldBeSkipped(Layer* layer,
- const TransformTree& transform_tree,
- const EffectTree& effect_tree) {
+bool LayerShouldBeSkippedForDrawPropertiesComputation(
+ Layer* layer,
+ const TransformTree& transform_tree,
+ const EffectTree& effect_tree) {
return LayerShouldBeSkippedInternal(layer, transform_tree, effect_tree);
}
@@ -827,8 +818,8 @@ void FindLayersThatNeedUpdates(LayerTreeHost* layer_tree_host,
const TransformTree& transform_tree = property_trees->transform_tree;
const EffectTree& effect_tree = property_trees->effect_tree;
for (auto* layer : *layer_tree_host) {
- if (!IsRootLayer(layer) &&
- LayerShouldBeSkipped(layer, transform_tree, effect_tree))
+ if (!IsRootLayer(layer) && LayerShouldBeSkippedForDrawPropertiesComputation(
+ layer, transform_tree, effect_tree))
continue;
bool layer_is_drawn =
@@ -852,16 +843,9 @@ void FindLayersThatNeedUpdates(LayerTreeImpl* layer_tree_impl,
const EffectTree& effect_tree = property_trees->effect_tree;
for (auto* layer_impl : *layer_tree_impl) {
- DCHECK(layer_impl);
- DCHECK(layer_impl->layer_tree_impl());
- // TODO(crbug.com/726423) : This is a workaround for crbug.com/725851 to
- // avoid crashing when layer_impl is nullptr. This workaround should be
- // removed as layer_impl should not be nullptr here.
- if (!layer_impl || !layer_impl->HasValidPropertyTreeIndices())
- continue;
-
if (!IsRootLayer(layer_impl) &&
- LayerShouldBeSkipped(layer_impl, transform_tree, effect_tree))
+ LayerShouldBeSkippedForDrawPropertiesComputation(
+ layer_impl, transform_tree, effect_tree))
continue;
bool layer_is_drawn =
@@ -891,16 +875,10 @@ void ComputeEffects(EffectTree* effect_tree) {
}
void UpdatePropertyTrees(LayerTreeHost* layer_tree_host,
- PropertyTrees* property_trees,
- bool can_render_to_separate_surface) {
+ PropertyTrees* property_trees) {
DCHECK(layer_tree_host);
DCHECK(property_trees);
DCHECK_EQ(layer_tree_host->property_trees(), property_trees);
- if (property_trees->non_root_surfaces_enabled !=
- can_render_to_separate_surface) {
- property_trees->non_root_surfaces_enabled = can_render_to_separate_surface;
- property_trees->transform_tree.set_needs_update(true);
- }
if (property_trees->transform_tree.needs_update()) {
property_trees->clip_tree.set_needs_update(true);
property_trees->effect_tree.set_needs_update(true);
@@ -915,15 +893,8 @@ void UpdatePropertyTrees(LayerTreeHost* layer_tree_host,
void UpdatePropertyTreesAndRenderSurfaces(LayerImpl* root_layer,
PropertyTrees* property_trees,
- bool can_render_to_separate_surface,
bool can_adjust_raster_scales) {
bool render_surfaces_need_update = false;
- if (property_trees->non_root_surfaces_enabled !=
- can_render_to_separate_surface) {
- property_trees->non_root_surfaces_enabled = can_render_to_separate_surface;
- property_trees->transform_tree.set_needs_update(true);
- render_surfaces_need_update = true;
- }
if (property_trees->can_adjust_raster_scales != can_adjust_raster_scales) {
property_trees->can_adjust_raster_scales = can_adjust_raster_scales;
property_trees->transform_tree.set_needs_update(true);
@@ -935,11 +906,9 @@ void UpdatePropertyTreesAndRenderSurfaces(LayerImpl* root_layer,
}
if (render_surfaces_need_update) {
property_trees->effect_tree.UpdateRenderSurfaces(
- root_layer->layer_tree_impl(),
- property_trees->non_root_surfaces_enabled);
+ root_layer->layer_tree_impl());
}
- UpdateRenderTarget(&property_trees->effect_tree,
- property_trees->non_root_surfaces_enabled);
+ UpdateRenderTarget(&property_trees->effect_tree);
ComputeTransforms(&property_trees->transform_tree);
ComputeEffects(&property_trees->effect_tree);
@@ -967,12 +936,9 @@ gfx::Transform DrawTransform(const LayerImpl* layer,
// node and surface's transform node and scales it by the surface's content
// scale.
gfx::Transform xform;
- if (transform_tree.property_trees()->non_root_surfaces_enabled)
- transform_tree.property_trees()->GetToTarget(
- layer->transform_tree_index(), layer->render_target_effect_tree_index(),
- &xform);
- else
- xform = transform_tree.ToScreen(layer->transform_tree_index());
+ transform_tree.property_trees()->GetToTarget(
+ layer->transform_tree_index(), layer->render_target_effect_tree_index(),
+ &xform);
if (layer->should_flatten_transform_from_property_tree())
xform.FlattenTo2d();
xform.Translate(layer->offset_to_transform_parent().x(),
@@ -1060,8 +1026,7 @@ void ComputeMaskDrawProperties(LayerImpl* mask_layer,
}
void ComputeSurfaceDrawProperties(PropertyTrees* property_trees,
- RenderSurfaceImpl* render_surface,
- const bool use_layer_lists) {
+ RenderSurfaceImpl* render_surface) {
SetSurfaceIsClipped(property_trees->clip_tree, render_surface);
SetSurfaceDrawOpacity(property_trees->effect_tree, render_surface);
SetSurfaceDrawTransform(property_trees, render_surface);
diff --git a/chromium/cc/trees/draw_property_utils.h b/chromium/cc/trees/draw_property_utils.h
index b5ff981c579..45ed01f6e88 100644
--- a/chromium/cc/trees/draw_property_utils.h
+++ b/chromium/cc/trees/draw_property_utils.h
@@ -37,15 +37,12 @@ void CC_EXPORT ComputeTransforms(TransformTree* transform_tree);
// Computes screen space opacity for every node in the opacity tree.
void CC_EXPORT ComputeEffects(EffectTree* effect_tree);
-
void CC_EXPORT UpdatePropertyTrees(LayerTreeHost* layer_tree_host,
- PropertyTrees* property_trees,
- bool can_render_to_separate_surface);
+ PropertyTrees* property_trees);
void CC_EXPORT
UpdatePropertyTreesAndRenderSurfaces(LayerImpl* root_layer,
PropertyTrees* property_trees,
- bool can_render_to_separate_surface,
bool can_adjust_raster_scales);
void CC_EXPORT FindLayersThatNeedUpdates(LayerTreeHost* layer_tree_host,
@@ -65,12 +62,12 @@ void CC_EXPORT ComputeMaskDrawProperties(LayerImpl* mask_layer,
const PropertyTrees* property_trees);
void CC_EXPORT ComputeSurfaceDrawProperties(PropertyTrees* property_trees,
- RenderSurfaceImpl* render_surface,
- const bool use_layer_lists);
+ RenderSurfaceImpl* render_surface);
-bool CC_EXPORT LayerShouldBeSkipped(LayerImpl* layer,
- const TransformTree& transform_tree,
- const EffectTree& effect_tree);
+bool CC_EXPORT LayerShouldBeSkippedForDrawPropertiesComputation(
+ LayerImpl* layer,
+ const TransformTree& transform_tree,
+ const EffectTree& effect_tree);
bool CC_EXPORT LayerNeedsUpdate(Layer* layer,
bool layer_is_drawn,
diff --git a/chromium/cc/trees/effect_node.cc b/chromium/cc/trees/effect_node.cc
index 142cb08db41..7a556277530 100644
--- a/chromium/cc/trees/effect_node.cc
+++ b/chromium/cc/trees/effect_node.cc
@@ -27,11 +27,12 @@ EffectNode::EffectNode()
is_currently_animating_filter(false),
is_currently_animating_opacity(false),
effect_changed(false),
- num_copy_requests_in_subtree(0),
+ subtree_has_copy_request(false),
transform_id(0),
clip_id(0),
target_id(1),
- mask_layer_id(-1) {}
+ mask_layer_id(Layer::INVALID_ID),
+ closest_ancestor_with_copy_request_id(-1) {}
EffectNode::EffectNode(const EffectNode& other) = default;
@@ -58,9 +59,11 @@ bool EffectNode::operator==(const EffectNode& other) const {
is_currently_animating_opacity ==
other.is_currently_animating_opacity &&
effect_changed == other.effect_changed &&
- num_copy_requests_in_subtree == other.num_copy_requests_in_subtree &&
+ subtree_has_copy_request == other.subtree_has_copy_request &&
transform_id == other.transform_id && clip_id == other.clip_id &&
- target_id == other.target_id && mask_layer_id == other.mask_layer_id;
+ target_id == other.target_id && mask_layer_id == other.mask_layer_id &&
+ closest_ancestor_with_copy_request_id ==
+ other.closest_ancestor_with_copy_request_id;
}
void EffectNode::AsValueInto(base::trace_event::TracedValue* value) const {
@@ -77,12 +80,13 @@ void EffectNode::AsValueInto(base::trace_event::TracedValue* value) const {
value->SetBoolean("has_potential_opacity_animation",
has_potential_opacity_animation);
value->SetBoolean("effect_changed", effect_changed);
- value->SetInteger("num_copy_requests_in_subtree",
- num_copy_requests_in_subtree);
+ value->SetInteger("subtree_has_copy_request", subtree_has_copy_request);
value->SetInteger("transform_id", transform_id);
value->SetInteger("clip_id", clip_id);
value->SetInteger("target_id", target_id);
value->SetInteger("mask_layer_id", mask_layer_id);
+ value->SetInteger("closest_ancestor_with_copy_request_id",
+ closest_ancestor_with_copy_request_id);
}
} // namespace cc
diff --git a/chromium/cc/trees/effect_node.h b/chromium/cc/trees/effect_node.h
index 48997c03823..8079f898283 100644
--- a/chromium/cc/trees/effect_node.h
+++ b/chromium/cc/trees/effect_node.h
@@ -43,27 +43,42 @@ struct CC_EXPORT EffectNode {
gfx::Size unscaled_mask_target_size;
- bool has_render_surface;
- bool has_copy_request;
- bool hidden_by_backface_visibility;
- bool double_sided;
- bool is_drawn;
+ bool has_render_surface : 1;
+ bool has_copy_request : 1;
+ bool hidden_by_backface_visibility : 1;
+ bool double_sided : 1;
+ bool is_drawn : 1;
// TODO(jaydasika) : Delete this after implementation of
// SetHideLayerAndSubtree is cleaned up. (crbug.com/595843)
- bool subtree_hidden;
- bool has_potential_filter_animation;
- bool has_potential_opacity_animation;
- bool is_currently_animating_filter;
- bool is_currently_animating_opacity;
- // We need to track changes to effects on the compositor to compute damage
- // rect.
- bool effect_changed;
- int num_copy_requests_in_subtree;
+ bool subtree_hidden : 1;
+ // Whether this node has a potentially running (i.e., irrespective
+ // of exact timeline) filter animation.
+ bool has_potential_filter_animation : 1;
+ // Whether this node has a potentially running (i.e., irrespective
+ // of exact timeline) opacity animation.
+ bool has_potential_opacity_animation : 1;
+ // Whether this node has a currently running filter animation.
+ bool is_currently_animating_filter : 1;
+ // Whether this node has a currently running opacity animation.
+ bool is_currently_animating_opacity : 1;
+ // Whether this node's effect has been changed since the last
+ // frame. Needed in order to compute damage rect.
+ bool effect_changed : 1;
+ bool subtree_has_copy_request : 1;
+ // The transform node index of the transform to apply to this effect
+ // node's content when rendering to a surface.
int transform_id;
+ // The clip node index of the clip to apply to this effect node's
+ // content when rendering to a surface.
int clip_id;
- // Effect node id of which this effect contributes to.
+
+ // This is the id of the ancestor effect node that induces a
+ // RenderSurfaceImpl.
int target_id;
+ // The layer id of the mask layer, if any, to apply to this effect
+ // node's content when rendering to a surface.
int mask_layer_id;
+ int closest_ancestor_with_copy_request_id;
bool operator==(const EffectNode& other) const;
diff --git a/chromium/cc/trees/element_id.cc b/chromium/cc/trees/element_id.cc
index 45913303c10..6e32b660aa5 100644
--- a/chromium/cc/trees/element_id.cc
+++ b/chromium/cc/trees/element_id.cc
@@ -13,7 +13,7 @@
namespace cc {
bool ElementId::operator==(const ElementId& o) const {
- return primaryId == o.primaryId && secondaryId == o.secondaryId;
+ return id_ == o.id_;
}
bool ElementId::operator!=(const ElementId& o) const {
@@ -21,36 +21,33 @@ bool ElementId::operator!=(const ElementId& o) const {
}
bool ElementId::operator<(const ElementId& o) const {
- return std::tie(primaryId, secondaryId) <
- std::tie(o.primaryId, o.secondaryId);
+ return id_ < o.id_;
}
ElementId::operator bool() const {
- return !!primaryId;
+ return !!id_;
}
ElementId LayerIdToElementIdForTesting(int layer_id) {
- return ElementId(std::numeric_limits<int>::max() - layer_id, 0);
+ return ElementId(std::numeric_limits<int>::max() - layer_id);
}
void ElementId::AddToTracedValue(base::trace_event::TracedValue* res) const {
- res->SetInteger("primaryId", primaryId);
- res->SetInteger("secondaryId", secondaryId);
+ res->SetInteger("id_", id_);
}
std::unique_ptr<base::Value> ElementId::AsValue() const {
std::unique_ptr<base::DictionaryValue> res(new base::DictionaryValue());
- res->SetInteger("primaryId", primaryId);
- res->SetInteger("secondaryId", secondaryId);
+ res->SetInteger("id_", id_);
return std::move(res);
}
size_t ElementIdHash::operator()(ElementId key) const {
- return base::HashInts(key.primaryId, key.secondaryId);
+ return std::hash<int>()(key.id_);
}
std::ostream& operator<<(std::ostream& out, const ElementId& id) {
- return out << "(" << id.primaryId << ", " << id.secondaryId << ")";
+ return out << "(" << id.id_ << ")";
}
} // namespace cc
diff --git a/chromium/cc/trees/element_id.h b/chromium/cc/trees/element_id.h
index 74de4c9995f..059cf2b36d7 100644
--- a/chromium/cc/trees/element_id.h
+++ b/chromium/cc/trees/element_id.h
@@ -24,20 +24,32 @@ class TracedValue;
namespace cc {
-// An "element" is really an animation target. It retains the name element to be
-// symmetric with ElementAnimations and blink::ElementAnimations, but is not
-// in fact tied to the notion of a blink element. It is also not associated with
-// the notion of a Layer. Ultimately, these ids will be used to look up the
-// property tree node associated with the given animation.
+using ElementIdType = uint64_t;
+
+static const ElementIdType kInvalidElementId = 0;
+
+// Element ids are chosen by cc's clients and can be used as a stable identifier
+// across updates.
+//
+// Historically, the layer tree stored all compositing data but this has been
+// refactored over time into auxilliary structures such as property trees.
+//
+// In composited scrolling, Layers directly reference scroll tree nodes
+// (Layer::scroll_tree_index) but scroll tree nodes are being refactored to
+// reference stable element ids instead of layers. Scroll property nodes have
+// unique element ids that blink creates from scrollable areas (though this is
+// opaque to the compositor). This refactoring of scroll nodes keeping a
+// scrolling element id instead of a scrolling layer id allows for more general
+// compositing where, for example, multiple layers scroll with one scroll node.
//
-// These ids are chosen by cc's clients to permit the destruction and
-// restoration of cc entities (when visuals are hidden and shown) but maintain
-// stable identifiers. There will be a single layer for an ElementId, but
-// not every layer will have an id.
+// The animation system (see: ElementAnimations and blink::ElementAnimations) is
+// another auxilliary structure to the layer tree and uses element ids as a
+// stable identifier for animation targets. A Layer's element id can change over
+// the Layer's lifetime because non-default ElementIds are only set during an
+// animation's lifetime.
struct CC_EXPORT ElementId {
- ElementId(int primaryId, int secondaryId)
- : primaryId(primaryId), secondaryId(secondaryId) {}
- ElementId() : ElementId(0, 0) {}
+ explicit ElementId(int id) : id_(id) {}
+ ElementId() : ElementId(kInvalidElementId) {}
bool operator==(const ElementId& o) const;
bool operator!=(const ElementId& o) const;
@@ -52,11 +64,10 @@ struct CC_EXPORT ElementId {
// The compositor treats this as an opaque handle and should not know how to
// interpret these bits. Non-blink cc clients typically operate in terms of
// layers and may set this value to match the client's layer id.
- int primaryId;
- int secondaryId;
+ ElementIdType id_;
};
-CC_EXPORT ElementId LayerIdToElementIdForTesting(int layer_id);
+ElementId CC_EXPORT LayerIdToElementIdForTesting(int layer_id);
struct CC_EXPORT ElementIdHash {
size_t operator()(ElementId key) const;
diff --git a/chromium/cc/trees/layer_tree_host.cc b/chromium/cc/trees/layer_tree_host.cc
index e8a6f4b0c07..8db96130c74 100644
--- a/chromium/cc/trees/layer_tree_host.cc
+++ b/chromium/cc/trees/layer_tree_host.cc
@@ -46,7 +46,6 @@
#include "cc/trees/layer_tree_host_client.h"
#include "cc/trees/layer_tree_host_common.h"
#include "cc/trees/layer_tree_host_impl.h"
-#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/mutator_host.h"
#include "cc/trees/property_tree_builder.h"
#include "cc/trees/proxy_main.h"
@@ -108,8 +107,6 @@ LayerTreeHost::LayerTreeHost(InitParams* params, CompositorMode mode)
mutator_host_(params->mutator_host) {
DCHECK(task_graph_runner_);
DCHECK(!settings_.enable_checker_imaging || image_worker_task_runner_);
- DCHECK(!settings_.enable_checker_imaging ||
- settings_.image_decode_tasks_enabled);
mutator_host_->SetMutatorHostClient(this);
@@ -168,14 +165,14 @@ void LayerTreeHost::InitializeProxy(std::unique_ptr<Proxy> proxy) {
LayerTreeHost::~LayerTreeHost() {
// Track when we're inside a main frame to see if compositor is being
// destroyed midway which causes a crash. crbug.com/654672
- CHECK(!inside_main_frame_);
+ DCHECK(!inside_main_frame_);
TRACE_EVENT0("cc", "LayerTreeHostInProcess::~LayerTreeHostInProcess");
// Clear any references into the LayerTreeHost.
mutator_host_->SetMutatorHostClient(nullptr);
// We must clear any pointers into the layer tree prior to destroying it.
- RegisterViewportLayers(nullptr, nullptr, nullptr, nullptr);
+ RegisterViewportLayers(ViewportLayers());
if (root_layer_) {
root_layer_->SetLayerTreeHost(nullptr);
@@ -249,6 +246,10 @@ void LayerTreeHost::BeginMainFrameNotExpectedSoon() {
client_->BeginMainFrameNotExpectedSoon();
}
+void LayerTreeHost::BeginMainFrameNotExpectedUntil(base::TimeTicks time) {
+ client_->BeginMainFrameNotExpectedUntil(time);
+}
+
void LayerTreeHost::BeginMainFrame(const BeginFrameArgs& args) {
client_->BeginMainFrame(args);
}
@@ -288,6 +289,7 @@ void LayerTreeHost::FinishCommitOnImplThread(
}
LayerTreeImpl* sync_tree = host_impl->sync_tree();
+ sync_tree->lifecycle().AdvanceTo(LayerTreeLifecycle::kBeginningSync);
if (next_commit_forces_redraw_) {
sync_tree->ForceRedrawNextActivation();
@@ -303,34 +305,37 @@ void LayerTreeHost::FinishCommitOnImplThread(
if (needs_full_tree_sync_)
TreeSynchronizer::SynchronizeTrees(root_layer(), sync_tree);
- PushPropertiesTo(sync_tree);
+ // Track the navigation state before pushing properties since it overwrites
+ // the |content_source_id_| on the sync tree.
+ bool did_navigate = content_source_id_ != sync_tree->content_source_id();
+ if (did_navigate)
+ host_impl->ClearImageCacheOnNavigation();
- sync_tree->PassSwapPromises(swap_promise_manager_.TakeSwapPromises());
+ {
+ TRACE_EVENT0("cc", "LayerTreeHostInProcess::PushProperties");
- host_impl->SetHasGpuRasterizationTrigger(has_gpu_rasterization_trigger_);
- host_impl->SetContentIsSuitableForGpuRasterization(
- content_is_suitable_for_gpu_rasterization_);
- RecordGpuRasterizationHistogram(host_impl);
+ PushPropertyTreesTo(sync_tree);
+ sync_tree->lifecycle().AdvanceTo(LayerTreeLifecycle::kSyncedPropertyTrees);
- host_impl->SetViewportSize(device_viewport_size_);
- sync_tree->SetDeviceScaleFactor(device_scale_factor_);
- host_impl->SetDebugState(debug_state_);
+ TreeSynchronizer::PushLayerProperties(this, sync_tree);
+ sync_tree->lifecycle().AdvanceTo(
+ LayerTreeLifecycle::kSyncedLayerProperties);
- if (did_navigate_) {
- did_navigate_ = false;
- host_impl->ClearImageCacheOnNavigation();
- }
+ PushLayerTreePropertiesTo(sync_tree);
+ PushLayerTreeHostPropertiesTo(host_impl);
- sync_tree->set_ui_resource_request_queue(
- ui_resource_manager_->TakeUIResourcesRequests());
+ sync_tree->PassSwapPromises(swap_promise_manager_.TakeSwapPromises());
- {
- TRACE_EVENT0("cc", "LayerTreeHostInProcess::PushProperties");
+ // TODO(pdr): Move this into PushPropertyTreesTo or introduce a lifecycle
+ // state for it.
+ sync_tree->SetDeviceScaleFactor(device_scale_factor_);
- TreeSynchronizer::PushLayerProperties(this, sync_tree);
+ sync_tree->set_ui_resource_request_queue(
+ ui_resource_manager_->TakeUIResourcesRequests());
// This must happen after synchronizing property trees and after pushing
// properties, which updates the clobber_active_value flag.
+ // TODO(pdr): Enforce this comment with DCHECKS and a lifecycle state.
sync_tree->property_trees()->scroll_tree.PushScrollUpdatesFromMainThread(
property_trees(), sync_tree);
@@ -339,11 +344,16 @@ void LayerTreeHost::FinishCommitOnImplThread(
// host pushes properties as animation host push properties can change
// Animation::InEffect and we want the old InEffect value for updating
// property tree scrolling and animation.
- sync_tree->UpdatePropertyTreeScrollingAndAnimationFromMainThread();
+ // TODO(pdr): Enforce this comment with DCHECKS and a lifecycle state.
+ bool is_impl_side_update = false;
+ sync_tree->UpdatePropertyTreeScrollingAndAnimationFromMainThread(
+ is_impl_side_update);
TRACE_EVENT0("cc", "LayerTreeHostInProcess::AnimationHost::PushProperties");
DCHECK(host_impl->mutator_host());
mutator_host_->PushPropertiesTo(host_impl->mutator_host());
+
+ sync_tree->lifecycle().AdvanceTo(LayerTreeLifecycle::kNotSyncing);
}
// Transfer image decode requests to the impl thread.
@@ -355,6 +365,23 @@ void LayerTreeHost::FinishCommitOnImplThread(
property_trees_.ResetAllChangeTracking();
}
+void LayerTreeHost::PushPropertyTreesTo(LayerTreeImpl* tree_impl) {
+ bool property_trees_changed_on_active_tree =
+ tree_impl->IsActiveTree() && tree_impl->property_trees()->changed;
+ // Property trees may store damage status. We preserve the sync tree damage
+ // status by pushing the damage status from sync tree property trees to main
+ // thread property trees or by moving it onto the layers.
+ if (root_layer_ && property_trees_changed_on_active_tree) {
+ if (property_trees_.sequence_number ==
+ tree_impl->property_trees()->sequence_number)
+ tree_impl->property_trees()->PushChangeTrackingTo(&property_trees_);
+ else
+ tree_impl->MoveChangeTrackingToLayers();
+ }
+
+ tree_impl->SetPropertyTrees(&property_trees_);
+}
+
void LayerTreeHost::WillCommit() {
swap_promise_manager_.WillCommit();
client_->WillCommit();
@@ -652,7 +679,7 @@ bool LayerTreeHost::DoUpdateLayers(Layer* root_layer) {
Layer* root_scroll =
PropertyTreeBuilder::FindFirstScrollableLayer(root_layer);
- Layer* page_scale_layer = page_scale_layer_.get();
+ Layer* page_scale_layer = viewport_layers_.page_scale.get();
if (!page_scale_layer && root_scroll)
page_scale_layer = root_scroll->parent();
@@ -682,7 +709,6 @@ bool LayerTreeHost::DoUpdateLayers(Layer* root_layer) {
TRACE_EVENT0(
TRACE_DISABLED_BY_DEFAULT("cc.debug.cdp-perf"),
"LayerTreeHostInProcessCommon::ComputeVisibleRectsWithPropertyTrees");
- bool can_render_to_separate_surface = true;
PropertyTrees* property_trees = &property_trees_;
if (!settings_.use_layer_lists) {
// If use_layer_lists is set, then the property trees should have been
@@ -702,15 +728,11 @@ bool LayerTreeHost::DoUpdateLayers(Layer* root_layer) {
TRACE_EVENT_SCOPE_THREAD, "property_trees",
property_trees->AsTracedValue());
}
- draw_property_utils::UpdatePropertyTrees(this, property_trees,
- can_render_to_separate_surface);
+ draw_property_utils::UpdatePropertyTrees(this, property_trees);
draw_property_utils::FindLayersThatNeedUpdates(this, property_trees,
&update_layer_list);
}
- for (const auto& layer : update_layer_list)
- layer->SavePaintProperties();
-
bool content_is_suitable_for_gpu = true;
bool did_paint_content =
PaintContent(update_layer_list, &content_is_suitable_for_gpu);
@@ -740,10 +762,10 @@ void LayerTreeHost::ApplyViewportDeltas(ScrollAndScaleSet* info) {
// Preemptively apply the scroll offset and scale delta here before sending
// it to the client. If the client comes back and sets it to the same
// value, then the layer can early out without needing a full commit.
- if (inner_viewport_scroll_layer_) {
- inner_viewport_scroll_layer_->SetScrollOffsetFromImplSide(
+ if (viewport_layers_.inner_viewport_scroll) {
+ viewport_layers_.inner_viewport_scroll->SetScrollOffsetFromImplSide(
gfx::ScrollOffsetWithDelta(
- inner_viewport_scroll_layer_->scroll_offset(),
+ viewport_layers_.inner_viewport_scroll->scroll_offset(),
inner_viewport_scroll_delta));
}
@@ -788,7 +810,7 @@ void LayerTreeHost::ApplyScrollAndScale(ScrollAndScaleSet* info) {
SetNeedsUpdateLayers();
}
for (size_t i = 0; i < info->scrollbars.size(); ++i) {
- Layer* layer = LayerById(info->scrollbars[i].layer_id);
+ Layer* layer = LayerByElementId(info->scrollbars[i].element_id);
if (!layer)
continue;
layer->SetScrollbarsHiddenFromImplSide(info->scrollbars[i].hidden);
@@ -878,20 +900,21 @@ void LayerTreeHost::SetRootLayer(scoped_refptr<Layer> root_layer) {
ResetGpuRasterizationTracking();
SetNeedsFullTreeSync();
- did_navigate_ = true;
}
-void LayerTreeHost::RegisterViewportLayers(
- scoped_refptr<Layer> overscroll_elasticity_layer,
- scoped_refptr<Layer> page_scale_layer,
- scoped_refptr<Layer> inner_viewport_scroll_layer,
- scoped_refptr<Layer> outer_viewport_scroll_layer) {
- DCHECK(!inner_viewport_scroll_layer ||
- inner_viewport_scroll_layer != outer_viewport_scroll_layer);
- overscroll_elasticity_layer_ = overscroll_elasticity_layer;
- page_scale_layer_ = page_scale_layer;
- inner_viewport_scroll_layer_ = inner_viewport_scroll_layer;
- outer_viewport_scroll_layer_ = outer_viewport_scroll_layer;
+LayerTreeHost::ViewportLayers::ViewportLayers() {}
+
+LayerTreeHost::ViewportLayers::~ViewportLayers() {}
+
+void LayerTreeHost::RegisterViewportLayers(const ViewportLayers& layers) {
+ DCHECK(!layers.inner_viewport_scroll ||
+ layers.inner_viewport_scroll != layers.outer_viewport_scroll);
+ viewport_layers_.overscroll_elasticity = layers.overscroll_elasticity;
+ viewport_layers_.page_scale = layers.page_scale;
+ viewport_layers_.inner_viewport_container = layers.inner_viewport_container;
+ viewport_layers_.outer_viewport_container = layers.outer_viewport_container;
+ viewport_layers_.inner_viewport_scroll = layers.inner_viewport_scroll;
+ viewport_layers_.outer_viewport_scroll = layers.outer_viewport_scroll;
}
void LayerTreeHost::RegisterSelection(const LayerSelection& selection) {
@@ -1123,7 +1146,7 @@ void LayerTreeHost::SetPropertyTreesNeedRebuild() {
SetNeedsUpdateLayers();
}
-void LayerTreeHost::PushPropertiesTo(LayerTreeImpl* tree_impl) {
+void LayerTreeHost::PushLayerTreePropertiesTo(LayerTreeImpl* tree_impl) {
tree_impl->set_needs_full_tree_sync(needs_full_tree_sync_);
needs_full_tree_sync_ = false;
@@ -1147,35 +1170,29 @@ void LayerTreeHost::PushPropertiesTo(LayerTreeImpl* tree_impl) {
EventListenerClass::kTouchEndOrCancel,
event_listener_properties(EventListenerClass::kTouchEndOrCancel));
- if (page_scale_layer_ && inner_viewport_scroll_layer_) {
- tree_impl->SetViewportLayersFromIds(
- overscroll_elasticity_layer_ ? overscroll_elasticity_layer_->id()
- : Layer::INVALID_ID,
- page_scale_layer_->id(), inner_viewport_scroll_layer_->id(),
- outer_viewport_scroll_layer_ ? outer_viewport_scroll_layer_->id()
- : Layer::INVALID_ID);
- DCHECK(inner_viewport_scroll_layer_->IsContainerForFixedPositionLayers());
+ if (viewport_layers_.page_scale && viewport_layers_.inner_viewport_scroll) {
+ LayerTreeImpl::ViewportLayerIds ids;
+ if (viewport_layers_.overscroll_elasticity)
+ ids.overscroll_elasticity = viewport_layers_.overscroll_elasticity->id();
+ ids.page_scale = viewport_layers_.page_scale->id();
+ if (viewport_layers_.inner_viewport_container)
+ ids.inner_viewport_container =
+ viewport_layers_.inner_viewport_container->id();
+ if (viewport_layers_.outer_viewport_container)
+ ids.outer_viewport_container =
+ viewport_layers_.outer_viewport_container->id();
+ ids.inner_viewport_scroll = viewport_layers_.inner_viewport_scroll->id();
+ if (viewport_layers_.outer_viewport_scroll)
+ ids.outer_viewport_scroll = viewport_layers_.outer_viewport_scroll->id();
+ tree_impl->SetViewportLayersFromIds(ids);
+ DCHECK(viewport_layers_.inner_viewport_scroll
+ ->IsContainerForFixedPositionLayers());
} else {
tree_impl->ClearViewportLayers();
}
tree_impl->RegisterSelection(selection_);
- bool property_trees_changed_on_active_tree =
- tree_impl->IsActiveTree() && tree_impl->property_trees()->changed;
- // Property trees may store damage status. We preserve the sync tree damage
- // status by pushing the damage status from sync tree property trees to main
- // thread property trees or by moving it onto the layers.
- if (root_layer_ && property_trees_changed_on_active_tree) {
- if (property_trees_.sequence_number ==
- tree_impl->property_trees()->sequence_number)
- tree_impl->property_trees()->PushChangeTrackingTo(&property_trees_);
- else
- tree_impl->MoveChangeTrackingToLayers();
- }
- // Setting property trees must happen before pushing the page scale.
- tree_impl->SetPropertyTrees(&property_trees_);
-
tree_impl->PushPageScaleFromMainThread(
page_scale_factor_, min_page_scale_factor_, max_page_scale_factor_);
@@ -1206,6 +1223,17 @@ void LayerTreeHost::PushPropertiesTo(LayerTreeImpl* tree_impl) {
tree_impl->set_has_ever_been_drawn(false);
}
+void LayerTreeHost::PushLayerTreeHostPropertiesTo(
+ LayerTreeHostImpl* host_impl) {
+ host_impl->SetHasGpuRasterizationTrigger(has_gpu_rasterization_trigger_);
+ host_impl->SetContentIsSuitableForGpuRasterization(
+ content_is_suitable_for_gpu_rasterization_);
+ RecordGpuRasterizationHistogram(host_impl);
+
+ host_impl->SetViewportSize(device_viewport_size_);
+ host_impl->SetDebugState(debug_state_);
+}
+
Layer* LayerTreeHost::LayerByElementId(ElementId element_id) const {
auto iter = element_layers_map_.find(element_id);
return iter != element_layers_map_.end() ? iter->second : nullptr;
@@ -1264,6 +1292,13 @@ void LayerTreeHost::SetMutatorsNeedRebuildPropertyTrees() {
void LayerTreeHost::SetElementFilterMutated(ElementId element_id,
ElementListType list_type,
const FilterOperations& filters) {
+ if (settings_.use_layer_lists) {
+ // In SPv2 we always have property trees and can set the filter
+ // directly on the effect node.
+ property_trees_.effect_tree.OnFilterAnimated(element_id, filters);
+ return;
+ }
+
Layer* layer = LayerByElementId(element_id);
DCHECK(layer);
layer->OnFilterAnimated(filters);
@@ -1272,10 +1307,16 @@ void LayerTreeHost::SetElementFilterMutated(ElementId element_id,
void LayerTreeHost::SetElementOpacityMutated(ElementId element_id,
ElementListType list_type,
float opacity) {
- Layer* layer = LayerByElementId(element_id);
- DCHECK(layer);
DCHECK_GE(opacity, 0.f);
DCHECK_LE(opacity, 1.f);
+
+ if (settings_.use_layer_lists) {
+ property_trees_.effect_tree.OnOpacityAnimated(element_id, opacity);
+ return;
+ }
+
+ Layer* layer = LayerByElementId(element_id);
+ DCHECK(layer);
layer->OnOpacityAnimated(opacity);
if (EffectNode* node =
@@ -1296,6 +1337,11 @@ void LayerTreeHost::SetElementTransformMutated(
ElementId element_id,
ElementListType list_type,
const gfx::Transform& transform) {
+ if (settings_.use_layer_lists) {
+ property_trees_.transform_tree.OnTransformAnimated(element_id, transform);
+ return;
+ }
+
Layer* layer = LayerByElementId(element_id);
DCHECK(layer);
layer->OnTransformAnimated(transform);
@@ -1441,4 +1487,8 @@ void LayerTreeHost::SetNeedsDisplayOnAllLayers() {
layer->SetNeedsDisplay();
}
+void LayerTreeHost::SetHasCopyRequest(bool has_copy_request) {
+ has_copy_request_ = has_copy_request;
+}
+
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host.h b/chromium/cc/trees/layer_tree_host.h
index bf5520e2a39..51622245b1e 100644
--- a/chromium/cc/trees/layer_tree_host.h
+++ b/chromium/cc/trees/layer_tree_host.h
@@ -19,6 +19,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
+#include "base/single_thread_task_runner.h"
#include "base/time/time.h"
#include "cc/benchmarks/micro_benchmark.h"
#include "cc/benchmarks/micro_benchmark_controller.h"
@@ -67,8 +68,6 @@ struct ScrollAndScaleSet;
class CC_EXPORT LayerTreeHost : public NON_EXPORTED_BASE(SurfaceReferenceOwner),
public NON_EXPORTED_BASE(MutatorHostClient) {
public:
- // TODO(sad): InitParams should be a movable type so that it can be
- // std::move()d to the Create* functions.
struct CC_EXPORT InitParams {
LayerTreeHostClient* client = nullptr;
TaskGraphRunner* task_graph_runner = nullptr;
@@ -242,20 +241,32 @@ class CC_EXPORT LayerTreeHost : public NON_EXPORTED_BASE(SurfaceReferenceOwner),
Layer* root_layer() { return root_layer_.get(); }
const Layer* root_layer() const { return root_layer_.get(); }
- void RegisterViewportLayers(scoped_refptr<Layer> overscroll_elasticity_layer,
- scoped_refptr<Layer> page_scale_layer,
- scoped_refptr<Layer> inner_viewport_scroll_layer,
- scoped_refptr<Layer> outer_viewport_scroll_layer);
-
+ struct CC_EXPORT ViewportLayers {
+ ViewportLayers();
+ ~ViewportLayers();
+ scoped_refptr<Layer> overscroll_elasticity;
+ scoped_refptr<Layer> page_scale;
+ scoped_refptr<Layer> inner_viewport_container;
+ scoped_refptr<Layer> outer_viewport_container;
+ scoped_refptr<Layer> inner_viewport_scroll;
+ scoped_refptr<Layer> outer_viewport_scroll;
+ };
+ void RegisterViewportLayers(const ViewportLayers& viewport_layers);
Layer* overscroll_elasticity_layer() const {
- return overscroll_elasticity_layer_.get();
+ return viewport_layers_.overscroll_elasticity.get();
+ }
+ Layer* page_scale_layer() const { return viewport_layers_.page_scale.get(); }
+ Layer* inner_viewport_container_layer() const {
+ return viewport_layers_.inner_viewport_container.get();
+ }
+ Layer* outer_viewport_container_layer() const {
+ return viewport_layers_.outer_viewport_container.get();
}
- Layer* page_scale_layer() const { return page_scale_layer_.get(); }
Layer* inner_viewport_scroll_layer() const {
- return inner_viewport_scroll_layer_.get();
+ return viewport_layers_.inner_viewport_scroll.get();
}
Layer* outer_viewport_scroll_layer() const {
- return outer_viewport_scroll_layer_.get();
+ return viewport_layers_.outer_viewport_scroll.get();
}
void RegisterSelection(const LayerSelection& selection);
@@ -341,6 +352,9 @@ class CC_EXPORT LayerTreeHost : public NON_EXPORTED_BASE(SurfaceReferenceOwner),
bool* content_is_suitable_for_gpu);
bool in_paint_layer_contents() const { return in_paint_layer_contents_; }
+ void SetHasCopyRequest(bool has_copy_request);
+ bool has_copy_request() const { return has_copy_request_; }
+
void AddLayerShouldPushProperties(Layer* layer);
void RemoveLayerShouldPushProperties(Layer* layer);
std::unordered_set<Layer*>& LayersThatShouldPushProperties();
@@ -358,7 +372,9 @@ class CC_EXPORT LayerTreeHost : public NON_EXPORTED_BASE(SurfaceReferenceOwner),
void SetPropertyTreesNeedRebuild();
- void PushPropertiesTo(LayerTreeImpl* tree_impl);
+ void PushPropertyTreesTo(LayerTreeImpl* tree_impl);
+ void PushLayerTreePropertiesTo(LayerTreeImpl* tree_impl);
+ void PushLayerTreeHostPropertiesTo(LayerTreeHostImpl* host_impl);
MutatorHost* mutator_host() const { return mutator_host_; }
@@ -384,6 +400,7 @@ class CC_EXPORT LayerTreeHost : public NON_EXPORTED_BASE(SurfaceReferenceOwner),
void DidBeginMainFrame();
void BeginMainFrame(const BeginFrameArgs& args);
void BeginMainFrameNotExpectedSoon();
+ void BeginMainFrameNotExpectedUntil(base::TimeTicks time);
void AnimateLayers(base::TimeTicks monotonic_frame_begin_time);
void RequestMainFrameUpdate();
void FinishCommitOnImplThread(LayerTreeHostImpl* host_impl);
@@ -557,10 +574,7 @@ class CC_EXPORT LayerTreeHost : public NON_EXPORTED_BASE(SurfaceReferenceOwner),
scoped_refptr<Layer> root_layer_;
- scoped_refptr<Layer> overscroll_elasticity_layer_;
- scoped_refptr<Layer> page_scale_layer_;
- scoped_refptr<Layer> inner_viewport_scroll_layer_;
- scoped_refptr<Layer> outer_viewport_scroll_layer_;
+ ViewportLayers viewport_layers_;
float top_controls_height_ = 0.f;
float top_controls_shown_ratio_ = 0.f;
@@ -611,13 +625,16 @@ class CC_EXPORT LayerTreeHost : public NON_EXPORTED_BASE(SurfaceReferenceOwner),
bool in_paint_layer_contents_ = false;
bool in_update_property_trees_ = false;
+ // This is true if atleast one layer in the layer tree has a copy request. We
+ // use this bool to decide whether we need to compute subtree has copy request
+ // for every layer during property tree building.
+ bool has_copy_request_ = false;
+
MutatorHost* mutator_host_;
std::vector<std::pair<sk_sp<const SkImage>, base::Callback<void(bool)>>>
queued_image_decodes_;
- bool did_navigate_ = false;
-
DISALLOW_COPY_AND_ASSIGN(LayerTreeHost);
};
diff --git a/chromium/cc/trees/layer_tree_host_client.h b/chromium/cc/trees/layer_tree_host_client.h
index 84416d60ef0..f54a69b0217 100644
--- a/chromium/cc/trees/layer_tree_host_client.h
+++ b/chromium/cc/trees/layer_tree_host_client.h
@@ -8,6 +8,7 @@
#include <memory>
#include "base/memory/ref_counted.h"
+#include "base/time/time.h"
namespace gfx {
class Vector2dF;
@@ -24,6 +25,7 @@ class LayerTreeHostClient {
// mode, this corresponds to DidCommit().
virtual void BeginMainFrame(const BeginFrameArgs& args) = 0;
virtual void BeginMainFrameNotExpectedSoon() = 0;
+ virtual void BeginMainFrameNotExpectedUntil(base::TimeTicks time) = 0;
virtual void DidBeginMainFrame() = 0;
// A LayerTreeHost is bound to a LayerTreeHostClient. Visual frame-based
// updates to the state of the LayerTreeHost are expected to happen only in
diff --git a/chromium/cc/trees/layer_tree_host_common.cc b/chromium/cc/trees/layer_tree_host_common.cc
index 8d09c07ec1d..e289a34db08 100644
--- a/chromium/cc/trees/layer_tree_host_common.cc
+++ b/chromium/cc/trees/layer_tree_host_common.cc
@@ -20,6 +20,7 @@
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/property_tree_builder.h"
#include "cc/trees/scroll_node.h"
+#include "cc/trees/transform_node.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/vector2d_conversions.h"
#include "ui/gfx/transform.h"
@@ -77,10 +78,8 @@ LayerTreeHostCommon::CalcDrawPropsImplInputs::CalcDrawPropsImplInputs(
const gfx::Vector2dF& elastic_overscroll,
const LayerImpl* elastic_overscroll_application_layer,
int max_texture_size,
- bool can_render_to_separate_surface,
bool can_adjust_raster_scales,
- bool use_layer_lists,
- LayerImplList* render_surface_layer_list,
+ RenderSurfaceList* render_surface_list,
PropertyTrees* property_trees)
: root_layer(root_layer),
device_viewport_size(device_viewport_size),
@@ -94,10 +93,8 @@ LayerTreeHostCommon::CalcDrawPropsImplInputs::CalcDrawPropsImplInputs(
elastic_overscroll_application_layer(
elastic_overscroll_application_layer),
max_texture_size(max_texture_size),
- can_render_to_separate_surface(can_render_to_separate_surface),
can_adjust_raster_scales(can_adjust_raster_scales),
- use_layer_lists(use_layer_lists),
- render_surface_layer_list(render_surface_layer_list),
+ render_surface_list(render_surface_list),
property_trees(property_trees) {}
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting::
@@ -105,7 +102,7 @@ LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting::
const gfx::Size& device_viewport_size,
const gfx::Transform& device_transform,
float device_scale_factor,
- LayerImplList* render_surface_layer_list)
+ RenderSurfaceList* render_surface_list)
: CalcDrawPropsImplInputs(root_layer,
device_viewport_size,
device_transform,
@@ -117,46 +114,44 @@ LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting::
gfx::Vector2dF(),
NULL,
std::numeric_limits<int>::max() / 2,
- true,
false,
- false,
- render_surface_layer_list,
+ render_surface_list,
GetPropertyTrees(root_layer)) {
DCHECK(root_layer);
- DCHECK(render_surface_layer_list);
+ DCHECK(render_surface_list);
}
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting::
CalcDrawPropsImplInputsForTesting(LayerImpl* root_layer,
const gfx::Size& device_viewport_size,
const gfx::Transform& device_transform,
- LayerImplList* render_surface_layer_list)
+ RenderSurfaceList* render_surface_list)
: CalcDrawPropsImplInputsForTesting(root_layer,
device_viewport_size,
device_transform,
1.f,
- render_surface_layer_list) {}
+ render_surface_list) {}
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting::
CalcDrawPropsImplInputsForTesting(LayerImpl* root_layer,
const gfx::Size& device_viewport_size,
- LayerImplList* render_surface_layer_list)
+ RenderSurfaceList* render_surface_list)
: CalcDrawPropsImplInputsForTesting(root_layer,
device_viewport_size,
gfx::Transform(),
1.f,
- render_surface_layer_list) {}
+ render_surface_list) {}
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting::
CalcDrawPropsImplInputsForTesting(LayerImpl* root_layer,
const gfx::Size& device_viewport_size,
float device_scale_factor,
- LayerImplList* render_surface_layer_list)
+ RenderSurfaceList* render_surface_list)
: CalcDrawPropsImplInputsForTesting(root_layer,
device_viewport_size,
gfx::Transform(),
device_scale_factor,
- render_surface_layer_list) {}
+ render_surface_list) {}
LayerTreeHostCommon::ScrollUpdateInfo::ScrollUpdateInfo()
: layer_id(Layer::INVALID_ID) {}
@@ -167,15 +162,15 @@ bool LayerTreeHostCommon::ScrollUpdateInfo::operator==(
}
LayerTreeHostCommon::ScrollbarsUpdateInfo::ScrollbarsUpdateInfo()
- : layer_id(Layer::INVALID_ID), hidden(true) {}
+ : element_id(), hidden(true) {}
-LayerTreeHostCommon::ScrollbarsUpdateInfo::ScrollbarsUpdateInfo(int layer_id,
+LayerTreeHostCommon::ScrollbarsUpdateInfo::ScrollbarsUpdateInfo(ElementId id,
bool hidden)
- : layer_id(layer_id), hidden(hidden) {}
+ : element_id(id), hidden(hidden) {}
bool LayerTreeHostCommon::ScrollbarsUpdateInfo::operator==(
const LayerTreeHostCommon::ScrollbarsUpdateInfo& other) const {
- return layer_id == other.layer_id && hidden == other.hidden;
+ return element_id == other.element_id && hidden == other.hidden;
}
ScrollAndScaleSet::ScrollAndScaleSet()
@@ -186,28 +181,21 @@ ScrollAndScaleSet::ScrollAndScaleSet()
ScrollAndScaleSet::~ScrollAndScaleSet() {}
-static inline void SetMaskLayersAreDrawnRenderSurfaceLayerListMembers(
+static inline void SetMaskLayersContributeToDrawnRenderSurface(
RenderSurfaceImpl* surface,
PropertyTrees* property_trees) {
LayerImpl* mask_layer = surface->MaskLayer();
if (mask_layer) {
- mask_layer->set_is_drawn_render_surface_layer_list_member(true);
+ mask_layer->set_contributes_to_drawn_render_surface(true);
draw_property_utils::ComputeMaskDrawProperties(mask_layer, property_trees);
}
}
-static inline void ClearMaskLayersAreDrawnRenderSurfaceLayerListMembers(
+static inline void ClearMaskLayersContributeToDrawnRenderSurface(
RenderSurfaceImpl* surface) {
LayerImpl* mask_layer = surface->MaskLayer();
if (mask_layer)
- mask_layer->set_is_drawn_render_surface_layer_list_member(false);
-}
-
-static inline void ClearIsDrawnRenderSurfaceLayerListMember(
- LayerImplList* layer_list,
- ScrollTree* scroll_tree) {
- for (LayerImpl* layer : *layer_list)
- layer->set_is_drawn_render_surface_layer_list_member(false);
+ mask_layer->set_contributes_to_drawn_render_surface(false);
}
static bool CdpPerfTracingEnabled() {
@@ -280,86 +268,120 @@ enum PropertyTreeOption {
DONT_BUILD_PROPERTY_TREES
};
-static void ComputeInitialRenderSurfaceLayerList(
+static void AddSurfaceToRenderSurfaceList(
+ RenderSurfaceImpl* render_surface,
+ RenderSurfaceList* render_surface_list,
+ PropertyTrees* property_trees) {
+ // |render_surface| must appear after its target, so first make sure its
+ // target is in the list.
+ RenderSurfaceImpl* target = render_surface->render_target();
+ bool is_root =
+ render_surface->EffectTreeIndex() == EffectTree::kContentsRootNodeId;
+ if (!is_root && !target->is_render_surface_list_member()) {
+ AddSurfaceToRenderSurfaceList(target, render_surface_list, property_trees);
+ }
+ render_surface->ClearAccumulatedContentRect();
+ render_surface_list->push_back(render_surface);
+ render_surface->set_is_render_surface_list_member(true);
+ if (is_root) {
+ // The root surface does not contribute to any other surface, it has no
+ // target.
+ render_surface->set_contributes_to_drawn_surface(false);
+ } else {
+ bool contributes_to_drawn_surface =
+ property_trees->effect_tree.ContributesToDrawnSurface(
+ render_surface->EffectTreeIndex());
+ render_surface->set_contributes_to_drawn_surface(
+ contributes_to_drawn_surface);
+ }
+
+ draw_property_utils::ComputeSurfaceDrawProperties(property_trees,
+ render_surface);
+
+ // Ignore occlusion from outside the surface when surface contents need to be
+ // fully drawn. Layers with copy-request need to be complete. We could be
+ // smarter about layers with filters that move pixels and exclude regions
+ // where both layers and the filters are occluded, but this seems like
+ // overkill.
+ // TODO(senorblanco): make this smarter for the SkImageFilter case (check for
+ // pixel-moving filters)
+ const FilterOperations& filters = render_surface->Filters();
+ bool is_occlusion_immune = render_surface->HasCopyRequest() ||
+ filters.HasReferenceFilter() ||
+ filters.HasFilterThatMovesPixels();
+ if (is_occlusion_immune) {
+ render_surface->SetNearestOcclusionImmuneAncestor(render_surface);
+ } else if (is_root) {
+ render_surface->SetNearestOcclusionImmuneAncestor(nullptr);
+ } else {
+ render_surface->SetNearestOcclusionImmuneAncestor(
+ render_surface->render_target()->nearest_occlusion_immune_ancestor());
+ }
+}
+
+static bool SkipForInvertibility(const LayerImpl* layer,
+ PropertyTrees* property_trees) {
+ const TransformNode* transform_node =
+ property_trees->transform_tree.Node(layer->transform_tree_index());
+ const EffectNode* effect_node =
+ property_trees->effect_tree.Node(layer->effect_tree_index());
+ bool non_root_copy_request =
+ effect_node->closest_ancestor_with_copy_request_id >
+ EffectTree::kContentsRootNodeId;
+ gfx::Transform from_target;
+ // If there is a copy request, we check the invertibility of the transform
+ // between the node corresponding to the layer and the node corresponding to
+ // the copy request. Otherwise, we are interested in the invertibility of
+ // screen space transform which is already cached on the transform node.
+ return non_root_copy_request
+ ? !property_trees->GetFromTarget(
+ layer->transform_tree_index(),
+ effect_node->closest_ancestor_with_copy_request_id,
+ &from_target)
+ : !transform_node->ancestors_are_invertible;
+}
+
+static void ComputeInitialRenderSurfaceList(
LayerTreeImpl* layer_tree_impl,
PropertyTrees* property_trees,
- LayerImplList* render_surface_layer_list,
- bool can_render_to_separate_surface,
- bool use_layer_lists) {
- // Add all non-skipped surfaces to the initial render surface layer list. Add
- // all non-skipped layers to the layer list of their target surface, and
- // add their content rect to their target surface's accumulated content rect.
+ RenderSurfaceList* render_surface_list) {
+ EffectTree& effect_tree = property_trees->effect_tree;
+ for (int i = EffectTree::kContentsRootNodeId;
+ i < static_cast<int>(effect_tree.size()); ++i) {
+ if (RenderSurfaceImpl* render_surface = effect_tree.GetRenderSurface(i)) {
+ render_surface->set_is_render_surface_list_member(false);
+ render_surface->reset_num_contributors();
+ ClearMaskLayersContributeToDrawnRenderSurface(render_surface);
+ }
+ }
+
+ RenderSurfaceImpl* root_surface =
+ effect_tree.GetRenderSurface(EffectTree::kContentsRootNodeId);
+ // The root surface always gets added to the render surface list.
+ AddSurfaceToRenderSurfaceList(root_surface, render_surface_list,
+ property_trees);
+ // For all non-skipped layers, add their target to the render surface list if
+ // it's not already been added, and add their content rect to the target
+ // surface's accumulated content rect.
for (LayerImpl* layer : *layer_tree_impl) {
- DCHECK(layer);
+ layer->set_contributes_to_drawn_render_surface(false);
- // TODO(crbug.com/726423): LayerImpls should never have invalid PropertyTree
- // indices.
- if (!layer)
- continue;
+ bool is_root = layer_tree_impl->IsRootLayer(layer);
- layer->set_is_drawn_render_surface_layer_list_member(false);
- if (!layer->HasValidPropertyTreeIndices())
- continue;
+ bool skip_draw_properties_computation =
+ draw_property_utils::LayerShouldBeSkippedForDrawPropertiesComputation(
+ layer, property_trees->transform_tree, property_trees->effect_tree);
- RenderSurfaceImpl* render_surface = layer->GetRenderSurface();
- if (render_surface) {
- render_surface->ClearLayerLists();
- ClearMaskLayersAreDrawnRenderSurfaceLayerListMembers(render_surface);
- }
- layer->set_is_drawn_render_surface_layer_list_member(false);
+ bool skip_for_invertibility = SkipForInvertibility(layer, property_trees);
- bool is_root = layer_tree_impl->IsRootLayer(layer);
- bool skip_layer = !is_root && draw_property_utils::LayerShouldBeSkipped(
- layer, property_trees->transform_tree,
- property_trees->effect_tree);
+ bool skip_layer = !is_root && (skip_draw_properties_computation ||
+ skip_for_invertibility);
+
+ layer->set_raster_even_if_not_in_rsll(skip_for_invertibility &&
+ !skip_draw_properties_computation);
if (skip_layer)
continue;
- bool render_to_separate_surface =
- is_root || (can_render_to_separate_surface && render_surface);
-
- if (render_to_separate_surface) {
- DCHECK(render_surface);
- DCHECK(layer->render_target() == render_surface);
- render_surface->ClearAccumulatedContentRect();
- render_surface_layer_list->push_back(layer);
- if (is_root) {
- // The root surface does not contribute to any other surface, it has no
- // target.
- render_surface->set_contributes_to_drawn_surface(false);
- } else {
- render_surface->render_target()->layer_list().push_back(layer);
- bool contributes_to_drawn_surface =
- property_trees->effect_tree.ContributesToDrawnSurface(
- layer->effect_tree_index());
- render_surface->set_contributes_to_drawn_surface(
- contributes_to_drawn_surface);
- }
-
- draw_property_utils::ComputeSurfaceDrawProperties(
- property_trees, render_surface, use_layer_lists);
-
- // Ignore occlusion from outside the surface when surface contents need to
- // be fully drawn. Layers with copy-request need to be complete. We could
- // be smarter about layers with filters that move pixels and exclude
- // regions where both layers and the filters are occluded, but this seems
- // like overkill.
- // TODO(senorblanco): make this smarter for the SkImageFilter case (check
- // for pixel-moving filters)
- const FilterOperations& filters = render_surface->Filters();
- bool is_occlusion_immune = render_surface->HasCopyRequest() ||
- filters.HasReferenceFilter() ||
- filters.HasFilterThatMovesPixels();
- if (is_occlusion_immune) {
- render_surface->SetNearestOcclusionImmuneAncestor(render_surface);
- } else if (is_root) {
- render_surface->SetNearestOcclusionImmuneAncestor(nullptr);
- } else {
- render_surface->SetNearestOcclusionImmuneAncestor(
- render_surface->render_target()
- ->nearest_occlusion_immune_ancestor());
- }
- }
bool layer_is_drawn =
property_trees->effect_tree.Node(layer->effect_tree_index())->is_drawn;
bool layer_should_be_drawn = draw_property_utils::LayerNeedsUpdate(
@@ -367,24 +389,30 @@ static void ComputeInitialRenderSurfaceLayerList(
if (!layer_should_be_drawn)
continue;
- layer->set_is_drawn_render_surface_layer_list_member(true);
- layer->render_target()->layer_list().push_back(layer);
+ RenderSurfaceImpl* render_target = layer->render_target();
+ if (!render_target->is_render_surface_list_member()) {
+ AddSurfaceToRenderSurfaceList(render_target, render_surface_list,
+ property_trees);
+ }
+
+ layer->set_contributes_to_drawn_render_surface(true);
// The layer contributes its drawable content rect to its render target.
- layer->render_target()->AccumulateContentRectFromContributingLayer(layer);
+ render_target->AccumulateContentRectFromContributingLayer(layer);
+ render_target->increment_num_contributors();
}
}
static void ComputeSurfaceContentRects(LayerTreeImpl* layer_tree_impl,
PropertyTrees* property_trees,
- LayerImplList* render_surface_layer_list,
+ RenderSurfaceList* render_surface_list,
int max_texture_size) {
// Walk the list backwards, accumulating each surface's content rect into its
// target's content rect.
- for (LayerImpl* layer : base::Reversed(*render_surface_layer_list)) {
- RenderSurfaceImpl* render_surface = layer->GetRenderSurface();
- if (layer_tree_impl->IsRootLayer(layer)) {
- // The root layer's surface content rect is always the entire viewport.
+ for (RenderSurfaceImpl* render_surface :
+ base::Reversed(*render_surface_list)) {
+ if (render_surface->EffectTreeIndex() == EffectTree::kContentsRootNodeId) {
+ // The root surface's content rect is always the entire viewport.
render_surface->SetContentRectToViewport();
continue;
}
@@ -396,82 +424,74 @@ static void ComputeSurfaceContentRects(LayerTreeImpl* layer_tree_impl,
// Now the render surface's content rect is calculated correctly, it could
// contribute to its render target.
- render_surface->render_target()
- ->AccumulateContentRectFromContributingRenderSurface(render_surface);
+ RenderSurfaceImpl* render_target = render_surface->render_target();
+ DCHECK(render_target->is_render_surface_list_member());
+ render_target->AccumulateContentRectFromContributingRenderSurface(
+ render_surface);
+ render_target->increment_num_contributors();
}
}
-static void ComputeListOfNonEmptySurfaces(LayerTreeImpl* layer_tree_impl,
- PropertyTrees* property_trees,
- LayerImplList* initial_surface_list,
- LayerImplList* final_surface_list) {
+static void ComputeListOfNonEmptySurfaces(
+ LayerTreeImpl* layer_tree_impl,
+ PropertyTrees* property_trees,
+ RenderSurfaceList* initial_surface_list,
+ RenderSurfaceList* final_surface_list) {
// Walk the initial surface list forwards. The root surface and each
// surface with a non-empty content rect go into the final render surface
// layer list. Surfaces with empty content rects or whose target isn't in
// the final list do not get added to the final list.
- for (LayerImpl* layer : *initial_surface_list) {
- bool is_root = layer_tree_impl->IsRootLayer(layer);
- RenderSurfaceImpl* surface = layer->GetRenderSurface();
+ bool removed_surface = false;
+ for (RenderSurfaceImpl* surface : *initial_surface_list) {
+ bool is_root =
+ surface->EffectTreeIndex() == EffectTree::kContentsRootNodeId;
RenderSurfaceImpl* target_surface = surface->render_target();
if (!is_root && (surface->content_rect().IsEmpty() ||
- target_surface->layer_list().empty())) {
- ClearIsDrawnRenderSurfaceLayerListMember(&surface->layer_list(),
- &property_trees->scroll_tree);
- surface->ClearLayerLists();
- if (!is_root) {
- LayerImplList& target_list = target_surface->layer_list();
- auto it = std::find(target_list.begin(), target_list.end(), layer);
- if (it != target_list.end()) {
- target_list.erase(it);
- // This surface has an empty content rect. If its target's layer list
- // had no other layers, then its target would also have had an empty
- // content rect, meaning it would have been removed and had its layer
- // list cleared when we visited it, unless the target surface is the
- // root surface.
- DCHECK(!target_surface->layer_list().empty() ||
- target_surface->render_target() == target_surface);
- } else {
- // This layer was removed when the target itself was cleared.
- DCHECK(target_surface->layer_list().empty());
+ !target_surface->is_render_surface_list_member())) {
+ surface->set_is_render_surface_list_member(false);
+ removed_surface = true;
+ target_surface->decrement_num_contributors();
+ continue;
+ }
+ SetMaskLayersContributeToDrawnRenderSurface(surface, property_trees);
+ final_surface_list->push_back(surface);
+ }
+ if (removed_surface) {
+ for (LayerImpl* layer : *layer_tree_impl) {
+ if (layer->contributes_to_drawn_render_surface()) {
+ RenderSurfaceImpl* render_target = layer->render_target();
+ if (!render_target->is_render_surface_list_member()) {
+ layer->set_contributes_to_drawn_render_surface(false);
+ render_target->decrement_num_contributors();
}
}
- continue;
}
- SetMaskLayersAreDrawnRenderSurfaceLayerListMembers(surface, property_trees);
- final_surface_list->push_back(layer);
}
}
static void CalculateRenderSurfaceLayerList(
LayerTreeImpl* layer_tree_impl,
PropertyTrees* property_trees,
- LayerImplList* render_surface_layer_list,
- const bool can_render_to_separate_surface,
- const bool use_layer_lists,
+ RenderSurfaceList* render_surface_list,
const int max_texture_size) {
- // This calculates top level Render Surface Layer List, and Layer List for all
- // Render Surfaces.
- // |render_surface_layer_list| is the top level RenderSurfaceLayerList.
+ RenderSurfaceList initial_render_surface_list;
- LayerImplList initial_render_surface_list;
-
- // First compute an RSLL that might include surfaces that later turn out to
+ // First compute a list that might include surfaces that later turn out to
// have an empty content rect. After surface content rects are computed,
- // produce a final RSLL that omits empty surfaces.
- ComputeInitialRenderSurfaceLayerList(
- layer_tree_impl, property_trees, &initial_render_surface_list,
- can_render_to_separate_surface, use_layer_lists);
+ // produce a final list that omits empty surfaces.
+ ComputeInitialRenderSurfaceList(layer_tree_impl, property_trees,
+ &initial_render_surface_list);
ComputeSurfaceContentRects(layer_tree_impl, property_trees,
&initial_render_surface_list, max_texture_size);
ComputeListOfNonEmptySurfaces(layer_tree_impl, property_trees,
&initial_render_surface_list,
- render_surface_layer_list);
+ render_surface_list);
}
void CalculateDrawPropertiesInternal(
LayerTreeHostCommon::CalcDrawPropsImplInputs* inputs,
PropertyTreeOption property_tree_option) {
- inputs->render_surface_layer_list->clear();
+ inputs->render_surface_list->clear();
const bool should_measure_property_tree_performance =
property_tree_option == BUILD_PROPERTY_TREES_IF_NEEDED;
@@ -498,7 +518,6 @@ void CalculateDrawPropertiesInternal(
inputs->device_transform, inputs->property_trees);
draw_property_utils::UpdatePropertyTreesAndRenderSurfaces(
inputs->root_layer, inputs->property_trees,
- inputs->can_render_to_separate_surface,
inputs->can_adjust_raster_scales);
// Property trees are normally constructed on the main thread and
@@ -545,7 +564,6 @@ void CalculateDrawPropertiesInternal(
inputs->device_transform, inputs->root_layer->position());
draw_property_utils::UpdatePropertyTreesAndRenderSurfaces(
inputs->root_layer, inputs->property_trees,
- inputs->can_render_to_separate_surface,
inputs->can_adjust_raster_scales);
break;
}
@@ -559,15 +577,12 @@ void CalculateDrawPropertiesInternal(
draw_property_utils::FindLayersThatNeedUpdates(
inputs->root_layer->layer_tree_impl(), inputs->property_trees,
&visible_layer_list);
- DCHECK(inputs->can_render_to_separate_surface ==
- inputs->property_trees->non_root_surfaces_enabled);
draw_property_utils::ComputeDrawPropertiesOfVisibleLayers(
&visible_layer_list, inputs->property_trees);
CalculateRenderSurfaceLayerList(
inputs->root_layer->layer_tree_impl(), inputs->property_trees,
- inputs->render_surface_layer_list, inputs->can_render_to_separate_surface,
- inputs->use_layer_lists, inputs->max_texture_size);
+ inputs->render_surface_list, inputs->max_texture_size);
if (should_measure_property_tree_performance) {
TRACE_EVENT_END0(TRACE_DISABLED_BY_DEFAULT("cc.debug.cdp-perf"),
@@ -576,13 +591,13 @@ void CalculateDrawPropertiesInternal(
// A root layer render_surface should always exist after
// CalculateDrawProperties.
- DCHECK(inputs->root_layer->GetRenderSurface());
+ DCHECK(inputs->property_trees->effect_tree.GetRenderSurface(
+ EffectTree::kContentsRootNodeId));
}
void LayerTreeHostCommon::CalculateDrawPropertiesForTesting(
CalcDrawPropsMainInputsForTesting* inputs) {
LayerList update_layer_list;
- bool can_render_to_separate_surface = true;
PropertyTrees* property_trees =
inputs->root_layer->layer_tree_host()->property_trees();
Layer* overscroll_elasticity_layer = nullptr;
@@ -595,8 +610,7 @@ void LayerTreeHostCommon::CalculateDrawPropertiesForTesting(
gfx::Rect(inputs->device_viewport_size), inputs->device_transform,
property_trees);
draw_property_utils::UpdatePropertyTrees(
- inputs->root_layer->layer_tree_host(), property_trees,
- can_render_to_separate_surface);
+ inputs->root_layer->layer_tree_host(), property_trees);
draw_property_utils::FindLayersThatNeedUpdates(
inputs->root_layer->layer_tree_host(), property_trees,
&update_layer_list);
diff --git a/chromium/cc/trees/layer_tree_host_common.h b/chromium/cc/trees/layer_tree_host_common.h
index dd668caa88e..522ef93c050 100644
--- a/chromium/cc/trees/layer_tree_host_common.h
+++ b/chromium/cc/trees/layer_tree_host_common.h
@@ -72,10 +72,8 @@ class CC_EXPORT LayerTreeHostCommon {
const gfx::Vector2dF& elastic_overscroll,
const LayerImpl* elastic_overscroll_application_layer,
int max_texture_size,
- bool can_render_to_separate_surface,
bool can_adjust_raster_scales,
- bool use_layer_lists,
- LayerImplList* render_surface_layer_list,
+ RenderSurfaceList* render_surface_list,
PropertyTrees* property_trees);
LayerImpl* root_layer;
@@ -89,10 +87,8 @@ class CC_EXPORT LayerTreeHostCommon {
gfx::Vector2dF elastic_overscroll;
const LayerImpl* elastic_overscroll_application_layer;
int max_texture_size;
- bool can_render_to_separate_surface;
bool can_adjust_raster_scales;
- bool use_layer_lists;
- LayerImplList* render_surface_layer_list;
+ RenderSurfaceList* render_surface_list;
PropertyTrees* property_trees;
};
@@ -102,18 +98,18 @@ class CC_EXPORT LayerTreeHostCommon {
const gfx::Size& device_viewport_size,
const gfx::Transform& device_transform,
float device_scale_factor,
- LayerImplList* render_surface_layer_list);
+ RenderSurfaceList* render_surface_list);
CalcDrawPropsImplInputsForTesting(LayerImpl* root_layer,
const gfx::Size& device_viewport_size,
const gfx::Transform& device_transform,
- LayerImplList* render_surface_layer_list);
+ RenderSurfaceList* render_surface_list);
CalcDrawPropsImplInputsForTesting(LayerImpl* root_layer,
const gfx::Size& device_viewport_size,
- LayerImplList* render_surface_layer_list);
+ RenderSurfaceList* render_surface_list);
CalcDrawPropsImplInputsForTesting(LayerImpl* root_layer,
const gfx::Size& device_viewport_size,
float device_scale_factor,
- LayerImplList* render_surface_layer_list);
+ RenderSurfaceList* render_surface_list);
};
static int CalculateLayerJitter(LayerImpl* scrolling_layer);
@@ -149,11 +145,11 @@ class CC_EXPORT LayerTreeHostCommon {
// to be told when they're faded out so it can stop handling input for
// invisible scrollbars.
struct CC_EXPORT ScrollbarsUpdateInfo {
- int layer_id;
+ ElementId element_id;
bool hidden;
ScrollbarsUpdateInfo();
- ScrollbarsUpdateInfo(int layer_id, bool hidden);
+ ScrollbarsUpdateInfo(ElementId element_id, bool hidden);
bool operator==(const ScrollbarsUpdateInfo& other) const;
};
diff --git a/chromium/cc/trees/layer_tree_host_common_perftest.cc b/chromium/cc/trees/layer_tree_host_common_perftest.cc
index 89946eea48a..c0b1e3254d2 100644
--- a/chromium/cc/trees/layer_tree_host_common_perftest.cc
+++ b/chromium/cc/trees/layer_tree_host_common_perftest.cc
@@ -86,12 +86,8 @@ class CalcDrawPropsTest : public LayerTreeHostCommonPerfTest {
LayerTreeImpl* active_tree = host_impl->active_tree();
do {
- bool can_render_to_separate_surface = true;
int max_texture_size = 8096;
- DoCalcDrawPropertiesImpl(can_render_to_separate_surface,
- max_texture_size,
- active_tree,
- host_impl);
+ DoCalcDrawPropertiesImpl(max_texture_size, active_tree, host_impl);
timer_.NextLap();
} while (!timer_.HasTimeLimitExpired());
@@ -99,22 +95,20 @@ class CalcDrawPropsTest : public LayerTreeHostCommonPerfTest {
EndTest();
}
- void DoCalcDrawPropertiesImpl(bool can_render_to_separate_surface,
- int max_texture_size,
+ void DoCalcDrawPropertiesImpl(int max_texture_size,
LayerTreeImpl* active_tree,
LayerTreeHostImpl* host_impl) {
- LayerImplList update_list;
+ RenderSurfaceList update_list;
LayerTreeHostCommon::CalcDrawPropsImplInputs inputs(
- active_tree->root_layer_for_testing(), active_tree->DrawViewportSize(),
- host_impl->DrawTransform(), active_tree->device_scale_factor(),
+ active_tree->root_layer_for_testing(),
+ active_tree->DeviceViewport().size(), host_impl->DrawTransform(),
+ active_tree->device_scale_factor(),
active_tree->current_page_scale_factor(),
active_tree->InnerViewportContainerLayer(),
active_tree->InnerViewportScrollLayer(),
active_tree->OuterViewportScrollLayer(),
active_tree->elastic_overscroll()->Current(active_tree->IsActiveTree()),
active_tree->OverscrollElasticityLayer(), max_texture_size,
- can_render_to_separate_surface,
- false, // don't use layer lists for perf tests
host_impl->settings().layer_transforms_should_scale_layer_contents,
&update_list, active_tree->property_trees());
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
diff --git a/chromium/cc/trees/layer_tree_host_common_unittest.cc b/chromium/cc/trees/layer_tree_host_common_unittest.cc
index e6f69f6dd99..a26ee7f4559 100644
--- a/chromium/cc/trees/layer_tree_host_common_unittest.cc
+++ b/chromium/cc/trees/layer_tree_host_common_unittest.cc
@@ -42,7 +42,6 @@
#include "cc/trees/clip_node.h"
#include "cc/trees/draw_property_utils.h"
#include "cc/trees/effect_node.h"
-#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/property_tree_builder.h"
#include "cc/trees/scroll_node.h"
#include "cc/trees/single_thread_proxy.h"
@@ -139,14 +138,13 @@ class LayerTreeHostCommonTestBase : public LayerTestCommon::LayerImplTest {
gfx::Size(root_layer->bounds().width() * device_scale_factor,
root_layer->bounds().height() * device_scale_factor);
- render_surface_layer_list_impl_.reset(new LayerImplList);
+ render_surface_list_impl_.reset(new RenderSurfaceList);
// We are probably not testing what is intended if the root_layer bounds are
// empty.
DCHECK(!root_layer->bounds().IsEmpty());
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root_layer, device_viewport_size,
- render_surface_layer_list_impl_.get());
+ root_layer, device_viewport_size, render_surface_list_impl_.get());
inputs.device_scale_factor = device_scale_factor;
inputs.page_scale_factor = page_scale_factor;
inputs.page_scale_layer = page_scale_layer;
@@ -182,8 +180,6 @@ class LayerTreeHostCommonTestBase : public LayerTestCommon::LayerImplTest {
void ExecuteCalculateDrawPropertiesAndSaveUpdateLayerList(Layer* root_layer) {
DCHECK(root_layer->layer_tree_host());
- bool can_render_to_separate_surface = true;
-
const Layer* page_scale_layer =
root_layer->layer_tree_host()->page_scale_layer();
Layer* inner_viewport_scroll_layer =
@@ -208,8 +204,7 @@ class LayerTreeHostCommonTestBase : public LayerTestCommon::LayerImplTest {
elastic_overscroll, page_scale_factor, device_scale_factor,
gfx::Rect(device_viewport_size), gfx::Transform(), property_trees);
draw_property_utils::UpdatePropertyTrees(root_layer->layer_tree_host(),
- property_trees,
- can_render_to_separate_surface);
+ property_trees);
draw_property_utils::FindLayersThatNeedUpdates(
root_layer->layer_tree_host(), property_trees, &update_layer_list_);
}
@@ -217,7 +212,6 @@ class LayerTreeHostCommonTestBase : public LayerTestCommon::LayerImplTest {
void ExecuteCalculateDrawPropertiesAndSaveUpdateLayerList(
LayerImpl* root_layer) {
DCHECK(root_layer->layer_tree_impl());
- bool can_render_to_separate_surface = true;
bool can_adjust_raster_scales = true;
const LayerImpl* page_scale_layer = nullptr;
@@ -245,8 +239,7 @@ class LayerTreeHostCommonTestBase : public LayerTestCommon::LayerImplTest {
elastic_overscroll, page_scale_factor, device_scale_factor,
gfx::Rect(device_viewport_size), gfx::Transform(), property_trees);
draw_property_utils::UpdatePropertyTreesAndRenderSurfaces(
- root_layer, property_trees, can_render_to_separate_surface,
- can_adjust_raster_scales);
+ root_layer, property_trees, can_adjust_raster_scales);
draw_property_utils::FindLayersThatNeedUpdates(
root_layer->layer_tree_impl(), property_trees,
update_layer_list_impl_.get());
@@ -258,14 +251,12 @@ class LayerTreeHostCommonTestBase : public LayerTestCommon::LayerImplTest {
LayerImpl* root_layer) {
gfx::Size device_viewport_size =
gfx::Size(root_layer->bounds().width(), root_layer->bounds().height());
- render_surface_layer_list_impl_.reset(new LayerImplList);
+ render_surface_list_impl_.reset(new RenderSurfaceList);
DCHECK(!root_layer->bounds().IsEmpty());
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root_layer, device_viewport_size,
- render_surface_layer_list_impl_.get());
+ root_layer, device_viewport_size, render_surface_list_impl_.get());
inputs.can_adjust_raster_scales = true;
- inputs.can_render_to_separate_surface = false;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
}
@@ -274,13 +265,11 @@ class LayerTreeHostCommonTestBase : public LayerTestCommon::LayerImplTest {
LayerImpl* root_layer) {
gfx::Size device_viewport_size =
gfx::Size(root_layer->bounds().width(), root_layer->bounds().height());
- render_surface_layer_list_impl_.reset(new LayerImplList);
+ render_surface_list_impl_.reset(new RenderSurfaceList);
DCHECK(!root_layer->bounds().IsEmpty());
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root_layer, device_viewport_size,
- render_surface_layer_list_impl_.get());
- inputs.can_render_to_separate_surface = true;
+ root_layer, device_viewport_size, render_surface_list_impl_.get());
inputs.can_adjust_raster_scales = false;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
@@ -302,8 +291,8 @@ class LayerTreeHostCommonTestBase : public LayerTestCommon::LayerImplTest {
return false;
}
- const LayerImplList* render_surface_layer_list_impl() const {
- return render_surface_layer_list_impl_.get();
+ const RenderSurfaceList* render_surface_list_impl() const {
+ return render_surface_list_impl_.get();
}
const LayerImplList* update_layer_list_impl() const {
return update_layer_list_impl_.get();
@@ -317,7 +306,7 @@ class LayerTreeHostCommonTestBase : public LayerTestCommon::LayerImplTest {
}
private:
- std::unique_ptr<std::vector<LayerImpl*>> render_surface_layer_list_impl_;
+ std::unique_ptr<RenderSurfaceList> render_surface_list_impl_;
LayerList update_layer_list_;
std::unique_ptr<LayerImplList> update_layer_list_impl_;
};
@@ -613,9 +602,10 @@ TEST_F(LayerTreeHostCommonTest, TransformsAboutScrollOffset) {
// Test that page scale is updated even when we don't rebuild property trees.
page_scale = 1.888f;
- root_layer->layer_tree_impl()->SetViewportLayersFromIds(
- Layer::INVALID_ID, scroll_layer->test_properties()->parent->id(),
- Layer::INVALID_ID, Layer::INVALID_ID);
+
+ LayerTreeImpl::ViewportLayerIds viewport_ids;
+ viewport_ids.page_scale = scroll_layer->test_properties()->parent->id();
+ root_layer->layer_tree_impl()->SetViewportLayersFromIds(viewport_ids);
root_layer->layer_tree_impl()->SetPageScaleOnActiveTree(page_scale);
EXPECT_FALSE(root_layer->layer_tree_impl()->property_trees()->needs_rebuild);
ExecuteCalculateDrawProperties(root_layer, kDeviceScale, page_scale,
@@ -750,8 +740,8 @@ TEST_F(LayerTreeHostCommonTest, TransformsForSingleRenderSurface) {
ExecuteCalculateDrawProperties(root);
// Render surface should have been created now.
- ASSERT_TRUE(child->GetRenderSurface());
- ASSERT_EQ(child->GetRenderSurface(), child->render_target());
+ ASSERT_TRUE(GetRenderSurface(child));
+ ASSERT_EQ(GetRenderSurface(child), child->render_target());
// The child layer's draw transform should refer to its new render surface.
// The screen-space transform, however, should still refer to the root.
@@ -773,54 +763,6 @@ TEST_F(LayerTreeHostCommonTest, TransformsForSingleRenderSurface) {
child->render_target()->screen_space_transform());
}
-TEST_F(LayerTreeHostCommonTest, TransformsWhenCannotRenderToSeparateSurface) {
- LayerImpl* root = root_layer_for_testing();
- LayerImpl* parent = AddChildToRoot<LayerImpl>();
- LayerImpl* child = AddChild<LayerImpl>(parent);
- LayerImpl* grand_child = AddChild<LayerImpl>(child);
-
- gfx::Transform parent_transform;
- parent_transform.Translate(10.0, 10.0);
-
- gfx::Transform child_transform;
- child_transform.Rotate(45.0);
-
- root->SetBounds(gfx::Size(100, 100));
- parent->test_properties()->transform = parent_transform;
- parent->SetBounds(gfx::Size(10, 10));
- child->test_properties()->transform = child_transform;
- child->SetBounds(gfx::Size(10, 10));
- child->test_properties()->force_render_surface = true;
- grand_child->SetPosition(gfx::PointF(2.f, 2.f));
- grand_child->SetBounds(gfx::Size(20, 20));
- grand_child->SetDrawsContent(true);
-
- gfx::Transform expected_grand_child_screen_space_transform;
- expected_grand_child_screen_space_transform.Translate(10.0, 10.0);
- expected_grand_child_screen_space_transform.Rotate(45.0);
- expected_grand_child_screen_space_transform.Translate(2.0, 2.0);
-
- // First compute draw properties with separate surfaces enabled.
- ExecuteCalculateDrawProperties(root);
-
- // The grand child's draw transform should be its offset wrt the child.
- gfx::Transform expected_grand_child_draw_transform;
- expected_grand_child_draw_transform.Translate(2.0, 2.0);
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected_grand_child_draw_transform,
- grand_child->DrawTransform());
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected_grand_child_screen_space_transform,
- grand_child->ScreenSpaceTransform());
-
- ExecuteCalculateDrawPropertiesWithoutSeparateSurfaces(root);
-
- // With separate surfaces disabled, the grand child's draw transform should be
- // the same as its screen space transform.
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected_grand_child_screen_space_transform,
- grand_child->DrawTransform());
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected_grand_child_screen_space_transform,
- grand_child->ScreenSpaceTransform());
-}
-
TEST_F(LayerTreeHostCommonTest, TransformsForRenderSurfaceHierarchy) {
// This test creates a more complex tree and verifies it all at once. This
// covers the following cases:
@@ -935,33 +877,37 @@ TEST_F(LayerTreeHostCommonTest, TransformsForRenderSurfaceHierarchy) {
// Only layers that are associated with render surfaces should have an actual
// RenderSurface() value.
- ASSERT_TRUE(root->GetRenderSurface());
- ASSERT_FALSE(child_of_root->GetRenderSurface());
- ASSERT_FALSE(grand_child_of_root->GetRenderSurface());
-
- ASSERT_TRUE(render_surface1->GetRenderSurface());
- ASSERT_FALSE(child_of_rs1->GetRenderSurface());
- ASSERT_FALSE(grand_child_of_rs1->GetRenderSurface());
-
- ASSERT_TRUE(render_surface2->GetRenderSurface());
- ASSERT_FALSE(child_of_rs2->GetRenderSurface());
- ASSERT_FALSE(grand_child_of_rs2->GetRenderSurface());
+ ASSERT_TRUE(GetRenderSurface(root));
+ ASSERT_EQ(GetRenderSurface(child_of_root), GetRenderSurface(root));
+ ASSERT_EQ(GetRenderSurface(grand_child_of_root), GetRenderSurface(root));
+
+ ASSERT_NE(GetRenderSurface(render_surface1), GetRenderSurface(root));
+ ASSERT_EQ(GetRenderSurface(child_of_rs1), GetRenderSurface(render_surface1));
+ ASSERT_EQ(GetRenderSurface(grand_child_of_rs1),
+ GetRenderSurface(render_surface1));
+
+ ASSERT_NE(GetRenderSurface(render_surface2), GetRenderSurface(root));
+ ASSERT_NE(GetRenderSurface(render_surface2),
+ GetRenderSurface(render_surface1));
+ ASSERT_EQ(GetRenderSurface(child_of_rs2), GetRenderSurface(render_surface2));
+ ASSERT_EQ(GetRenderSurface(grand_child_of_rs2),
+ GetRenderSurface(render_surface2));
// Verify all render target accessors
- EXPECT_EQ(root->GetRenderSurface(), parent->render_target());
- EXPECT_EQ(root->GetRenderSurface(), child_of_root->render_target());
- EXPECT_EQ(root->GetRenderSurface(), grand_child_of_root->render_target());
+ EXPECT_EQ(GetRenderSurface(root), parent->render_target());
+ EXPECT_EQ(GetRenderSurface(root), child_of_root->render_target());
+ EXPECT_EQ(GetRenderSurface(root), grand_child_of_root->render_target());
- EXPECT_EQ(render_surface1->GetRenderSurface(),
+ EXPECT_EQ(GetRenderSurface(render_surface1),
render_surface1->render_target());
- EXPECT_EQ(render_surface1->GetRenderSurface(), child_of_rs1->render_target());
- EXPECT_EQ(render_surface1->GetRenderSurface(),
+ EXPECT_EQ(GetRenderSurface(render_surface1), child_of_rs1->render_target());
+ EXPECT_EQ(GetRenderSurface(render_surface1),
grand_child_of_rs1->render_target());
- EXPECT_EQ(render_surface2->GetRenderSurface(),
+ EXPECT_EQ(GetRenderSurface(render_surface2),
render_surface2->render_target());
- EXPECT_EQ(render_surface2->GetRenderSurface(), child_of_rs2->render_target());
- EXPECT_EQ(render_surface2->GetRenderSurface(),
+ EXPECT_EQ(GetRenderSurface(render_surface2), child_of_rs2->render_target());
+ EXPECT_EQ(GetRenderSurface(render_surface2),
grand_child_of_rs2->render_target());
// Verify layer draw transforms note that draw transforms are described with
@@ -1007,17 +953,16 @@ TEST_F(LayerTreeHostCommonTest, TransformsForRenderSurfaceHierarchy) {
//
// Draw transform of render surface 1 is described with respect to root.
EXPECT_TRANSFORMATION_MATRIX_EQ(
- A * A * S1, render_surface1->GetRenderSurface()->draw_transform());
+ A * A * S1, GetRenderSurface(render_surface1)->draw_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(
- A * A * S1,
- render_surface1->GetRenderSurface()->screen_space_transform());
+ A * A * S1, GetRenderSurface(render_surface1)->screen_space_transform());
// Draw transform of render surface 2 is described with respect to render
// surface 1.
EXPECT_TRANSFORMATION_MATRIX_EQ(
- SS1 * A * S2, render_surface2->GetRenderSurface()->draw_transform());
+ SS1 * A * S2, GetRenderSurface(render_surface2)->draw_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(
A * A * A * S2,
- render_surface2->GetRenderSurface()->screen_space_transform());
+ GetRenderSurface(render_surface2)->screen_space_transform());
// Sanity check. If these fail there is probably a bug in the test itself. It
// is expected that we correctly set up transforms so that the y-component of
@@ -1088,12 +1033,12 @@ TEST_F(LayerTreeHostCommonTest, TransformsForFlatteningLayer) {
ExecuteCalculateDrawProperties(root);
// The child's draw transform should have been taken by its surface.
- ASSERT_TRUE(child->GetRenderSurface());
+ ASSERT_TRUE(GetRenderSurface(child));
EXPECT_TRANSFORMATION_MATRIX_EQ(expected_child_draw_transform,
- child->GetRenderSurface()->draw_transform());
+ GetRenderSurface(child)->draw_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(
expected_child_screen_space_transform,
- child->GetRenderSurface()->screen_space_transform());
+ GetRenderSurface(child)->screen_space_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(gfx::Transform(), child->DrawTransform());
EXPECT_TRANSFORMATION_MATRIX_EQ(expected_child_screen_space_transform,
child->ScreenSpaceTransform());
@@ -1169,10 +1114,10 @@ TEST_F(LayerTreeHostCommonTest, TransformsForDegenerateIntermediateLayer) {
grand_child->SetBounds(gfx::Size(10, 10));
ExecuteCalculateDrawProperties(root);
- ASSERT_TRUE(child->GetRenderSurface());
+ ASSERT_TRUE(GetRenderSurface(child));
// This is the real test, the rest are sanity checks.
EXPECT_TRANSFORMATION_MATRIX_EQ(gfx::Transform(),
- child->GetRenderSurface()->draw_transform());
+ GetRenderSurface(child)->draw_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(gfx::Transform(), child->DrawTransform());
EXPECT_TRANSFORMATION_MATRIX_EQ(gfx::Transform(),
grand_child->DrawTransform());
@@ -1199,9 +1144,9 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceWithSublayerScale) {
// render_surface will have a sublayer scale because of device scale factor.
float device_scale_factor = 2.0f;
- LayerImplList render_surface_layer_list_impl;
+ RenderSurfaceList render_surface_list_impl;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root, root->bounds(), translate, &render_surface_layer_list_impl);
+ root, root->bounds(), translate, &render_surface_list_impl);
inputs.device_scale_factor = device_scale_factor;
inputs.property_trees->needs_rebuild = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
@@ -1229,9 +1174,9 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) {
gfx::Transform translate;
translate.Translate(50, 50);
{
- LayerImplList render_surface_layer_list_impl;
+ RenderSurfaceList render_surface_list_impl;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root, root->bounds(), translate, &render_surface_layer_list_impl);
+ root, root->bounds(), translate, &render_surface_list_impl);
inputs.property_trees->needs_rebuild = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
EXPECT_TRANSFORMATION_MATRIX_EQ(
@@ -1239,7 +1184,7 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) {
EXPECT_TRANSFORMATION_MATRIX_EQ(
translate, child->draw_properties().target_space_transform);
EXPECT_TRANSFORMATION_MATRIX_EQ(gfx::Transform(),
- root->GetRenderSurface()->draw_transform());
+ GetRenderSurface(root)->draw_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(translate, child->ScreenSpaceTransform());
EXPECT_EQ(gfx::Rect(50, 50, 100, 100), child->clip_rect());
}
@@ -1247,9 +1192,9 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) {
gfx::Transform scale;
scale.Scale(2, 2);
{
- LayerImplList render_surface_layer_list_impl;
+ RenderSurfaceList render_surface_list_impl;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root, root->bounds(), scale, &render_surface_layer_list_impl);
+ root, root->bounds(), scale, &render_surface_list_impl);
inputs.property_trees->needs_rebuild = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
EXPECT_TRANSFORMATION_MATRIX_EQ(
@@ -1257,7 +1202,7 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) {
EXPECT_TRANSFORMATION_MATRIX_EQ(
scale, child->draw_properties().target_space_transform);
EXPECT_TRANSFORMATION_MATRIX_EQ(gfx::Transform(),
- root->GetRenderSurface()->draw_transform());
+ GetRenderSurface(root)->draw_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(scale, child->ScreenSpaceTransform());
EXPECT_EQ(gfx::Rect(0, 0, 200, 200), child->clip_rect());
}
@@ -1265,9 +1210,9 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) {
gfx::Transform rotate;
rotate.Rotate(2);
{
- LayerImplList render_surface_layer_list_impl;
+ RenderSurfaceList render_surface_list_impl;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root, root->bounds(), rotate, &render_surface_layer_list_impl);
+ root, root->bounds(), rotate, &render_surface_list_impl);
inputs.property_trees->needs_rebuild = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
EXPECT_TRANSFORMATION_MATRIX_EQ(
@@ -1275,7 +1220,7 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) {
EXPECT_TRANSFORMATION_MATRIX_EQ(
rotate, child->draw_properties().target_space_transform);
EXPECT_TRANSFORMATION_MATRIX_EQ(gfx::Transform(),
- root->GetRenderSurface()->draw_transform());
+ GetRenderSurface(root)->draw_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(rotate, child->ScreenSpaceTransform());
EXPECT_EQ(gfx::Rect(-4, 0, 104, 104), child->clip_rect());
}
@@ -1285,9 +1230,9 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) {
composite.ConcatTransform(scale);
composite.ConcatTransform(rotate);
{
- LayerImplList render_surface_layer_list_impl;
+ RenderSurfaceList render_surface_list_impl;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root, root->bounds(), composite, &render_surface_layer_list_impl);
+ root, root->bounds(), composite, &render_surface_list_impl);
inputs.property_trees->needs_rebuild = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
EXPECT_TRANSFORMATION_MATRIX_EQ(
@@ -1295,7 +1240,7 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) {
EXPECT_TRANSFORMATION_MATRIX_EQ(
composite, child->draw_properties().target_space_transform);
EXPECT_TRANSFORMATION_MATRIX_EQ(gfx::Transform(),
- root->GetRenderSurface()->draw_transform());
+ GetRenderSurface(root)->draw_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(composite, child->ScreenSpaceTransform());
EXPECT_EQ(gfx::Rect(89, 103, 208, 208), child->clip_rect());
}
@@ -1304,9 +1249,9 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) {
float device_scale_factor = 1.5f;
{
- LayerImplList render_surface_layer_list_impl;
+ RenderSurfaceList render_surface_list_impl;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root, root->bounds(), translate, &render_surface_layer_list_impl);
+ root, root->bounds(), translate, &render_surface_list_impl);
inputs.device_scale_factor = device_scale_factor;
inputs.property_trees->needs_rebuild = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
@@ -1319,7 +1264,7 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) {
device_scaled_translate,
child->draw_properties().target_space_transform);
EXPECT_TRANSFORMATION_MATRIX_EQ(gfx::Transform(),
- root->GetRenderSurface()->draw_transform());
+ GetRenderSurface(root)->draw_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(device_scaled_translate,
child->ScreenSpaceTransform());
EXPECT_EQ(gfx::Rect(50, 50, 150, 150), child->clip_rect());
@@ -1329,9 +1274,9 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) {
float page_scale_factor = 2.f;
{
- LayerImplList render_surface_layer_list_impl;
+ RenderSurfaceList render_surface_list_impl;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root, root->bounds(), translate, &render_surface_layer_list_impl);
+ root, root->bounds(), translate, &render_surface_list_impl);
inputs.page_scale_factor = page_scale_factor;
inputs.page_scale_layer = root;
inputs.property_trees->needs_rebuild = true;
@@ -1343,7 +1288,7 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) {
EXPECT_TRANSFORMATION_MATRIX_EQ(
page_scaled_translate, child->draw_properties().target_space_transform);
EXPECT_TRANSFORMATION_MATRIX_EQ(gfx::Transform(),
- root->GetRenderSurface()->draw_transform());
+ GetRenderSurface(root)->draw_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(page_scaled_translate,
child->ScreenSpaceTransform());
EXPECT_EQ(gfx::Rect(50, 50, 200, 200), child->clip_rect());
@@ -1353,9 +1298,9 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) {
root->test_properties()->transform = composite;
{
- LayerImplList render_surface_layer_list_impl;
+ RenderSurfaceList render_surface_list_impl;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root, root->bounds(), composite, &render_surface_layer_list_impl);
+ root, root->bounds(), composite, &render_surface_list_impl);
inputs.property_trees->needs_rebuild = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
gfx::Transform compositeSquared = composite;
@@ -1365,13 +1310,68 @@ TEST_F(LayerTreeHostCommonTest, TransformAboveRootLayer) {
EXPECT_TRANSFORMATION_MATRIX_EQ(
compositeSquared, child->draw_properties().target_space_transform);
EXPECT_TRANSFORMATION_MATRIX_EQ(gfx::Transform(),
- root->GetRenderSurface()->draw_transform());
+ GetRenderSurface(root)->draw_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(compositeSquared,
child->ScreenSpaceTransform());
EXPECT_EQ(gfx::Rect(254, 316, 428, 428), child->clip_rect());
}
}
+TEST_F(LayerTreeHostCommonTest, RenderSurfaceForNonAxisAlignedClipping) {
+ LayerImpl* root = root_layer_for_testing();
+ LayerImpl* rotated_and_transparent = AddChildToRoot<LayerImpl>();
+ LayerImpl* clips_subtree = AddChild<LayerImpl>(rotated_and_transparent);
+ LayerImpl* draws_content = AddChild<LayerImpl>(clips_subtree);
+
+ root->SetBounds(gfx::Size(10, 10));
+ rotated_and_transparent->SetBounds(gfx::Size(10, 10));
+ rotated_and_transparent->test_properties()->opacity = 0.5f;
+ gfx::Transform rotate;
+ rotate.Rotate(2);
+ rotated_and_transparent->test_properties()->transform = rotate;
+ clips_subtree->SetBounds(gfx::Size(10, 10));
+ clips_subtree->SetMasksToBounds(true);
+ draws_content->SetBounds(gfx::Size(10, 10));
+ draws_content->SetDrawsContent(true);
+
+ ExecuteCalculateDrawProperties(root);
+ EffectTree& effect_tree =
+ root->layer_tree_impl()->property_trees()->effect_tree;
+ EffectNode* node = effect_tree.Node(clips_subtree->effect_tree_index());
+ EXPECT_TRUE(node->has_render_surface);
+}
+
+TEST_F(LayerTreeHostCommonTest, EffectNodesForNonAxisAlignedClips) {
+ LayerImpl* root = root_layer_for_testing();
+ LayerImpl* rotate_and_clip = AddChildToRoot<LayerImpl>();
+ LayerImpl* only_clip = AddChild<LayerImpl>(rotate_and_clip);
+ LayerImpl* rotate_and_clip2 = AddChild<LayerImpl>(only_clip);
+
+ gfx::Transform rotate;
+ rotate.Rotate(2);
+ root->SetBounds(gfx::Size(10, 10));
+ rotate_and_clip->SetBounds(gfx::Size(10, 10));
+ rotate_and_clip->test_properties()->transform = rotate;
+ rotate_and_clip->SetMasksToBounds(true);
+ only_clip->SetBounds(gfx::Size(10, 10));
+ only_clip->SetMasksToBounds(true);
+ rotate_and_clip2->SetBounds(gfx::Size(10, 10));
+ rotate_and_clip2->test_properties()->transform = rotate;
+ rotate_and_clip2->SetMasksToBounds(true);
+
+ ExecuteCalculateDrawProperties(root);
+ // non-axis aligned clip should create an effect node
+ EXPECT_NE(root->effect_tree_index(), rotate_and_clip->effect_tree_index());
+ // Since only_clip's clip is in the same non-axis aligned space as
+ // rotate_and_clip's clip, no new effect node should be created.
+ EXPECT_EQ(rotate_and_clip->effect_tree_index(),
+ only_clip->effect_tree_index());
+ // rotate_and_clip2's clip and only_clip's clip are in different non-axis
+ // aligned spaces. So, new effect node should be created.
+ EXPECT_NE(rotate_and_clip2->effect_tree_index(),
+ only_clip->effect_tree_index());
+}
+
TEST_F(LayerTreeHostCommonTest,
RenderSurfaceListForRenderSurfaceWithClippedLayer) {
LayerImpl* root = root_layer_for_testing();
@@ -1392,8 +1392,8 @@ TEST_F(LayerTreeHostCommonTest,
// forced to be created. Render surfaces without children or visible content
// are unexpected at draw time (e.g. we might try to create a content texture
// of size 0).
- ASSERT_TRUE(root->GetRenderSurface());
- EXPECT_EQ(1U, render_surface_layer_list_impl()->size());
+ ASSERT_TRUE(GetRenderSurface(root));
+ EXPECT_EQ(1U, render_surface_list_impl()->size());
}
TEST_F(LayerTreeHostCommonTest, RenderSurfaceListForTransparentChild) {
@@ -1407,19 +1407,19 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceListForTransparentChild) {
child->SetBounds(gfx::Size(10, 10));
child->SetDrawsContent(true);
- LayerImplList render_surface_layer_list;
+ RenderSurfaceList render_surface_list;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root, root->bounds(), &render_surface_layer_list);
+ root, root->bounds(), &render_surface_list);
inputs.can_adjust_raster_scales = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
// Since the layer is transparent, render_surface1->GetRenderSurface() should
// not have gotten added anywhere. Also, the drawable content rect should not
// have been extended by the children.
- ASSERT_TRUE(root->GetRenderSurface());
- EXPECT_EQ(0U, root->GetRenderSurface()->layer_list().size());
- EXPECT_EQ(1U, render_surface_layer_list.size());
- EXPECT_EQ(root->id(), render_surface_layer_list.at(0)->id());
+ ASSERT_TRUE(GetRenderSurface(root));
+ EXPECT_EQ(0, GetRenderSurface(root)->num_contributors());
+ EXPECT_EQ(1U, render_surface_list.size());
+ EXPECT_EQ(root->id(), render_surface_list.at(0)->id());
EXPECT_EQ(gfx::Rect(), root->drawable_content_rect());
}
@@ -1442,19 +1442,19 @@ TEST_F(LayerTreeHostCommonTest,
root->layer_tree_impl()->SetElementIdsForTesting();
{
- LayerImplList render_surface_layer_list;
+ RenderSurfaceList render_surface_list;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root, root->bounds(), &render_surface_layer_list);
+ root, root->bounds(), &render_surface_list);
inputs.can_adjust_raster_scales = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
- EXPECT_EQ(2U, render_surface_layer_list.size());
+ EXPECT_EQ(2U, render_surface_list.size());
}
// The layer is fully transparent, but has a background filter, so it
// shouldn't be skipped and should be drawn.
- ASSERT_TRUE(root->GetRenderSurface());
- EXPECT_EQ(1U, root->GetRenderSurface()->layer_list().size());
+ ASSERT_TRUE(GetRenderSurface(root));
+ EXPECT_EQ(1, GetRenderSurface(root)->num_contributors());
EXPECT_EQ(gfx::RectF(0, 0, 10, 10),
- root->GetRenderSurface()->DrawableContentRect());
+ GetRenderSurface(root)->DrawableContentRect());
EffectTree& effect_tree =
root->layer_tree_impl()->property_trees()->effect_tree;
EffectNode* node = effect_tree.Node(render_surface1->effect_tree_index());
@@ -1466,9 +1466,9 @@ TEST_F(LayerTreeHostCommonTest,
1.f);
render_surface1->set_visible_layer_rect(gfx::Rect());
{
- LayerImplList render_surface_layer_list;
+ RenderSurfaceList render_surface_list;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root, root->bounds(), &render_surface_layer_list);
+ root, root->bounds(), &render_surface_list);
inputs.can_adjust_raster_scales = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
}
@@ -1501,21 +1501,21 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceListForFilter) {
child2->SetDrawsContent(true);
child2->test_properties()->force_render_surface = true;
- LayerImplList render_surface_layer_list;
+ RenderSurfaceList render_surface_list;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root, root->bounds(), &render_surface_layer_list);
+ root, root->bounds(), &render_surface_list);
inputs.can_adjust_raster_scales = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
- ASSERT_TRUE(parent->GetRenderSurface());
- EXPECT_EQ(2U, parent->GetRenderSurface()->layer_list().size());
- EXPECT_EQ(4U, render_surface_layer_list.size());
+ ASSERT_TRUE(GetRenderSurface(parent));
+ EXPECT_EQ(2, GetRenderSurface(parent)->num_contributors());
+ EXPECT_EQ(4U, render_surface_list.size());
// The rectangle enclosing child1 and child2 (0,0 50x50), expanded for the
// blur (-30,-30 110x110), and then scaled by the scale matrix
// (-60,-60 220x220).
EXPECT_EQ(gfx::RectF(-60, -60, 220, 220),
- parent->GetRenderSurface()->DrawableContentRect());
+ GetRenderSurface(parent)->DrawableContentRect());
}
TEST_F(LayerTreeHostCommonTest, DrawableContentRectForReferenceFilter) {
@@ -1535,9 +1535,9 @@ TEST_F(LayerTreeHostCommonTest, DrawableContentRectForReferenceFilter) {
// The render surface's size should be unaffected by the offset image filter;
// it need only have a drawable content rect large enough to contain the
// contents (at the new offset).
- ASSERT_TRUE(child->GetRenderSurface());
+ ASSERT_TRUE(GetRenderSurface(child));
EXPECT_EQ(gfx::RectF(50, 50, 25, 25),
- child->GetRenderSurface()->DrawableContentRect());
+ GetRenderSurface(child)->DrawableContentRect());
}
TEST_F(LayerTreeHostCommonTest, DrawableContentRectForReferenceFilterHighDpi) {
@@ -1562,9 +1562,9 @@ TEST_F(LayerTreeHostCommonTest, DrawableContentRectForReferenceFilterHighDpi) {
// it need only have a drawable content rect large enough to contain the
// contents (at the new offset). All coordinates should be scaled by 2,
// corresponding to the device scale factor.
- ASSERT_TRUE(child->GetRenderSurface());
+ ASSERT_TRUE(GetRenderSurface(child));
EXPECT_EQ(gfx::RectF(100, 100, 50, 50),
- child->GetRenderSurface()->DrawableContentRect());
+ GetRenderSurface(child)->DrawableContentRect());
}
TEST_F(LayerTreeHostCommonTest, RenderSurfaceForBlendMode) {
@@ -1581,10 +1581,10 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceForBlendMode) {
// Since the child layer has a blend mode other than normal, it should get
// its own render surface.
- ASSERT_TRUE(child->GetRenderSurface());
+ ASSERT_TRUE(GetRenderSurface(child));
EXPECT_EQ(1.0f, child->draw_opacity());
- EXPECT_EQ(0.5f, child->GetRenderSurface()->draw_opacity());
- EXPECT_EQ(SkBlendMode::kMultiply, child->GetRenderSurface()->BlendMode());
+ EXPECT_EQ(0.5f, GetRenderSurface(child)->draw_opacity());
+ EXPECT_EQ(SkBlendMode::kMultiply, GetRenderSurface(child)->BlendMode());
}
TEST_F(LayerTreeHostCommonTest, RenderSurfaceDrawOpacity) {
@@ -1606,73 +1606,13 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceDrawOpacity) {
surface2->test_properties()->force_render_surface = true;
ExecuteCalculateDrawProperties(root);
- ASSERT_TRUE(surface1->GetRenderSurface());
- ASSERT_FALSE(not_surface->GetRenderSurface());
- ASSERT_TRUE(surface2->GetRenderSurface());
- EXPECT_EQ(0.5f, surface1->GetRenderSurface()->draw_opacity());
+ ASSERT_TRUE(GetRenderSurface(surface1));
+ ASSERT_EQ(GetRenderSurface(not_surface), GetRenderSurface(surface1));
+ ASSERT_TRUE(GetRenderSurface(surface2));
+ EXPECT_EQ(0.5f, GetRenderSurface(surface1)->draw_opacity());
// surface2's draw opacity should include the opacity of not-surface and
// itself, but not the opacity of surface1.
- EXPECT_EQ(0.25f, surface2->GetRenderSurface()->draw_opacity());
-}
-
-TEST_F(LayerTreeHostCommonTest, DrawOpacityWhenCannotRenderToSeparateSurface) {
- // Tests that when separate surfaces are disabled, a layer's draw opacity is
- // the product of all ancestor layer opacties and the layer's own opacity.
- // (Rendering will still be incorrect in situations where we really do need
- // surfaces to apply opacity, such as when we have overlapping layers with an
- // ancestor whose opacity is <1.)
- LayerImpl* root = root_layer_for_testing();
- LayerImpl* parent = AddChild<LayerImpl>(root);
- LayerImpl* child1 = AddChild<LayerImpl>(parent);
- LayerImpl* child2 = AddChild<LayerImpl>(parent);
- LayerImpl* grand_child = AddChild<LayerImpl>(child1);
- LayerImpl* leaf_node1 = AddChild<LayerImpl>(grand_child);
- LayerImpl* leaf_node2 = AddChild<LayerImpl>(child2);
-
- root->SetBounds(gfx::Size(100, 100));
- root->SetDrawsContent(true);
- parent->SetBounds(gfx::Size(100, 100));
- parent->SetDrawsContent(true);
- child1->SetBounds(gfx::Size(100, 100));
- child1->SetDrawsContent(true);
- child1->test_properties()->opacity = 0.5f;
- child1->test_properties()->force_render_surface = true;
- child2->SetBounds(gfx::Size(100, 100));
- child2->SetDrawsContent(true);
- grand_child->SetBounds(gfx::Size(100, 100));
- grand_child->SetDrawsContent(true);
- grand_child->test_properties()->opacity = 0.5f;
- grand_child->test_properties()->force_render_surface = true;
- leaf_node1->SetBounds(gfx::Size(100, 100));
- leaf_node1->SetDrawsContent(true);
- leaf_node1->test_properties()->opacity = 0.5f;
- leaf_node2->SetBounds(gfx::Size(100, 100));
- leaf_node2->SetDrawsContent(true);
- leaf_node2->test_properties()->opacity = 0.5f;
-
- // With surfaces enabled, each layer's draw opacity is the product of layer
- // opacities on the path from the layer to its render target, not including
- // the opacity of the layer that owns the target surface (since that opacity
- // is applied by the surface).
- ExecuteCalculateDrawProperties(root);
- EXPECT_EQ(1.f, root->draw_opacity());
- EXPECT_EQ(1.f, parent->draw_opacity());
- EXPECT_EQ(1.f, child1->draw_opacity());
- EXPECT_EQ(1.f, child2->draw_opacity());
- EXPECT_EQ(1.f, grand_child->draw_opacity());
- EXPECT_EQ(0.5f, leaf_node1->draw_opacity());
- EXPECT_EQ(0.5f, leaf_node2->draw_opacity());
-
- // With surfaces disabled, each layer's draw opacity is the product of layer
- // opacities on the path from the layer to the root.
- ExecuteCalculateDrawPropertiesWithoutSeparateSurfaces(root);
- EXPECT_EQ(1.f, root->draw_opacity());
- EXPECT_EQ(1.f, parent->draw_opacity());
- EXPECT_EQ(0.5f, child1->draw_opacity());
- EXPECT_EQ(1.f, child2->draw_opacity());
- EXPECT_EQ(0.25f, grand_child->draw_opacity());
- EXPECT_EQ(0.125f, leaf_node1->draw_opacity());
- EXPECT_EQ(0.5f, leaf_node2->draw_opacity());
+ EXPECT_EQ(0.25f, GetRenderSurface(surface2)->draw_opacity());
}
TEST_F(LayerTreeHostCommonTest, ForceRenderSurface) {
@@ -1690,16 +1630,16 @@ TEST_F(LayerTreeHostCommonTest, ForceRenderSurface) {
ExecuteCalculateDrawPropertiesAndSaveUpdateLayerList(root);
// The root layer always creates a render surface
- EXPECT_TRUE(root->GetRenderSurface());
- EXPECT_TRUE(render_surface1->GetRenderSurface());
+ EXPECT_TRUE(GetRenderSurface(root));
+ EXPECT_NE(GetRenderSurface(render_surface1), GetRenderSurface(root));
}
{
render_surface1->test_properties()->force_render_surface = false;
render_surface1->layer_tree_impl()->property_trees()->needs_rebuild = true;
ExecuteCalculateDrawPropertiesAndSaveUpdateLayerList(root);
- EXPECT_TRUE(root->GetRenderSurface());
- EXPECT_FALSE(render_surface1->GetRenderSurface());
+ EXPECT_TRUE(GetRenderSurface(root));
+ EXPECT_EQ(GetRenderSurface(render_surface1), GetRenderSurface(root));
}
}
@@ -1725,9 +1665,9 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfacesFlattenScreenSpaceTransform) {
grand_child->test_properties()->should_flatten_transform = false;
ExecuteCalculateDrawProperties(root);
- EXPECT_TRUE(parent->GetRenderSurface());
- EXPECT_FALSE(child->GetRenderSurface());
- EXPECT_FALSE(grand_child->GetRenderSurface());
+ EXPECT_TRUE(GetRenderSurface(parent));
+ EXPECT_EQ(GetRenderSurface(child), GetRenderSurface(parent));
+ EXPECT_EQ(GetRenderSurface(grand_child), GetRenderSurface(parent));
EXPECT_TRANSFORMATION_MATRIX_EQ(gfx::Transform(), child->DrawTransform());
EXPECT_TRANSFORMATION_MATRIX_EQ(gfx::Transform(),
@@ -1746,7 +1686,7 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfacesFlattenScreenSpaceTransform) {
TEST_F(LayerTreeHostCommonTest, ClipRectCullsRenderSurfaces) {
// The entire subtree of layers that are outside the clip rect should be
- // culled away, and should not affect the render_surface_layer_list.
+ // culled away, and should not affect the render_surface_list.
//
// The test tree is set up as follows:
// - all layers except the leaf_nodes are forced to be a new render surface
@@ -1765,9 +1705,8 @@ TEST_F(LayerTreeHostCommonTest, ClipRectCullsRenderSurfaces) {
LayerImpl* grand_child = AddChild<LayerImpl>(child);
LayerImpl* great_grand_child = AddChild<LayerImpl>(grand_child);
- // leaf_node1 ensures that root and child are kept on the
- // render_surface_layer_list, even though grand_child and great_grand_child
- // should be clipped.
+ // leaf_node1 ensures that root and child are kept on the render_surface_list,
+ // even though grand_child and great_grand_child should be clipped.
LayerImpl* leaf_node1 = AddChild<LayerImpl>(child);
LayerImpl* leaf_node2 = AddChild<LayerImpl>(great_grand_child);
@@ -1784,9 +1723,9 @@ TEST_F(LayerTreeHostCommonTest, ClipRectCullsRenderSurfaces) {
leaf_node2->SetDrawsContent(true);
ExecuteCalculateDrawProperties(root);
- ASSERT_EQ(2U, render_surface_layer_list_impl()->size());
- EXPECT_EQ(root->id(), render_surface_layer_list_impl()->at(0)->id());
- EXPECT_EQ(child->id(), render_surface_layer_list_impl()->at(1)->id());
+ ASSERT_EQ(2U, render_surface_list_impl()->size());
+ EXPECT_EQ(root->id(), render_surface_list_impl()->at(0)->id());
+ EXPECT_EQ(child->id(), render_surface_list_impl()->at(1)->id());
}
TEST_F(LayerTreeHostCommonTest, ClipRectCullsSurfaceWithoutVisibleContent) {
@@ -1802,7 +1741,7 @@ TEST_F(LayerTreeHostCommonTest, ClipRectCullsSurfaceWithoutVisibleContent) {
// In this configuration, grand_child should be outside the clipped
// content rect of the child, making grand_child not appear in the
- // render_surface_layer_list.
+ // render_surface_list.
LayerImpl* root = root_layer_for_testing();
LayerImpl* child = AddChildToRoot<LayerImpl>();
@@ -1821,9 +1760,9 @@ TEST_F(LayerTreeHostCommonTest, ClipRectCullsSurfaceWithoutVisibleContent) {
ExecuteCalculateDrawProperties(root);
// We should cull child and grand_child from the
- // render_surface_layer_list.
- ASSERT_EQ(1U, render_surface_layer_list_impl()->size());
- EXPECT_EQ(root->id(), render_surface_layer_list_impl()->at(0)->id());
+ // render_surface_list.
+ ASSERT_EQ(1U, render_surface_list_impl()->size());
+ EXPECT_EQ(root->id(), render_surface_list_impl()->at(0)->id());
}
TEST_F(LayerTreeHostCommonTest, IsClippedIsSetCorrectlyLayerImpl) {
@@ -1866,15 +1805,15 @@ TEST_F(LayerTreeHostCommonTest, IsClippedIsSetCorrectlyLayerImpl) {
// Case 1: nothing is clipped except the root render surface.
ExecuteCalculateDrawProperties(root);
- ASSERT_TRUE(root->GetRenderSurface());
- ASSERT_TRUE(child2->GetRenderSurface());
+ ASSERT_TRUE(GetRenderSurface(root));
+ ASSERT_TRUE(GetRenderSurface(child2));
EXPECT_FALSE(root->is_clipped());
- EXPECT_TRUE(root->GetRenderSurface()->is_clipped());
+ EXPECT_TRUE(GetRenderSurface(root)->is_clipped());
EXPECT_FALSE(parent->is_clipped());
EXPECT_FALSE(child1->is_clipped());
EXPECT_FALSE(child2->is_clipped());
- EXPECT_FALSE(child2->GetRenderSurface()->is_clipped());
+ EXPECT_FALSE(GetRenderSurface(child2)->is_clipped());
EXPECT_FALSE(grand_child->is_clipped());
EXPECT_FALSE(leaf_node1->is_clipped());
EXPECT_FALSE(leaf_node2->is_clipped());
@@ -1888,15 +1827,15 @@ TEST_F(LayerTreeHostCommonTest, IsClippedIsSetCorrectlyLayerImpl) {
ExecuteCalculateDrawProperties(root);
- ASSERT_TRUE(root->GetRenderSurface());
- ASSERT_TRUE(child2->GetRenderSurface());
+ ASSERT_TRUE(GetRenderSurface(root));
+ ASSERT_TRUE(GetRenderSurface(child2));
EXPECT_FALSE(root->is_clipped());
- EXPECT_TRUE(root->GetRenderSurface()->is_clipped());
+ EXPECT_TRUE(GetRenderSurface(root)->is_clipped());
EXPECT_TRUE(parent->is_clipped());
EXPECT_TRUE(child1->is_clipped());
EXPECT_FALSE(child2->is_clipped());
- EXPECT_TRUE(child2->GetRenderSurface()->is_clipped());
+ EXPECT_TRUE(GetRenderSurface(child2)->is_clipped());
EXPECT_TRUE(grand_child->is_clipped());
EXPECT_TRUE(leaf_node1->is_clipped());
EXPECT_FALSE(leaf_node2->is_clipped());
@@ -1910,15 +1849,15 @@ TEST_F(LayerTreeHostCommonTest, IsClippedIsSetCorrectlyLayerImpl) {
ExecuteCalculateDrawProperties(root);
- ASSERT_TRUE(root->GetRenderSurface());
- ASSERT_TRUE(child2->GetRenderSurface());
+ ASSERT_TRUE(GetRenderSurface(root));
+ ASSERT_TRUE(GetRenderSurface(child2));
EXPECT_FALSE(root->is_clipped());
- EXPECT_TRUE(root->GetRenderSurface()->is_clipped());
+ EXPECT_TRUE(GetRenderSurface(root)->is_clipped());
EXPECT_FALSE(parent->is_clipped());
EXPECT_FALSE(child1->is_clipped());
EXPECT_TRUE(child2->is_clipped());
- EXPECT_FALSE(child2->GetRenderSurface()->is_clipped());
+ EXPECT_FALSE(GetRenderSurface(child2)->is_clipped());
EXPECT_FALSE(grand_child->is_clipped());
EXPECT_FALSE(leaf_node1->is_clipped());
EXPECT_TRUE(leaf_node2->is_clipped());
@@ -1958,154 +1897,6 @@ TEST_F(LayerTreeHostCommonTest, UpdateClipRectCorrectly) {
EXPECT_EQ(gfx::Rect(), child->clip_rect());
}
-TEST_F(LayerTreeHostCommonTest, IsClippedWhenCannotRenderToSeparateSurface) {
- // Tests that when separate surfaces are disabled, is_clipped is true exactly
- // when a layer or its ancestor has a clip; in particular, if a layer
- // is_clipped, so is its entire subtree (since there are no render surfaces
- // that can reset is_clipped).
- LayerImpl* root = root_layer_for_testing();
- LayerImpl* parent = AddChild<LayerImpl>(root);
- LayerImpl* child1 = AddChild<LayerImpl>(parent);
- LayerImpl* child2 = AddChild<LayerImpl>(parent);
- LayerImpl* grand_child = AddChild<LayerImpl>(child1);
- LayerImpl* leaf_node1 = AddChild<LayerImpl>(grand_child);
- LayerImpl* leaf_node2 = AddChild<LayerImpl>(child2);
-
- root->SetBounds(gfx::Size(100, 100));
- root->SetDrawsContent(true);
- parent->SetBounds(gfx::Size(100, 100));
- parent->SetDrawsContent(true);
- child1->SetBounds(gfx::Size(100, 100));
- child1->SetDrawsContent(true);
- child1->test_properties()->force_render_surface = true;
- child2->SetBounds(gfx::Size(100, 100));
- child2->SetDrawsContent(true);
- grand_child->SetBounds(gfx::Size(100, 100));
- grand_child->SetDrawsContent(true);
- grand_child->test_properties()->force_render_surface = true;
- leaf_node1->SetBounds(gfx::Size(100, 100));
- leaf_node1->SetDrawsContent(true);
- leaf_node2->SetBounds(gfx::Size(100, 100));
- leaf_node2->SetDrawsContent(true);
-
- // Case 1: Nothing is clipped. In this case, is_clipped is always false, with
- // or without surfaces.
- ExecuteCalculateDrawProperties(root);
- EXPECT_FALSE(root->is_clipped());
- EXPECT_FALSE(parent->is_clipped());
- EXPECT_FALSE(child1->is_clipped());
- EXPECT_FALSE(child2->is_clipped());
- EXPECT_FALSE(grand_child->is_clipped());
- EXPECT_FALSE(leaf_node1->is_clipped());
- EXPECT_FALSE(leaf_node2->is_clipped());
-
- ExecuteCalculateDrawPropertiesWithoutSeparateSurfaces(root);
- EXPECT_FALSE(root->is_clipped());
- EXPECT_FALSE(parent->is_clipped());
- EXPECT_FALSE(child1->is_clipped());
- EXPECT_FALSE(child2->is_clipped());
- EXPECT_FALSE(grand_child->is_clipped());
- EXPECT_FALSE(leaf_node1->is_clipped());
- EXPECT_FALSE(leaf_node2->is_clipped());
-
- // Case 2: The root is clipped. With surfaces, this only persists until the
- // next render surface. Without surfaces, the entire tree is clipped.
- root->SetMasksToBounds(true);
- host_impl()->active_tree()->property_trees()->needs_rebuild = true;
- ExecuteCalculateDrawProperties(root);
- EXPECT_TRUE(root->is_clipped());
- EXPECT_TRUE(parent->is_clipped());
- EXPECT_FALSE(child1->is_clipped());
- EXPECT_TRUE(child2->is_clipped());
- EXPECT_FALSE(grand_child->is_clipped());
- EXPECT_FALSE(leaf_node1->is_clipped());
- EXPECT_TRUE(leaf_node2->is_clipped());
-
- ExecuteCalculateDrawPropertiesWithoutSeparateSurfaces(root);
- EXPECT_TRUE(root->is_clipped());
- EXPECT_TRUE(parent->is_clipped());
- EXPECT_TRUE(child1->is_clipped());
- EXPECT_TRUE(child2->is_clipped());
- EXPECT_TRUE(grand_child->is_clipped());
- EXPECT_TRUE(leaf_node1->is_clipped());
- EXPECT_TRUE(leaf_node2->is_clipped());
-
- root->SetMasksToBounds(false);
-
- // Case 3: The parent is clipped. Again, with surfaces, this only persists
- // until the next render surface. Without surfaces, parent's entire subtree is
- // clipped.
- parent->SetMasksToBounds(true);
- host_impl()->active_tree()->property_trees()->needs_rebuild = true;
- ExecuteCalculateDrawProperties(root);
- EXPECT_FALSE(root->is_clipped());
- EXPECT_TRUE(parent->is_clipped());
- EXPECT_FALSE(child1->is_clipped());
- EXPECT_TRUE(child2->is_clipped());
- EXPECT_FALSE(grand_child->is_clipped());
- EXPECT_FALSE(leaf_node1->is_clipped());
- EXPECT_TRUE(leaf_node2->is_clipped());
-
- ExecuteCalculateDrawPropertiesWithoutSeparateSurfaces(root);
- EXPECT_FALSE(root->is_clipped());
- EXPECT_TRUE(parent->is_clipped());
- EXPECT_TRUE(child1->is_clipped());
- EXPECT_TRUE(child2->is_clipped());
- EXPECT_TRUE(grand_child->is_clipped());
- EXPECT_TRUE(leaf_node1->is_clipped());
- EXPECT_TRUE(leaf_node2->is_clipped());
-
- parent->SetMasksToBounds(false);
-
- // Case 4: child1 is clipped. With surfaces, only child1 is_clipped, since it
- // has no non-surface children. Without surfaces, child1's entire subtree is
- // clipped.
- child1->SetMasksToBounds(true);
- host_impl()->active_tree()->property_trees()->needs_rebuild = true;
- ExecuteCalculateDrawProperties(root);
- EXPECT_FALSE(root->is_clipped());
- EXPECT_FALSE(parent->is_clipped());
- EXPECT_TRUE(child1->is_clipped());
- EXPECT_FALSE(child2->is_clipped());
- EXPECT_FALSE(grand_child->is_clipped());
- EXPECT_FALSE(leaf_node1->is_clipped());
- EXPECT_FALSE(leaf_node2->is_clipped());
-
- ExecuteCalculateDrawPropertiesWithoutSeparateSurfaces(root);
- EXPECT_FALSE(root->is_clipped());
- EXPECT_FALSE(parent->is_clipped());
- EXPECT_TRUE(child1->is_clipped());
- EXPECT_FALSE(child2->is_clipped());
- EXPECT_TRUE(grand_child->is_clipped());
- EXPECT_TRUE(leaf_node1->is_clipped());
- EXPECT_FALSE(leaf_node2->is_clipped());
-
- child1->SetMasksToBounds(false);
-
- // Case 5: Only the leaf nodes are clipped. The behavior with and without
- // surfaces is the same.
- leaf_node1->SetMasksToBounds(true);
- leaf_node2->SetMasksToBounds(true);
- host_impl()->active_tree()->property_trees()->needs_rebuild = true;
- ExecuteCalculateDrawProperties(root);
- EXPECT_FALSE(root->is_clipped());
- EXPECT_FALSE(parent->is_clipped());
- EXPECT_FALSE(child1->is_clipped());
- EXPECT_FALSE(child2->is_clipped());
- EXPECT_FALSE(grand_child->is_clipped());
- EXPECT_TRUE(leaf_node1->is_clipped());
- EXPECT_TRUE(leaf_node2->is_clipped());
-
- ExecuteCalculateDrawPropertiesWithoutSeparateSurfaces(root);
- EXPECT_FALSE(root->is_clipped());
- EXPECT_FALSE(parent->is_clipped());
- EXPECT_FALSE(child1->is_clipped());
- EXPECT_FALSE(child2->is_clipped());
- EXPECT_FALSE(grand_child->is_clipped());
- EXPECT_TRUE(leaf_node1->is_clipped());
- EXPECT_TRUE(leaf_node2->is_clipped());
-}
-
TEST_F(LayerTreeHostCommonTest, DrawableContentRectForLayers) {
// Verify that layers get the appropriate DrawableContentRect when their
// parent MasksToBounds is true.
@@ -2201,286 +1992,18 @@ TEST_F(LayerTreeHostCommonTest, ClipRectIsPropagatedCorrectlyToSurfaces) {
leaf_node4->SetDrawsContent(true);
ExecuteCalculateDrawProperties(parent);
- ASSERT_TRUE(grand_child1->GetRenderSurface());
- ASSERT_TRUE(grand_child2->GetRenderSurface());
- ASSERT_TRUE(grand_child3->GetRenderSurface());
+ ASSERT_TRUE(GetRenderSurface(grand_child1));
+ ASSERT_TRUE(GetRenderSurface(grand_child2));
+ ASSERT_TRUE(GetRenderSurface(grand_child3));
// Surfaces are clipped by their parent, but un-affected by the owning layer's
// MasksToBounds.
EXPECT_EQ(gfx::Rect(0, 0, 20, 20),
- grand_child1->GetRenderSurface()->clip_rect());
+ GetRenderSurface(grand_child1)->clip_rect());
EXPECT_EQ(gfx::Rect(0, 0, 20, 20),
- grand_child2->GetRenderSurface()->clip_rect());
+ GetRenderSurface(grand_child2)->clip_rect());
EXPECT_EQ(gfx::Rect(0, 0, 20, 20),
- grand_child3->GetRenderSurface()->clip_rect());
-}
-
-TEST_F(LayerTreeHostCommonTest, ClipRectWhenCannotRenderToSeparateSurface) {
- // Tests that when separate surfaces are disabled, a layer's clip_rect is the
- // intersection of all ancestor clips in screen space; in particular, if a
- // layer masks to bounds, it contributes to the clip_rect of all layers in its
- // subtree (since there are no render surfaces that can reset the clip_rect).
- LayerImpl* root = root_layer_for_testing();
- LayerImpl* parent = AddChild<LayerImpl>(root);
- LayerImpl* child1 = AddChild<LayerImpl>(parent);
- LayerImpl* child2 = AddChild<LayerImpl>(parent);
- LayerImpl* grand_child = AddChild<LayerImpl>(child1);
- LayerImpl* leaf_node1 = AddChild<LayerImpl>(grand_child);
- LayerImpl* leaf_node2 = AddChild<LayerImpl>(child2);
-
- root->SetBounds(gfx::Size(100, 100));
- parent->SetPosition(gfx::PointF(2.f, 2.f));
- parent->SetBounds(gfx::Size(400, 400));
- child1->SetPosition(gfx::PointF(4.f, 4.f));
- child1->SetBounds(gfx::Size(800, 800));
- child2->SetPosition(gfx::PointF(3.f, 3.f));
- child2->SetBounds(gfx::Size(800, 800));
- grand_child->SetPosition(gfx::PointF(8.f, 8.f));
- grand_child->SetBounds(gfx::Size(1500, 1500));
- leaf_node1->SetPosition(gfx::PointF(16.f, 16.f));
- leaf_node1->SetBounds(gfx::Size(2000, 2000));
- leaf_node2->SetPosition(gfx::PointF(9.f, 9.f));
- leaf_node2->SetBounds(gfx::Size(2000, 2000));
-
- root->SetDrawsContent(true);
- parent->SetDrawsContent(true);
- child1->SetDrawsContent(true);
- child2->SetDrawsContent(true);
- grand_child->SetDrawsContent(true);
- leaf_node1->SetDrawsContent(true);
- leaf_node2->SetDrawsContent(true);
-
- root->test_properties()->force_render_surface = true;
- child1->test_properties()->force_render_surface = true;
- grand_child->test_properties()->force_render_surface = true;
-
- // Case 1: Nothing is clipped. In this case, each layer's clip rect is its
- // bounds in target space. The only thing that changes when surfaces are
- // disabled is that target space is always screen space.
- ExecuteCalculateDrawProperties(root);
- EXPECT_TRUE(root->GetRenderSurface());
- EXPECT_FALSE(parent->GetRenderSurface());
- EXPECT_TRUE(child1->GetRenderSurface());
- EXPECT_FALSE(child2->GetRenderSurface());
- EXPECT_TRUE(grand_child->GetRenderSurface());
- EXPECT_FALSE(leaf_node1->GetRenderSurface());
- EXPECT_FALSE(leaf_node2->GetRenderSurface());
- EXPECT_FALSE(root->is_clipped());
- EXPECT_FALSE(parent->is_clipped());
- EXPECT_FALSE(child1->is_clipped());
- EXPECT_FALSE(child2->is_clipped());
- EXPECT_FALSE(grand_child->is_clipped());
- EXPECT_FALSE(leaf_node1->is_clipped());
- EXPECT_FALSE(leaf_node2->is_clipped());
- EXPECT_TRUE(root->GetRenderSurface()->is_clipped());
- EXPECT_FALSE(child1->GetRenderSurface()->is_clipped());
- EXPECT_FALSE(grand_child->GetRenderSurface()->is_clipped());
- EXPECT_EQ(gfx::Rect(100, 100), root->GetRenderSurface()->clip_rect());
-
- ExecuteCalculateDrawPropertiesWithoutSeparateSurfaces(root);
- EXPECT_FALSE(root->is_clipped());
- EXPECT_FALSE(parent->is_clipped());
- EXPECT_FALSE(child1->is_clipped());
- EXPECT_FALSE(child2->is_clipped());
- EXPECT_FALSE(grand_child->is_clipped());
- EXPECT_FALSE(leaf_node1->is_clipped());
- EXPECT_FALSE(leaf_node2->is_clipped());
- EXPECT_TRUE(root->GetRenderSurface()->is_clipped());
- EXPECT_EQ(gfx::Rect(100, 100), root->GetRenderSurface()->clip_rect());
-
- // Case 2: The root is clipped. In this case, layers that draw into the root
- // render surface are clipped by the root's bounds.
- root->SetMasksToBounds(true);
- host_impl()->active_tree()->property_trees()->needs_rebuild = true;
- root->test_properties()->force_render_surface = true;
- child1->test_properties()->force_render_surface = true;
- grand_child->test_properties()->force_render_surface = true;
- ExecuteCalculateDrawProperties(root);
- EXPECT_TRUE(root->GetRenderSurface());
- EXPECT_FALSE(parent->GetRenderSurface());
- EXPECT_TRUE(child1->GetRenderSurface());
- EXPECT_FALSE(child2->GetRenderSurface());
- EXPECT_TRUE(grand_child->GetRenderSurface());
- EXPECT_FALSE(leaf_node1->GetRenderSurface());
- EXPECT_FALSE(leaf_node2->GetRenderSurface());
- EXPECT_TRUE(root->is_clipped());
- EXPECT_TRUE(parent->is_clipped());
- EXPECT_FALSE(child1->is_clipped());
- EXPECT_TRUE(child1->GetRenderSurface()->is_clipped());
- EXPECT_TRUE(child2->is_clipped());
- EXPECT_FALSE(grand_child->is_clipped());
- EXPECT_FALSE(grand_child->GetRenderSurface()->is_clipped());
- EXPECT_FALSE(leaf_node1->is_clipped());
- EXPECT_TRUE(leaf_node2->is_clipped());
- EXPECT_EQ(gfx::Rect(100, 100), root->clip_rect());
- EXPECT_EQ(gfx::Rect(100, 100), parent->clip_rect());
- EXPECT_EQ(gfx::Rect(100, 100), child1->GetRenderSurface()->clip_rect());
- EXPECT_EQ(gfx::Rect(100, 100), child2->clip_rect());
- EXPECT_EQ(gfx::Rect(100, 100), leaf_node2->clip_rect());
-
- ExecuteCalculateDrawPropertiesWithoutSeparateSurfaces(root);
- EXPECT_TRUE(root->is_clipped());
- EXPECT_TRUE(parent->is_clipped());
- EXPECT_TRUE(child1->is_clipped());
- EXPECT_TRUE(child2->is_clipped());
- EXPECT_TRUE(grand_child->is_clipped());
- EXPECT_TRUE(leaf_node1->is_clipped());
- EXPECT_TRUE(leaf_node2->is_clipped());
- EXPECT_EQ(gfx::Rect(100, 100), root->clip_rect());
- EXPECT_EQ(gfx::Rect(100, 100), parent->clip_rect());
- EXPECT_EQ(gfx::Rect(100, 100), child1->clip_rect());
- EXPECT_EQ(gfx::Rect(100, 100), child2->clip_rect());
- EXPECT_EQ(gfx::Rect(100, 100), grand_child->clip_rect());
- EXPECT_EQ(gfx::Rect(100, 100), leaf_node1->clip_rect());
- EXPECT_EQ(gfx::Rect(100, 100), leaf_node2->clip_rect());
-
- root->SetMasksToBounds(false);
-
- // Case 3: The parent and child1 are clipped. When surfaces are enabled, the
- // parent clip rect only contributes to the subtree rooted at child2, since
- // the subtree rooted at child1 renders into a separate surface. Similarly,
- // child1's clip rect doesn't contribute to its descendants, since its only
- // child is a render surface. However, without surfaces, these clip rects
- // contribute to all descendants.
- parent->SetMasksToBounds(true);
- child1->SetMasksToBounds(true);
- host_impl()->active_tree()->property_trees()->needs_rebuild = true;
- root->test_properties()->force_render_surface = true;
- child1->test_properties()->force_render_surface = true;
- grand_child->test_properties()->force_render_surface = true;
- ExecuteCalculateDrawProperties(root);
- EXPECT_TRUE(root->GetRenderSurface());
- EXPECT_FALSE(parent->GetRenderSurface());
- EXPECT_TRUE(child1->GetRenderSurface());
- EXPECT_FALSE(child2->GetRenderSurface());
- EXPECT_TRUE(grand_child->GetRenderSurface());
- EXPECT_FALSE(leaf_node1->GetRenderSurface());
- EXPECT_FALSE(leaf_node2->GetRenderSurface());
- EXPECT_FALSE(root->is_clipped());
- EXPECT_TRUE(root->GetRenderSurface()->is_clipped());
- EXPECT_TRUE(parent->is_clipped());
- EXPECT_TRUE(child1->is_clipped());
- EXPECT_TRUE(child2->is_clipped());
- EXPECT_FALSE(grand_child->is_clipped());
- EXPECT_TRUE(grand_child->GetRenderSurface()->is_clipped());
- EXPECT_FALSE(leaf_node1->is_clipped());
- EXPECT_TRUE(leaf_node2->is_clipped());
- EXPECT_EQ(gfx::Rect(100, 100), root->GetRenderSurface()->clip_rect());
- EXPECT_EQ(gfx::Rect(2, 2, 400, 400), parent->clip_rect());
- EXPECT_EQ(gfx::Rect(800, 800), child1->clip_rect());
- EXPECT_EQ(gfx::Rect(2, 2, 400, 400), child2->clip_rect());
- EXPECT_EQ(gfx::Rect(800, 800), grand_child->GetRenderSurface()->clip_rect());
- EXPECT_EQ(gfx::Rect(2, 2, 400, 400), leaf_node2->clip_rect());
-
- ExecuteCalculateDrawPropertiesWithoutSeparateSurfaces(root);
- EXPECT_FALSE(root->is_clipped());
- EXPECT_TRUE(root->GetRenderSurface()->is_clipped());
- EXPECT_TRUE(parent->is_clipped());
- EXPECT_TRUE(child1->is_clipped());
- EXPECT_TRUE(child2->is_clipped());
- EXPECT_TRUE(grand_child->is_clipped());
- EXPECT_TRUE(leaf_node1->is_clipped());
- EXPECT_TRUE(leaf_node2->is_clipped());
- EXPECT_EQ(gfx::Rect(100, 100), root->GetRenderSurface()->clip_rect());
- EXPECT_EQ(gfx::Rect(2, 2, 400, 400), parent->clip_rect());
- EXPECT_EQ(gfx::Rect(6, 6, 396, 396), child1->clip_rect());
- EXPECT_EQ(gfx::Rect(2, 2, 400, 400), child2->clip_rect());
- EXPECT_EQ(gfx::Rect(6, 6, 396, 396), grand_child->clip_rect());
- EXPECT_EQ(gfx::Rect(6, 6, 396, 396), leaf_node1->clip_rect());
- EXPECT_EQ(gfx::Rect(2, 2, 400, 400), leaf_node2->clip_rect());
-}
-
-TEST_F(LayerTreeHostCommonTest, HitTestingWhenSurfacesDisabled) {
- LayerImpl* root = root_layer_for_testing();
- LayerImpl* parent = AddChild<LayerImpl>(root);
- LayerImpl* child = AddChild<LayerImpl>(parent);
- LayerImpl* grand_child = AddChild<LayerImpl>(child);
- LayerImpl* leaf_node = AddChild<LayerImpl>(grand_child);
-
- root->SetBounds(gfx::Size(100, 100));
- parent->SetPosition(gfx::PointF(2.f, 2.f));
- parent->SetBounds(gfx::Size(400, 400));
- parent->SetMasksToBounds(true);
- child->SetPosition(gfx::PointF(4.f, 4.f));
- child->SetBounds(gfx::Size(800, 800));
- child->SetMasksToBounds(true);
- child->test_properties()->force_render_surface = true;
- grand_child->SetPosition(gfx::PointF(8.f, 8.f));
- grand_child->SetBounds(gfx::Size(1500, 1500));
- grand_child->test_properties()->force_render_surface = true;
- leaf_node->SetPosition(gfx::PointF(16.f, 16.f));
- leaf_node->SetBounds(gfx::Size(2000, 2000));
-
- root->SetDrawsContent(true);
- parent->SetDrawsContent(true);
- child->SetDrawsContent(true);
- grand_child->SetDrawsContent(true);
- leaf_node->SetDrawsContent(true);
-
- host_impl()->set_resourceless_software_draw_for_testing();
- ExecuteCalculateDrawPropertiesWithoutSeparateSurfaces(root);
- gfx::PointF test_point(90.f, 90.f);
- LayerImpl* result_layer =
- root->layer_tree_impl()->FindLayerThatIsHitByPoint(test_point);
- ASSERT_TRUE(result_layer);
- EXPECT_EQ(leaf_node, result_layer);
-}
-
-TEST_F(LayerTreeHostCommonTest, SurfacesDisabledAndReEnabled) {
- // Tests that draw properties are computed correctly when we disable and then
- // re-enable separate surfaces.
- LayerImpl* root = root_layer_for_testing();
- LayerImpl* parent = AddChild<LayerImpl>(root);
- LayerImpl* child = AddChild<LayerImpl>(parent);
- LayerImpl* grand_child = AddChild<LayerImpl>(child);
- LayerImpl* leaf_node = AddChild<LayerImpl>(grand_child);
-
- root->SetBounds(gfx::Size(100, 100));
- parent->SetPosition(gfx::PointF(2.f, 2.f));
- parent->SetBounds(gfx::Size(400, 400));
- parent->SetMasksToBounds(true);
- child->SetPosition(gfx::PointF(4.f, 4.f));
- child->SetBounds(gfx::Size(800, 800));
- child->SetMasksToBounds(true);
- child->test_properties()->force_render_surface = true;
- grand_child->SetPosition(gfx::PointF(8.f, 8.f));
- grand_child->SetBounds(gfx::Size(1500, 1500));
- grand_child->test_properties()->force_render_surface = true;
- leaf_node->SetPosition(gfx::PointF(16.f, 16.f));
- leaf_node->SetBounds(gfx::Size(2000, 2000));
-
- root->SetDrawsContent(true);
- parent->SetDrawsContent(true);
- child->SetDrawsContent(true);
- grand_child->SetDrawsContent(true);
- leaf_node->SetDrawsContent(true);
-
- gfx::Transform expected_leaf_draw_transform_with_surfaces;
- expected_leaf_draw_transform_with_surfaces.Translate(16.0, 16.0);
-
- gfx::Transform expected_leaf_draw_transform_without_surfaces;
- expected_leaf_draw_transform_without_surfaces.Translate(30.0, 30.0);
-
- ExecuteCalculateDrawProperties(root);
- EXPECT_FALSE(leaf_node->is_clipped());
- EXPECT_TRUE(leaf_node->render_target()->is_clipped());
- EXPECT_EQ(gfx::Rect(16, 16, 2000, 2000), leaf_node->drawable_content_rect());
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected_leaf_draw_transform_with_surfaces,
- leaf_node->DrawTransform());
-
- ExecuteCalculateDrawPropertiesWithoutSeparateSurfaces(root);
- EXPECT_TRUE(leaf_node->is_clipped());
- EXPECT_EQ(gfx::Rect(6, 6, 396, 396), leaf_node->clip_rect());
- EXPECT_EQ(gfx::Rect(30, 30, 372, 372), leaf_node->drawable_content_rect());
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected_leaf_draw_transform_without_surfaces,
- leaf_node->DrawTransform());
-
- ExecuteCalculateDrawProperties(root);
- EXPECT_FALSE(leaf_node->is_clipped());
- EXPECT_TRUE(leaf_node->render_target()->is_clipped());
- EXPECT_EQ(gfx::Rect(16, 16, 2000, 2000), leaf_node->drawable_content_rect());
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected_leaf_draw_transform_with_surfaces,
- leaf_node->DrawTransform());
+ GetRenderSurface(grand_child3)->clip_rect());
}
TEST_F(LayerTreeHostCommonTest, AnimationsForRenderSurfaceHierarchy) {
@@ -2581,33 +2104,37 @@ TEST_F(LayerTreeHostCommonTest, AnimationsForRenderSurfaceHierarchy) {
// Only layers that are associated with render surfaces should have an actual
// RenderSurface() value.
- ASSERT_TRUE(root->GetRenderSurface());
- ASSERT_FALSE(child_of_root->GetRenderSurface());
- ASSERT_FALSE(grand_child_of_root->GetRenderSurface());
-
- ASSERT_TRUE(render_surface1->GetRenderSurface());
- ASSERT_FALSE(child_of_rs1->GetRenderSurface());
- ASSERT_FALSE(grand_child_of_rs1->GetRenderSurface());
-
- ASSERT_TRUE(render_surface2->GetRenderSurface());
- ASSERT_FALSE(child_of_rs2->GetRenderSurface());
- ASSERT_FALSE(grand_child_of_rs2->GetRenderSurface());
+ ASSERT_TRUE(GetRenderSurface(root));
+ ASSERT_EQ(GetRenderSurface(child_of_root), GetRenderSurface(root));
+ ASSERT_EQ(GetRenderSurface(grand_child_of_root), GetRenderSurface(root));
+
+ ASSERT_NE(GetRenderSurface(render_surface1), GetRenderSurface(root));
+ ASSERT_EQ(GetRenderSurface(child_of_rs1), GetRenderSurface(render_surface1));
+ ASSERT_EQ(GetRenderSurface(grand_child_of_rs1),
+ GetRenderSurface(render_surface1));
+
+ ASSERT_NE(GetRenderSurface(render_surface2), GetRenderSurface(root));
+ ASSERT_NE(GetRenderSurface(render_surface2),
+ GetRenderSurface(render_surface1));
+ ASSERT_EQ(GetRenderSurface(child_of_rs2), GetRenderSurface(render_surface2));
+ ASSERT_EQ(GetRenderSurface(grand_child_of_rs2),
+ GetRenderSurface(render_surface2));
// Verify all render target accessors
- EXPECT_EQ(root->GetRenderSurface(), root->render_target());
- EXPECT_EQ(root->GetRenderSurface(), child_of_root->render_target());
- EXPECT_EQ(root->GetRenderSurface(), grand_child_of_root->render_target());
+ EXPECT_EQ(GetRenderSurface(root), root->render_target());
+ EXPECT_EQ(GetRenderSurface(root), child_of_root->render_target());
+ EXPECT_EQ(GetRenderSurface(root), grand_child_of_root->render_target());
- EXPECT_EQ(render_surface1->GetRenderSurface(),
+ EXPECT_EQ(GetRenderSurface(render_surface1),
render_surface1->render_target());
- EXPECT_EQ(render_surface1->GetRenderSurface(), child_of_rs1->render_target());
- EXPECT_EQ(render_surface1->GetRenderSurface(),
+ EXPECT_EQ(GetRenderSurface(render_surface1), child_of_rs1->render_target());
+ EXPECT_EQ(GetRenderSurface(render_surface1),
grand_child_of_rs1->render_target());
- EXPECT_EQ(render_surface2->GetRenderSurface(),
+ EXPECT_EQ(GetRenderSurface(render_surface2),
render_surface2->render_target());
- EXPECT_EQ(render_surface2->GetRenderSurface(), child_of_rs2->render_target());
- EXPECT_EQ(render_surface2->GetRenderSurface(),
+ EXPECT_EQ(GetRenderSurface(render_surface2), child_of_rs2->render_target());
+ EXPECT_EQ(GetRenderSurface(render_surface2),
grand_child_of_rs2->render_target());
// Verify screen_space_transform_is_animating values
@@ -2662,6 +2189,11 @@ TEST_F(LayerTreeHostCommonTest, LargeTransforms) {
EXPECT_EQ(gfx::Rect(), grand_child->visible_layer_rect());
}
+static bool TransformIsAnimating(LayerImpl* layer) {
+ return layer->GetMutatorHost()->IsAnimatingTransformProperty(
+ layer->element_id(), layer->GetElementTypeForAnimation());
+}
+
TEST_F(LayerTreeHostCommonTest,
ScreenSpaceTransformIsAnimatingWithDelayedAnimation) {
LayerImpl* root = root_layer_for_testing();
@@ -2694,7 +2226,7 @@ TEST_F(LayerTreeHostCommonTest,
EXPECT_FALSE(root->screen_space_transform_is_animating());
EXPECT_FALSE(child->screen_space_transform_is_animating());
- EXPECT_FALSE(grand_child->TransformIsAnimating());
+ EXPECT_FALSE(TransformIsAnimating(grand_child));
EXPECT_TRUE(grand_child->HasPotentiallyRunningTransformAnimation());
EXPECT_TRUE(grand_child->screen_space_transform_is_animating());
EXPECT_TRUE(great_grand_child->screen_space_transform_is_animating());
@@ -3031,7 +2563,7 @@ TEST_F(LayerTreeHostCommonTest,
ExecuteCalculateDrawProperties(root);
EXPECT_EQ(gfx::RectF(100.f, 100.f),
- root->GetRenderSurface()->DrawableContentRect());
+ GetRenderSurface(root)->DrawableContentRect());
// In target space, not clipped.
EXPECT_EQ(gfx::Rect(60, 70, 100, 100), root->drawable_content_rect());
// In layer space, clipped.
@@ -3056,7 +2588,7 @@ TEST_F(LayerTreeHostCommonTest, DrawableAndVisibleContentRectsForSimpleLayers) {
ExecuteCalculateDrawProperties(root);
EXPECT_EQ(gfx::RectF(100.f, 100.f),
- root->GetRenderSurface()->DrawableContentRect());
+ GetRenderSurface(root)->DrawableContentRect());
// Layers that do not draw content should have empty visible_layer_rects.
EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_layer_rect());
@@ -3095,7 +2627,7 @@ TEST_F(LayerTreeHostCommonTest,
ExecuteCalculateDrawProperties(root);
EXPECT_EQ(gfx::RectF(100.f, 100.f),
- root->GetRenderSurface()->DrawableContentRect());
+ GetRenderSurface(root)->DrawableContentRect());
// Layers that do not draw content should have empty visible content rects.
EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_layer_rect());
@@ -3152,7 +2684,7 @@ TEST_F(LayerTreeHostCommonTest, VisibleRectWithClippingAndFilters) {
ExecuteCalculateDrawProperties(root);
EXPECT_EQ(gfx::Rect(50, 50, 10, 10), filter_child->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(10, 10), filter->GetRenderSurface()->content_rect());
+ EXPECT_EQ(gfx::Rect(10, 10), GetRenderSurface(filter)->content_rect());
FilterOperations blur_filter;
blur_filter.Append(FilterOperation::CreateBlurFilter(4.0f));
@@ -3163,7 +2695,7 @@ TEST_F(LayerTreeHostCommonTest, VisibleRectWithClippingAndFilters) {
EXPECT_EQ(gfx::Rect(38, 38, 34, 34), filter_child->visible_layer_rect());
EXPECT_EQ(gfx::Rect(-12, -12, 34, 34),
- filter->GetRenderSurface()->content_rect());
+ GetRenderSurface(filter)->content_rect());
gfx::Transform vertical_flip;
vertical_flip.Scale(1, -1);
@@ -3180,7 +2712,7 @@ TEST_F(LayerTreeHostCommonTest, VisibleRectWithClippingAndFilters) {
EXPECT_EQ(gfx::Rect(50, 40, 10, 20), filter_child->visible_layer_rect());
EXPECT_EQ(gfx::Rect(0, -10, 10, 20),
- filter->GetRenderSurface()->content_rect());
+ GetRenderSurface(filter)->content_rect());
}
TEST_F(LayerTreeHostCommonTest, VisibleRectWithScalingClippingAndFilters) {
@@ -3205,7 +2737,7 @@ TEST_F(LayerTreeHostCommonTest, VisibleRectWithScalingClippingAndFilters) {
ExecuteCalculateDrawProperties(root);
EXPECT_EQ(gfx::Rect(50, 50, 10, 10), filter_child->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(30, 30), filter->GetRenderSurface()->content_rect());
+ EXPECT_EQ(gfx::Rect(30, 30), GetRenderSurface(filter)->content_rect());
FilterOperations blur_filter;
blur_filter.Append(FilterOperation::CreateBlurFilter(4.0f));
@@ -3216,7 +2748,7 @@ TEST_F(LayerTreeHostCommonTest, VisibleRectWithScalingClippingAndFilters) {
EXPECT_EQ(gfx::Rect(38, 38, 34, 34), filter_child->visible_layer_rect());
EXPECT_EQ(gfx::Rect(-36, -36, 102, 102),
- filter->GetRenderSurface()->content_rect());
+ GetRenderSurface(filter)->content_rect());
gfx::Transform vertical_flip;
vertical_flip.Scale(1, -1);
@@ -3233,7 +2765,7 @@ TEST_F(LayerTreeHostCommonTest, VisibleRectWithScalingClippingAndFilters) {
EXPECT_EQ(gfx::Rect(50, 40, 10, 20), filter_child->visible_layer_rect());
EXPECT_EQ(gfx::Rect(0, -30, 30, 60),
- filter->GetRenderSurface()->content_rect());
+ GetRenderSurface(filter)->content_rect());
}
TEST_F(LayerTreeHostCommonTest, ClipRectWithClipParentAndFilters) {
@@ -3331,10 +2863,10 @@ TEST_F(LayerTreeHostCommonTest,
child3->SetDrawsContent(true);
ExecuteCalculateDrawProperties(root);
- ASSERT_TRUE(render_surface->GetRenderSurface());
+ ASSERT_TRUE(GetRenderSurface(render_surface));
EXPECT_EQ(gfx::RectF(100.f, 100.f),
- root->GetRenderSurface()->DrawableContentRect());
+ GetRenderSurface(root)->DrawableContentRect());
// Layers that do not draw content should have empty visible content rects.
EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_layer_rect());
@@ -3343,7 +2875,7 @@ TEST_F(LayerTreeHostCommonTest,
// An unclipped surface grows its DrawableContentRect to include all drawable
// regions of the subtree.
EXPECT_EQ(gfx::RectF(5.f, 5.f, 170.f, 170.f),
- render_surface->GetRenderSurface()->DrawableContentRect());
+ GetRenderSurface(render_surface)->DrawableContentRect());
// All layers that draw content into the unclipped surface are also unclipped.
// Only the viewport clip should apply
@@ -3357,184 +2889,6 @@ TEST_F(LayerTreeHostCommonTest,
}
TEST_F(LayerTreeHostCommonTest,
- DrawableAndVisibleRectsWhenCannotRenderToSeparateSurface) {
- LayerImpl* root = root_layer_for_testing();
- LayerImpl* parent = AddChild<LayerImpl>(root);
- LayerImpl* child1 = AddChild<LayerImpl>(parent);
- LayerImpl* child2 = AddChild<LayerImpl>(parent);
- LayerImpl* grand_child1 = AddChild<LayerImpl>(child1);
- LayerImpl* grand_child2 = AddChild<LayerImpl>(child2);
- LayerImpl* leaf_node1 = AddChild<LayerImpl>(grand_child1);
- LayerImpl* leaf_node2 = AddChild<LayerImpl>(grand_child2);
-
- root->SetBounds(gfx::Size(100, 100));
- parent->SetPosition(gfx::PointF(2.f, 2.f));
- parent->SetBounds(gfx::Size(400, 400));
- child1->SetPosition(gfx::PointF(4.f, 4.f));
- child1->SetBounds(gfx::Size(800, 800));
- child1->test_properties()->force_render_surface = true;
- child2->SetPosition(gfx::PointF(3.f, 3.f));
- child2->SetBounds(gfx::Size(800, 800));
- child2->test_properties()->force_render_surface = true;
- grand_child1->SetPosition(gfx::PointF(8.f, 8.f));
- grand_child1->SetBounds(gfx::Size(1500, 1500));
- grand_child2->SetPosition(gfx::PointF(7.f, 7.f));
- grand_child2->SetBounds(gfx::Size(1500, 1500));
- leaf_node1->SetPosition(gfx::PointF(16.f, 16.f));
- leaf_node1->SetBounds(gfx::Size(2000, 2000));
- leaf_node2->SetPosition(gfx::PointF(9.f, 9.f));
- leaf_node2->SetBounds(gfx::Size(2000, 2000));
-
- root->SetDrawsContent(true);
- parent->SetDrawsContent(true);
- child1->SetDrawsContent(true);
- child2->SetDrawsContent(true);
- grand_child1->SetDrawsContent(true);
- grand_child2->SetDrawsContent(true);
- leaf_node1->SetDrawsContent(true);
- leaf_node2->SetDrawsContent(true);
-
- // Case 1: No layers clip. Visible rects are clipped by the viewport.
- // Each layer's drawable content rect is its bounds in target space; the only
- // thing that changes with surfaces disabled is that target space is always
- // screen space.
- child1->test_properties()->force_render_surface = true;
- child2->test_properties()->force_render_surface = true;
- ExecuteCalculateDrawProperties(root);
- EXPECT_EQ(gfx::Rect(100, 100), root->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(0, 0, 98, 98), parent->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(94, 94), child1->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(95, 95), child2->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(86, 86), grand_child1->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(88, 88), grand_child2->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(70, 70), leaf_node1->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(79, 79), leaf_node2->visible_layer_rect());
-
- EXPECT_EQ(gfx::Rect(100, 100), root->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(2, 2, 400, 400), parent->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(800, 800), child1->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(800, 800), child2->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(8, 8, 1500, 1500), grand_child1->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(7, 7, 1500, 1500), grand_child2->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(24, 24, 2000, 2000), leaf_node1->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(16, 16, 2000, 2000), leaf_node2->drawable_content_rect());
-
- ExecuteCalculateDrawPropertiesWithoutSeparateSurfaces(root);
- EXPECT_EQ(gfx::Rect(100, 100), root->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(98, 98), parent->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(94, 94), child1->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(95, 95), child2->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(86, 86), grand_child1->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(88, 88), grand_child2->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(70, 70), leaf_node1->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(79, 79), leaf_node2->visible_layer_rect());
-
- EXPECT_EQ(gfx::Rect(100, 100), root->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(2, 2, 400, 400), parent->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(6, 6, 800, 800), child1->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(5, 5, 800, 800), child2->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(14, 14, 1500, 1500),
- grand_child1->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(12, 12, 1500, 1500),
- grand_child2->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(30, 30, 2000, 2000), leaf_node1->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(21, 21, 2000, 2000), leaf_node2->drawable_content_rect());
-
- // Case 2: The parent clips. In this case, neither surface is unclipped, so
- // all visible layer rects are clipped by the intersection of all ancestor
- // clips, whether or not surfaces are disabled. However, drawable content
- // rects are clipped only until the next render surface is reached, so
- // descendants of parent have their drawable content rects clipped only when
- // surfaces are disabled.
- parent->SetMasksToBounds(true);
- host_impl()->active_tree()->property_trees()->needs_rebuild = true;
- ExecuteCalculateDrawProperties(root);
- EXPECT_EQ(gfx::Rect(100, 100), root->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(98, 98), parent->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(94, 94), child1->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(95, 95), child2->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(86, 86), grand_child1->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(88, 88), grand_child2->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(70, 70), leaf_node1->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(79, 79), leaf_node2->visible_layer_rect());
-
- EXPECT_EQ(gfx::Rect(100, 100), root->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(2, 2, 400, 400), parent->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(800, 800), child1->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(800, 800), child2->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(8, 8, 1500, 1500), grand_child1->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(7, 7, 1500, 1500), grand_child2->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(24, 24, 2000, 2000), leaf_node1->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(16, 16, 2000, 2000), leaf_node2->drawable_content_rect());
-
- ExecuteCalculateDrawPropertiesWithoutSeparateSurfaces(root);
- EXPECT_EQ(gfx::Rect(100, 100), root->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(98, 98), parent->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(94, 94), child1->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(95, 95), child2->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(86, 86), grand_child1->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(88, 88), grand_child2->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(70, 70), leaf_node1->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(79, 79), leaf_node2->visible_layer_rect());
-
- EXPECT_EQ(gfx::Rect(100, 100), root->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(2, 2, 400, 400), parent->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(6, 6, 396, 396), child1->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(5, 5, 397, 397), child2->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(14, 14, 388, 388), grand_child1->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(12, 12, 390, 390), grand_child2->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(30, 30, 372, 372), leaf_node1->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(21, 21, 381, 381), leaf_node2->drawable_content_rect());
-
- parent->SetMasksToBounds(false);
-
- // Case 3: child1 and grand_child2 clip. In this case, descendants of these
- // layers have their visible rects clipped by them; Similarly, descendants of
- // these layers have their drawable content rects clipped by them.
- child1->SetMasksToBounds(true);
- grand_child2->SetMasksToBounds(true);
- host_impl()->active_tree()->property_trees()->needs_rebuild = true;
- ExecuteCalculateDrawProperties(root);
- EXPECT_EQ(gfx::Rect(100, 100), root->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(98, 98), parent->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(94, 94), child1->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(95, 95), child2->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(86, 86), grand_child1->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(88, 88), grand_child2->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(70, 70), leaf_node1->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(79, 79), leaf_node2->visible_layer_rect());
-
- EXPECT_EQ(gfx::Rect(100, 100), root->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(2, 2, 400, 400), parent->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(800, 800), child1->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(800, 800), child2->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(8, 8, 792, 792), grand_child1->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(7, 7, 1500, 1500), grand_child2->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(24, 24, 776, 776), leaf_node1->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(16, 16, 1491, 1491), leaf_node2->drawable_content_rect());
-
- ExecuteCalculateDrawPropertiesWithoutSeparateSurfaces(root);
- EXPECT_EQ(gfx::Rect(100, 100), root->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(98, 98), parent->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(94, 94), child1->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(95, 95), child2->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(86, 86), grand_child1->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(88, 88), grand_child2->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(70, 70), leaf_node1->visible_layer_rect());
- EXPECT_EQ(gfx::Rect(79, 79), leaf_node2->visible_layer_rect());
-
- EXPECT_EQ(gfx::Rect(100, 100), root->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(2, 2, 400, 400), parent->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(6, 6, 800, 800), child1->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(5, 5, 800, 800), child2->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(14, 14, 792, 792), grand_child1->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(12, 12, 1500, 1500),
- grand_child2->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(30, 30, 776, 776), leaf_node1->drawable_content_rect());
- EXPECT_EQ(gfx::Rect(21, 21, 1491, 1491), leaf_node2->drawable_content_rect());
-}
-
-TEST_F(LayerTreeHostCommonTest,
VisibleContentRectsForClippedSurfaceWithEmptyClip) {
LayerImpl* root = root_layer_for_testing();
LayerImpl* child1 = AddChild<LayerImpl>(root);
@@ -3552,18 +2906,18 @@ TEST_F(LayerTreeHostCommonTest,
child3->SetBounds(gfx::Size(50, 50));
child3->SetDrawsContent(true);
- LayerImplList render_surface_layer_list_impl;
+ RenderSurfaceList render_surface_list_impl;
// Now set the root render surface an empty clip.
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root, gfx::Size(), &render_surface_layer_list_impl);
+ root, gfx::Size(), &render_surface_list_impl);
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
- ASSERT_TRUE(root->GetRenderSurface());
+ ASSERT_TRUE(GetRenderSurface(root));
EXPECT_FALSE(root->is_clipped());
gfx::Rect empty;
- EXPECT_EQ(empty, root->GetRenderSurface()->clip_rect());
- EXPECT_TRUE(root->GetRenderSurface()->is_clipped());
+ EXPECT_EQ(empty, GetRenderSurface(root)->clip_rect());
+ EXPECT_TRUE(GetRenderSurface(root)->is_clipped());
// Visible content rect calculation will check if the target surface is
// clipped or not. An empty clip rect does not indicate the render surface
@@ -3717,11 +3071,11 @@ TEST_F(LayerTreeHostCommonTest, OcclusionBySiblingOfTarget) {
host_impl.active_tree()->UpdateDrawProperties(update_lcd_text);
EXPECT_TRANSFORMATION_MATRIX_EQ(
- surface_ptr->GetRenderSurface()->draw_transform(), translate);
+ GetRenderSurface(surface_ptr)->draw_transform(), translate);
// surface_sibling draws into the root render surface and occludes
// surface_child's contents.
Occlusion actual_occlusion =
- surface_child_ptr->GetRenderSurface()->occlusion_in_content_space();
+ GetRenderSurface(surface_child_ptr)->occlusion_in_content_space();
Occlusion expected_occlusion(translate, SimpleEnclosedRegion(gfx::Rect()),
SimpleEnclosedRegion(gfx::Rect(200, 200)));
EXPECT_TRUE(expected_occlusion.IsEqual(actual_occlusion));
@@ -3874,10 +3228,10 @@ TEST_F(LayerTreeHostCommonTest,
child3->SetDrawsContent(true);
ExecuteCalculateDrawProperties(root);
- ASSERT_TRUE(render_surface->GetRenderSurface());
+ ASSERT_TRUE(GetRenderSurface(render_surface));
EXPECT_EQ(gfx::RectF(100.f, 100.f),
- root->GetRenderSurface()->DrawableContentRect());
+ GetRenderSurface(root)->DrawableContentRect());
// Layers that do not draw content should have empty visible content rects.
EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_layer_rect());
@@ -3886,7 +3240,7 @@ TEST_F(LayerTreeHostCommonTest,
// A clipped surface grows its DrawableContentRect to include all drawable
// regions of the subtree, but also gets clamped by the ancestor's clip.
EXPECT_EQ(gfx::RectF(5.f, 5.f, 95.f, 95.f),
- render_surface->GetRenderSurface()->DrawableContentRect());
+ GetRenderSurface(render_surface)->DrawableContentRect());
// All layers that draw content into the surface have their visible content
// rect clipped by the surface clip rect.
@@ -3927,11 +3281,11 @@ TEST_F(LayerTreeHostCommonTest,
child3->SetDrawsContent(true);
ExecuteCalculateDrawProperties(root);
- ASSERT_TRUE(render_surface1->GetRenderSurface());
- ASSERT_TRUE(render_surface2->GetRenderSurface());
+ ASSERT_TRUE(GetRenderSurface(render_surface1));
+ ASSERT_TRUE(GetRenderSurface(render_surface2));
EXPECT_EQ(gfx::RectF(100.f, 100.f),
- root->GetRenderSurface()->DrawableContentRect());
+ GetRenderSurface(root)->DrawableContentRect());
// Layers that do not draw content should have empty visible content rects.
EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_layer_rect());
@@ -3941,13 +3295,13 @@ TEST_F(LayerTreeHostCommonTest,
// A clipped surface grows its DrawableContentRect to include all drawable
// regions of the subtree, but also gets clamped by the ancestor's clip.
EXPECT_EQ(gfx::RectF(5.f, 5.f, 95.f, 95.f),
- render_surface1->GetRenderSurface()->DrawableContentRect());
+ GetRenderSurface(render_surface1)->DrawableContentRect());
// render_surface1 lives in the "unclipped universe" of render_surface1, and
// is only implicitly clipped by render_surface1's content rect. So,
// render_surface2 grows to enclose all drawable content of its subtree.
EXPECT_EQ(gfx::RectF(5.f, 5.f, 170.f, 170.f),
- render_surface2->GetRenderSurface()->DrawableContentRect());
+ GetRenderSurface(render_surface2)->DrawableContentRect());
// All layers that draw content into render_surface2 think they are unclipped
// by the surface. So, only the viewport clip applies.
@@ -4058,12 +3412,11 @@ TEST_F(LayerTreeHostCommonTest, ClipRectOfSurfaceWhoseParentIsAClipChild) {
float device_scale_factor = 1.f;
ExecuteCalculateDrawProperties(root, device_scale_factor);
- EXPECT_EQ(gfx::Rect(50, 50),
- render_surface2->GetRenderSurface()->clip_rect());
+ EXPECT_EQ(gfx::Rect(50, 50), GetRenderSurface(render_surface2)->clip_rect());
device_scale_factor = 2.f;
ExecuteCalculateDrawProperties(root, device_scale_factor);
EXPECT_EQ(gfx::Rect(100, 100),
- render_surface2->GetRenderSurface()->clip_rect());
+ GetRenderSurface(render_surface2)->clip_rect());
}
TEST_F(LayerTreeHostCommonTest, RenderSurfaceContentRectWhenLayerNotDrawn) {
@@ -4079,11 +3432,11 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceContentRectWhenLayerNotDrawn) {
test_layer->SetBounds(gfx::Size(150, 150));
ExecuteCalculateDrawProperties(root);
- EXPECT_EQ(gfx::Rect(100, 100), surface->GetRenderSurface()->content_rect());
+ EXPECT_EQ(gfx::Rect(100, 100), GetRenderSurface(surface)->content_rect());
test_layer->SetDrawsContent(true);
ExecuteCalculateDrawProperties(root);
- EXPECT_EQ(gfx::Rect(150, 150), surface->GetRenderSurface()->content_rect());
+ EXPECT_EQ(gfx::Rect(150, 150), GetRenderSurface(surface)->content_rect());
}
TEST_F(LayerTreeHostCommonTest, VisibleRectsMultipleSurfaces) {
@@ -4191,10 +3544,10 @@ TEST_F(LayerTreeHostCommonTest,
child1->test_properties()->transform_origin = gfx::Point3F(25.f, 25.f, 0.f);
ExecuteCalculateDrawProperties(root);
- ASSERT_TRUE(render_surface->GetRenderSurface());
+ ASSERT_TRUE(GetRenderSurface(render_surface));
EXPECT_EQ(gfx::RectF(100.f, 100.f),
- root->GetRenderSurface()->DrawableContentRect());
+ GetRenderSurface(root)->DrawableContentRect());
// Layers that do not draw content should have empty visible content rects.
EXPECT_EQ(gfx::Rect(0, 0, 0, 0), root->visible_layer_rect());
@@ -4209,7 +3562,7 @@ TEST_F(LayerTreeHostCommonTest,
diagonal_radius * 2,
diagonal_radius * 2);
EXPECT_EQ(gfx::RectF(expected_surface_drawable_content),
- render_surface->GetRenderSurface()->DrawableContentRect());
+ GetRenderSurface(render_surface)->DrawableContentRect());
// All layers that draw content into the unclipped surface are also unclipped.
EXPECT_EQ(gfx::Rect(0, 0, 50, 50), child1->visible_layer_rect());
@@ -4238,7 +3591,7 @@ TEST_F(LayerTreeHostCommonTest,
child1->test_properties()->transform_origin = gfx::Point3F(25.f, 25.f, 0.f);
ExecuteCalculateDrawProperties(root);
- ASSERT_TRUE(render_surface->GetRenderSurface());
+ ASSERT_TRUE(GetRenderSurface(render_surface));
// The clipped surface clamps the DrawableContentRect that encloses the
// rotated layer.
@@ -4250,7 +3603,7 @@ TEST_F(LayerTreeHostCommonTest,
gfx::RectF expected_surface_drawable_content(
gfx::IntersectRects(unclipped_surface_content, gfx::Rect(50, 50)));
EXPECT_EQ(expected_surface_drawable_content,
- render_surface->GetRenderSurface()->DrawableContentRect());
+ GetRenderSurface(render_surface)->DrawableContentRect());
// On the clipped surface, only a quarter of the child1 is visible, but when
// rotating it back to child1's content space, the actual enclosing rect ends
@@ -4296,20 +3649,20 @@ TEST_F(LayerTreeHostCommonTest, DrawableAndVisibleContentRectsInHighDPI) {
float device_scale_factor = 2.f;
ExecuteCalculateDrawProperties(root, device_scale_factor);
- ASSERT_TRUE(render_surface1->GetRenderSurface());
- ASSERT_TRUE(render_surface2->GetRenderSurface());
+ ASSERT_TRUE(GetRenderSurface(render_surface1));
+ ASSERT_TRUE(GetRenderSurface(render_surface2));
// drawable_content_rects for all layers and surfaces are scaled by
// device_scale_factor.
EXPECT_EQ(gfx::RectF(200.f, 200.f),
- root->GetRenderSurface()->DrawableContentRect());
+ GetRenderSurface(root)->DrawableContentRect());
EXPECT_EQ(gfx::RectF(10.f, 10.f, 190.f, 190.f),
- render_surface1->GetRenderSurface()->DrawableContentRect());
+ GetRenderSurface(render_surface1)->DrawableContentRect());
// render_surface2 lives in the "unclipped universe" of render_surface1, and
// is only implicitly clipped by render_surface1.
EXPECT_EQ(gfx::RectF(10.f, 10.f, 350.f, 350.f),
- render_surface2->GetRenderSurface()->DrawableContentRect());
+ GetRenderSurface(render_surface2)->DrawableContentRect());
EXPECT_EQ(gfx::Rect(10, 10, 100, 100), child1->drawable_content_rect());
EXPECT_EQ(gfx::Rect(150, 150, 100, 100), child2->drawable_content_rect());
@@ -4401,14 +3754,20 @@ TEST_F(LayerTreeHostCommonTest, BackFaceCullingWithoutPreserves3d) {
ExecuteCalculateDrawPropertiesAndSaveUpdateLayerList(root);
// Verify which render surfaces were created.
- EXPECT_FALSE(front_facing_child->GetRenderSurface());
- EXPECT_FALSE(back_facing_child->GetRenderSurface());
- EXPECT_TRUE(front_facing_surface->GetRenderSurface());
- EXPECT_TRUE(back_facing_surface->GetRenderSurface());
- EXPECT_FALSE(front_facing_child_of_front_facing_surface->GetRenderSurface());
- EXPECT_FALSE(back_facing_child_of_front_facing_surface->GetRenderSurface());
- EXPECT_FALSE(front_facing_child_of_back_facing_surface->GetRenderSurface());
- EXPECT_FALSE(back_facing_child_of_back_facing_surface->GetRenderSurface());
+ EXPECT_EQ(GetRenderSurface(front_facing_child), GetRenderSurface(root));
+ EXPECT_EQ(GetRenderSurface(back_facing_child), GetRenderSurface(root));
+ EXPECT_NE(GetRenderSurface(front_facing_surface), GetRenderSurface(root));
+ EXPECT_NE(GetRenderSurface(back_facing_surface), GetRenderSurface(root));
+ EXPECT_NE(GetRenderSurface(back_facing_surface),
+ GetRenderSurface(front_facing_surface));
+ EXPECT_EQ(GetRenderSurface(front_facing_child_of_front_facing_surface),
+ GetRenderSurface(front_facing_surface));
+ EXPECT_EQ(GetRenderSurface(back_facing_child_of_front_facing_surface),
+ GetRenderSurface(front_facing_surface));
+ EXPECT_EQ(GetRenderSurface(front_facing_child_of_back_facing_surface),
+ GetRenderSurface(back_facing_surface));
+ EXPECT_EQ(GetRenderSurface(back_facing_child_of_back_facing_surface),
+ GetRenderSurface(back_facing_surface));
EXPECT_EQ(3u, update_layer_list_impl()->size());
EXPECT_TRUE(UpdateLayerListImplContains(front_facing_child->id()));
@@ -4509,15 +3868,21 @@ TEST_F(LayerTreeHostCommonTest, BackFaceCullingWithPreserves3d) {
ExecuteCalculateDrawPropertiesAndSaveUpdateLayerList(root);
// Verify which render surfaces were created and used.
- EXPECT_FALSE(front_facing_child->GetRenderSurface());
- EXPECT_FALSE(back_facing_child->GetRenderSurface());
- EXPECT_TRUE(front_facing_surface->GetRenderSurface());
+ EXPECT_EQ(GetRenderSurface(front_facing_child), GetRenderSurface(root));
+ EXPECT_EQ(GetRenderSurface(back_facing_child), GetRenderSurface(root));
+ EXPECT_NE(GetRenderSurface(front_facing_surface), GetRenderSurface(root));
// We expect that a has_render_surface was created but not used.
- EXPECT_TRUE(back_facing_surface->GetRenderSurface());
- EXPECT_FALSE(front_facing_child_of_front_facing_surface->GetRenderSurface());
- EXPECT_FALSE(back_facing_child_of_front_facing_surface->GetRenderSurface());
- EXPECT_FALSE(front_facing_child_of_back_facing_surface->GetRenderSurface());
- EXPECT_FALSE(back_facing_child_of_back_facing_surface->GetRenderSurface());
+ EXPECT_NE(GetRenderSurface(back_facing_surface), GetRenderSurface(root));
+ EXPECT_NE(GetRenderSurface(back_facing_surface),
+ GetRenderSurface(front_facing_surface));
+ EXPECT_EQ(GetRenderSurface(front_facing_child_of_front_facing_surface),
+ GetRenderSurface(front_facing_surface));
+ EXPECT_EQ(GetRenderSurface(back_facing_child_of_front_facing_surface),
+ GetRenderSurface(front_facing_surface));
+ EXPECT_EQ(GetRenderSurface(front_facing_child_of_back_facing_surface),
+ GetRenderSurface(back_facing_surface));
+ EXPECT_EQ(GetRenderSurface(back_facing_child_of_back_facing_surface),
+ GetRenderSurface(back_facing_surface));
EXPECT_EQ(3u, update_layer_list_impl()->size());
@@ -4583,11 +3948,12 @@ TEST_F(LayerTreeHostCommonTest, BackFaceCullingWithAnimatingTransforms) {
ExecuteCalculateDrawPropertiesAndSaveUpdateLayerList(root);
- EXPECT_FALSE(child->GetRenderSurface());
- EXPECT_TRUE(animating_surface->GetRenderSurface());
- EXPECT_FALSE(child_of_animating_surface->GetRenderSurface());
- EXPECT_FALSE(animating_child->GetRenderSurface());
- EXPECT_FALSE(child2->GetRenderSurface());
+ EXPECT_EQ(GetRenderSurface(child), GetRenderSurface(root));
+ EXPECT_TRUE(GetRenderSurface(animating_surface));
+ EXPECT_EQ(GetRenderSurface(child_of_animating_surface),
+ GetRenderSurface(animating_surface));
+ EXPECT_EQ(GetRenderSurface(animating_child), GetRenderSurface(root));
+ EXPECT_EQ(GetRenderSurface(child2), GetRenderSurface(root));
EXPECT_EQ(1u, update_layer_list_impl()->size());
@@ -4643,12 +4009,12 @@ TEST_F(LayerTreeHostCommonTest,
ExecuteCalculateDrawPropertiesAndSaveUpdateLayerList(root);
// Verify which render surfaces were created and used.
- EXPECT_TRUE(front_facing_surface->GetRenderSurface());
+ EXPECT_TRUE(GetRenderSurface(front_facing_surface));
// We expect the render surface to have been created, but remain unused.
- EXPECT_TRUE(back_facing_surface->GetRenderSurface());
- EXPECT_FALSE(child1->GetRenderSurface());
- EXPECT_FALSE(child2->GetRenderSurface());
+ EXPECT_NE(GetRenderSurface(back_facing_surface), GetRenderSurface(root));
+ EXPECT_EQ(GetRenderSurface(child1), GetRenderSurface(front_facing_surface));
+ EXPECT_EQ(GetRenderSurface(child2), GetRenderSurface(back_facing_surface));
EXPECT_EQ(2u, update_layer_list_impl()->size());
EXPECT_TRUE(UpdateLayerListImplContains(front_facing_surface->id()));
@@ -4679,7 +4045,7 @@ TEST_F(LayerTreeHostCommonScalingTest, LayerTransformsInHighDPI) {
EXPECT_FLOAT_EQ(device_scale_factor, child->GetIdealContentsScale());
EXPECT_FLOAT_EQ(device_scale_factor, child2->GetIdealContentsScale());
- EXPECT_EQ(1u, render_surface_layer_list_impl()->size());
+ EXPECT_EQ(1u, render_surface_list_impl()->size());
// Verify root transforms
gfx::Transform expected_root_transform;
@@ -4774,9 +4140,9 @@ TEST_F(LayerTreeHostCommonScalingTest, SurfaceLayerTransformsInHighDPI) {
float device_scale_factor = 2.5f;
float page_scale_factor = 3.f;
- root->layer_tree_impl()->SetViewportLayersFromIds(
- Layer::INVALID_ID, page_scale->id(), Layer::INVALID_ID,
- Layer::INVALID_ID);
+ LayerTreeImpl::ViewportLayerIds viewport_ids;
+ viewport_ids.page_scale = page_scale->id();
+ root->layer_tree_impl()->SetViewportLayersFromIds(viewport_ids);
root->layer_tree_impl()->BuildLayerListAndPropertyTreesForTesting();
root->layer_tree_impl()->SetPageScaleOnActiveTree(page_scale_factor);
ExecuteCalculateDrawProperties(root, device_scale_factor, page_scale_factor,
@@ -4806,7 +4172,7 @@ TEST_F(LayerTreeHostCommonScalingTest, SurfaceLayerTransformsInHighDPI) {
std::max(target_space_transform_scales.x(),
target_space_transform_scales.y()));
- EXPECT_EQ(3u, render_surface_layer_list_impl()->size());
+ EXPECT_EQ(3u, render_surface_list_impl()->size());
gfx::Transform expected_parent_draw_transform;
expected_parent_draw_transform.Scale(device_scale_factor * page_scale_factor,
@@ -4832,7 +4198,7 @@ TEST_F(LayerTreeHostCommonScalingTest, SurfaceLayerTransformsInHighDPI) {
device_scale_factor * page_scale_factor);
EXPECT_TRANSFORMATION_MATRIX_EQ(
expected_perspective_surface_draw_transform,
- perspective_surface->GetRenderSurface()->draw_transform());
+ GetRenderSurface(perspective_surface)->draw_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(
expected_perspective_surface_layer_draw_transform,
perspective_surface->DrawTransform());
@@ -4937,7 +4303,7 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceTransformsInHighDPI) {
// We should have two render surfaces. The root's render surface and child's
// render surface (it needs one because of force_render_surface).
- EXPECT_EQ(2u, render_surface_layer_list_impl()->size());
+ EXPECT_EQ(2u, render_surface_list_impl()->size());
gfx::Transform expected_parent_transform;
expected_parent_transform.Scale(device_scale_factor, device_scale_factor);
@@ -4975,20 +4341,20 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceTransformsInHighDPI) {
device_scale_factor * child->position().x(),
device_scale_factor * child->position().y());
EXPECT_TRANSFORMATION_MATRIX_EQ(expected_render_surface_draw_transform,
- child->GetRenderSurface()->draw_transform());
+ GetRenderSurface(child)->draw_transform());
gfx::Transform expected_surface_draw_transform;
expected_surface_draw_transform.Translate(device_scale_factor * 2.f,
device_scale_factor * 2.f);
EXPECT_TRANSFORMATION_MATRIX_EQ(expected_surface_draw_transform,
- child->GetRenderSurface()->draw_transform());
+ GetRenderSurface(child)->draw_transform());
gfx::Transform expected_surface_screen_space_transform;
expected_surface_screen_space_transform.Translate(device_scale_factor * 2.f,
device_scale_factor * 2.f);
EXPECT_TRANSFORMATION_MATRIX_EQ(
expected_surface_screen_space_transform,
- child->GetRenderSurface()->screen_space_transform());
+ GetRenderSurface(child)->screen_space_transform());
}
TEST_F(LayerTreeHostCommonTest,
@@ -5007,14 +4373,14 @@ TEST_F(LayerTreeHostCommonTest,
// We should have two render surfaces. The root's render surface and child's
// render surface (it needs one because of force_render_surface).
- EXPECT_EQ(2u, render_surface_layer_list_impl()->size());
+ EXPECT_EQ(2u, render_surface_list_impl()->size());
EXPECT_TRANSFORMATION_MATRIX_EQ(gfx::Transform(),
- child->GetRenderSurface()->draw_transform());
+ GetRenderSurface(child)->draw_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(gfx::Transform(),
- child->GetRenderSurface()->draw_transform());
+ GetRenderSurface(child)->draw_transform());
EXPECT_TRANSFORMATION_MATRIX_EQ(
- gfx::Transform(), child->GetRenderSurface()->screen_space_transform());
+ gfx::Transform(), GetRenderSurface(child)->screen_space_transform());
}
TEST_F(LayerTreeHostCommonTest, LayerSearch) {
@@ -5048,7 +4414,7 @@ TEST_F(LayerTreeHostCommonTest, TransparentChildRenderSurfaceCreation) {
grand_child->SetBounds(gfx::Size(10, 10));
grand_child->SetDrawsContent(true);
ExecuteCalculateDrawProperties(root);
- EXPECT_FALSE(child->GetRenderSurface());
+ EXPECT_EQ(GetRenderSurface(child), GetRenderSurface(root));
}
TEST_F(LayerTreeHostCommonTest, OpacityAnimatingOnPendingTree) {
@@ -5085,24 +4451,24 @@ TEST_F(LayerTreeHostCommonTest, OpacityAnimatingOnPendingTree) {
AddOpacityTransitionToElementWithPlayer(child_element_id, timeline, 10.0,
0.0f, 1.0f, false);
- LayerImplList render_surface_layer_list;
+ RenderSurfaceList render_surface_list;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root_layer, root_layer->bounds(), &render_surface_layer_list);
+ root_layer, root_layer->bounds(), &render_surface_list);
inputs.can_adjust_raster_scales = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
// We should have one render surface and two layers. The child
// layer should be included even though it is transparent.
- ASSERT_EQ(1u, render_surface_layer_list.size());
- ASSERT_EQ(2u, root_layer->GetRenderSurface()->layer_list().size());
+ ASSERT_EQ(1u, render_surface_list.size());
+ ASSERT_EQ(2, GetRenderSurface(root_layer)->num_contributors());
// If the root itself is hidden, the child should not be drawn even if it has
// an animating opacity.
root_layer->test_properties()->opacity = 0.0f;
root_layer->layer_tree_impl()->property_trees()->needs_rebuild = true;
- LayerImplList render_surface_layer_list2;
+ RenderSurfaceList render_surface_list2;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs2(
- root_layer, root_layer->bounds(), &render_surface_layer_list2);
+ root_layer, root_layer->bounds(), &render_surface_list2);
inputs2.can_adjust_raster_scales = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs2);
@@ -5117,9 +4483,9 @@ TEST_F(LayerTreeHostCommonTest, OpacityAnimatingOnPendingTree) {
root_layer->test_properties()->opacity = 1.0f;
child_ptr->test_properties()->opacity = 0.0f;
root_layer->layer_tree_impl()->property_trees()->needs_rebuild = true;
- LayerImplList render_surface_layer_list3;
+ RenderSurfaceList render_surface_list3;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs3(
- root_layer, root_layer->bounds(), &render_surface_layer_list3);
+ root_layer, root_layer->bounds(), &render_surface_list3);
inputs3.can_adjust_raster_scales = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs3);
@@ -5384,29 +4750,32 @@ TEST_F(LayerTreeHostCommonTest, SubtreeHidden_SingleLayerImpl) {
LayerImpl::Create(host_impl.pending_tree(), 2);
child->SetBounds(gfx::Size(40, 40));
child->SetDrawsContent(true);
+ LayerImpl* child_layer = child.get();
std::unique_ptr<LayerImpl> grand_child =
LayerImpl::Create(host_impl.pending_tree(), 3);
grand_child->SetBounds(gfx::Size(30, 30));
grand_child->SetDrawsContent(true);
grand_child->test_properties()->hide_layer_and_subtree = true;
+ LayerImpl* grand_child_layer = grand_child.get();
child->test_properties()->AddChild(std::move(grand_child));
root->test_properties()->AddChild(std::move(child));
host_impl.pending_tree()->SetRootLayerForTesting(std::move(root));
- LayerImplList render_surface_layer_list;
+ RenderSurfaceList render_surface_list;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root_layer, root_layer->bounds(), &render_surface_layer_list);
+ root_layer, root_layer->bounds(), &render_surface_list);
inputs.can_adjust_raster_scales = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
// We should have one render surface and two layers. The grand child has
// hidden itself.
- ASSERT_EQ(1u, render_surface_layer_list.size());
- ASSERT_EQ(2u, root_layer->GetRenderSurface()->layer_list().size());
- EXPECT_EQ(1, root_layer->GetRenderSurface()->layer_list().at(0)->id());
- EXPECT_EQ(2, root_layer->GetRenderSurface()->layer_list().at(1)->id());
+ ASSERT_EQ(1u, render_surface_list.size());
+ ASSERT_EQ(2, GetRenderSurface(root_layer)->num_contributors());
+ EXPECT_TRUE(root_layer->contributes_to_drawn_render_surface());
+ EXPECT_TRUE(child_layer->contributes_to_drawn_render_surface());
+ EXPECT_FALSE(grand_child_layer->contributes_to_drawn_render_surface());
}
TEST_F(LayerTreeHostCommonTest, SubtreeHidden_TwoLayersImpl) {
@@ -5426,27 +4795,31 @@ TEST_F(LayerTreeHostCommonTest, SubtreeHidden_TwoLayersImpl) {
child->SetBounds(gfx::Size(40, 40));
child->SetDrawsContent(true);
child->test_properties()->hide_layer_and_subtree = true;
+ LayerImpl* child_layer = child.get();
std::unique_ptr<LayerImpl> grand_child =
LayerImpl::Create(host_impl.pending_tree(), 3);
grand_child->SetBounds(gfx::Size(30, 30));
grand_child->SetDrawsContent(true);
+ LayerImpl* grand_child_layer = grand_child.get();
child->test_properties()->AddChild(std::move(grand_child));
root->test_properties()->AddChild(std::move(child));
host_impl.pending_tree()->SetRootLayerForTesting(std::move(root));
- LayerImplList render_surface_layer_list;
+ RenderSurfaceList render_surface_list;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root_layer, root_layer->bounds(), &render_surface_layer_list);
+ root_layer, root_layer->bounds(), &render_surface_list);
inputs.can_adjust_raster_scales = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
- // We should have one render surface and one layers. The child has
+ // We should have one render surface and one layer. The child has
// hidden itself and the grand child.
- ASSERT_EQ(1u, render_surface_layer_list.size());
- ASSERT_EQ(1u, root_layer->GetRenderSurface()->layer_list().size());
- EXPECT_EQ(1, root_layer->GetRenderSurface()->layer_list().at(0)->id());
+ ASSERT_EQ(1u, render_surface_list.size());
+ ASSERT_EQ(1, GetRenderSurface(root_layer)->num_contributors());
+ EXPECT_TRUE(root_layer->contributes_to_drawn_render_surface());
+ EXPECT_FALSE(child_layer->contributes_to_drawn_render_surface());
+ EXPECT_FALSE(grand_child_layer->contributes_to_drawn_render_surface());
}
void EmptyCopyOutputCallback(std::unique_ptr<CopyOutputResult> result) {}
@@ -5532,46 +4905,45 @@ TEST_F(LayerTreeHostCommonTest, SubtreeHiddenWithCopyRequest) {
copy_layer->test_properties()->copy_requests.push_back(
CopyOutputRequest::CreateRequest(base::Bind(&EmptyCopyOutputCallback)));
- LayerImplList render_surface_layer_list;
+ RenderSurfaceList render_surface_list;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root_layer, root_layer->bounds(), &render_surface_layer_list);
+ root_layer, root_layer->bounds(), &render_surface_list);
inputs.can_adjust_raster_scales = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
- EXPECT_GT(root_layer->num_copy_requests_in_target_subtree(), 0);
- EXPECT_GT(copy_grand_parent_layer->num_copy_requests_in_target_subtree(), 0);
- EXPECT_GT(copy_parent_layer->num_copy_requests_in_target_subtree(), 0);
- EXPECT_GT(copy_layer->num_copy_requests_in_target_subtree(), 0);
+ EXPECT_TRUE(root_layer->has_copy_requests_in_target_subtree());
+ EXPECT_TRUE(copy_grand_parent_layer->has_copy_requests_in_target_subtree());
+ EXPECT_TRUE(copy_parent_layer->has_copy_requests_in_target_subtree());
+ EXPECT_TRUE(copy_layer->has_copy_requests_in_target_subtree());
// We should have four render surfaces, one for the root, one for the grand
// parent since it has opacity and two drawing descendants, one for the parent
// since it owns a surface, and one for the copy_layer.
- ASSERT_EQ(4u, render_surface_layer_list.size());
- EXPECT_EQ(root_layer->id(), render_surface_layer_list.at(0)->id());
- EXPECT_EQ(copy_grand_parent_layer->id(),
- render_surface_layer_list.at(1)->id());
- EXPECT_EQ(copy_parent_layer->id(), render_surface_layer_list.at(2)->id());
- EXPECT_EQ(copy_layer->id(), render_surface_layer_list.at(3)->id());
+ ASSERT_EQ(4u, render_surface_list.size());
+ EXPECT_EQ(root_layer->id(), render_surface_list.at(0)->id());
+ EXPECT_EQ(copy_grand_parent_layer->id(), render_surface_list.at(1)->id());
+ EXPECT_EQ(copy_parent_layer->id(), render_surface_list.at(2)->id());
+ EXPECT_EQ(copy_layer->id(), render_surface_list.at(3)->id());
// The root render surface should have 2 contributing layers.
- ASSERT_EQ(2u, root_layer->GetRenderSurface()->layer_list().size());
- EXPECT_EQ(root_layer->id(),
- root_layer->GetRenderSurface()->layer_list().at(0)->id());
- EXPECT_EQ(copy_grand_parent_layer->id(),
- root_layer->GetRenderSurface()->layer_list().at(1)->id());
+ EXPECT_EQ(2, GetRenderSurface(root_layer)->num_contributors());
+ EXPECT_TRUE(root_layer->contributes_to_drawn_render_surface());
+ EXPECT_FALSE(copy_grand_parent_layer->contributes_to_drawn_render_surface());
+ EXPECT_FALSE(copy_grand_parent_sibling_before_layer
+ ->contributes_to_drawn_render_surface());
+ EXPECT_FALSE(copy_grand_parent_sibling_after_layer
+ ->contributes_to_drawn_render_surface());
// Nothing actually draws into the copy parent, so only the copy_layer will
// appear in its list, since it needs to be drawn for the copy request.
- ASSERT_EQ(1u, copy_parent_layer->GetRenderSurface()->layer_list().size());
- EXPECT_EQ(copy_layer->id(),
- copy_parent_layer->GetRenderSurface()->layer_list().at(0)->id());
+ ASSERT_EQ(1, GetRenderSurface(copy_parent_layer)->num_contributors());
+ EXPECT_FALSE(copy_parent_layer->contributes_to_drawn_render_surface());
- // The copy_layer's render surface should have two contributing layers.
- ASSERT_EQ(2u, copy_layer->GetRenderSurface()->layer_list().size());
- EXPECT_EQ(copy_layer->id(),
- copy_layer->GetRenderSurface()->layer_list().at(0)->id());
- EXPECT_EQ(copy_child_layer->id(),
- copy_layer->GetRenderSurface()->layer_list().at(1)->id());
+ // The copy layer's render surface should have 2 contributing layers.
+ ASSERT_EQ(2, GetRenderSurface(copy_layer)->num_contributors());
+ EXPECT_TRUE(copy_layer->contributes_to_drawn_render_surface());
+ EXPECT_TRUE(copy_child_layer->contributes_to_drawn_render_surface());
+ EXPECT_FALSE(copy_grand_child_layer->contributes_to_drawn_render_surface());
// copy_grand_parent, copy_parent shouldn't be drawn because they are hidden,
// but the copy_layer and copy_child should be drawn for the copy request.
@@ -5592,7 +4964,7 @@ TEST_F(LayerTreeHostCommonTest, SubtreeHiddenWithCopyRequest) {
// Though copy_layer is drawn, it shouldn't contribute to drawn surface as its
// actually hidden.
- EXPECT_FALSE(copy_layer->GetRenderSurface()->contributes_to_drawn_surface());
+ EXPECT_FALSE(GetRenderSurface(copy_layer)->contributes_to_drawn_surface());
}
TEST_F(LayerTreeHostCommonTest, ClippedOutCopyRequest) {
@@ -5629,23 +5001,66 @@ TEST_F(LayerTreeHostCommonTest, ClippedOutCopyRequest) {
copy_parent->test_properties()->AddChild(std::move(copy_layer));
root->test_properties()->AddChild(std::move(copy_parent));
- LayerImplList render_surface_layer_list;
+ RenderSurfaceList render_surface_list;
LayerImpl* root_layer = root.get();
root_layer->layer_tree_impl()->SetRootLayerForTesting(std::move(root));
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root_layer, root_layer->bounds(), &render_surface_layer_list);
+ root_layer, root_layer->bounds(), &render_surface_list);
inputs.can_adjust_raster_scales = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
// We should have two render surface, as the others are clipped out.
- ASSERT_EQ(2u, render_surface_layer_list.size());
- EXPECT_EQ(root_layer->id(), render_surface_layer_list.at(0)->id());
+ ASSERT_EQ(2u, render_surface_list.size());
+ EXPECT_EQ(root_layer->id(), render_surface_list.at(0)->id());
+
+ // The root render surface should have only 2 contributing layer, since the
+ // other layers are clipped away.
+ ASSERT_EQ(2, GetRenderSurface(root_layer)->num_contributors());
+ EXPECT_TRUE(root_layer->contributes_to_drawn_render_surface());
+}
+
+TEST_F(LayerTreeHostCommonTest, SingularTransformAndCopyRequests) {
+ LayerImpl* root = root_layer_for_testing();
+ root->SetBounds(gfx::Size(50, 50));
+ root->SetDrawsContent(true);
- // The root render surface should only have 2 contributing layer, since the
- // other layers are empty/clipped away.
- ASSERT_EQ(2u, root_layer->GetRenderSurface()->layer_list().size());
- EXPECT_EQ(root_layer->id(),
- root_layer->GetRenderSurface()->layer_list().at(0)->id());
+ LayerImpl* singular_transform_layer = AddChild<LayerImpl>(root);
+ singular_transform_layer->SetBounds(gfx::Size(100, 100));
+ singular_transform_layer->SetDrawsContent(true);
+ gfx::Transform singular;
+ singular.Scale3d(6.f, 6.f, 0.f);
+ singular_transform_layer->test_properties()->transform = singular;
+
+ LayerImpl* copy_layer = AddChild<LayerImpl>(singular_transform_layer);
+ copy_layer->SetBounds(gfx::Size(100, 100));
+ copy_layer->SetDrawsContent(true);
+ copy_layer->test_properties()->copy_requests.push_back(
+ CopyOutputRequest::CreateRequest(base::Bind(&EmptyCopyOutputCallback)));
+
+ LayerImpl* copy_child = AddChild<LayerImpl>(copy_layer);
+ copy_child->SetBounds(gfx::Size(100, 100));
+ copy_child->SetDrawsContent(true);
+
+ LayerImpl* copy_grand_child = AddChild<LayerImpl>(copy_child);
+ copy_grand_child->SetBounds(gfx::Size(100, 100));
+ copy_grand_child->SetDrawsContent(true);
+ copy_grand_child->test_properties()->transform = singular;
+
+ DCHECK(!copy_layer->test_properties()->copy_requests.empty());
+ ExecuteCalculateDrawProperties(root);
+ DCHECK(copy_layer->test_properties()->copy_requests.empty());
+
+ // A layer with singular transform should not contribute to drawn render
+ // surface.
+ EXPECT_FALSE(singular_transform_layer->contributes_to_drawn_render_surface());
+ // Even though copy_layer and copy_child have singular screen space transform,
+ // they still contribute to drawn render surface as their transform to the
+ // closest ancestor with copy request is not singular.
+ EXPECT_TRUE(copy_layer->contributes_to_drawn_render_surface());
+ EXPECT_TRUE(copy_child->contributes_to_drawn_render_surface());
+ // copy_grand_child's transform to its closest ancestor with copy request is
+ // also singular. So, it doesn't contribute to drawn render surface.
+ EXPECT_FALSE(copy_grand_child->contributes_to_drawn_render_surface());
}
TEST_F(LayerTreeHostCommonTest, VisibleRectInNonRootCopyRequest) {
@@ -5765,8 +5180,8 @@ TEST_F(LayerTreeHostCommonTest, TransformedClipParent) {
clip_child->SetBounds(gfx::Size(10, 10));
ExecuteCalculateDrawProperties(root);
- ASSERT_TRUE(root->GetRenderSurface());
- ASSERT_TRUE(render_surface->GetRenderSurface());
+ ASSERT_TRUE(GetRenderSurface(root));
+ ASSERT_TRUE(GetRenderSurface(render_surface));
// Ensure that we've inherited our clip parent's clip and weren't affected
// by the intervening clip layer.
@@ -5777,14 +5192,14 @@ TEST_F(LayerTreeHostCommonTest, TransformedClipParent) {
// Ensure that the render surface reports a content rect that has been grown
// to accomodate for the clip child.
ASSERT_EQ(gfx::Rect(1, 1, 20, 20),
- render_surface->GetRenderSurface()->content_rect());
+ GetRenderSurface(render_surface)->content_rect());
// The above check implies the two below, but they nicely demonstrate that
// we've grown, despite the intervening layer's clip.
ASSERT_TRUE(clip_parent->clip_rect().Contains(
- render_surface->GetRenderSurface()->content_rect()));
+ GetRenderSurface(render_surface)->content_rect()));
ASSERT_FALSE(intervening->clip_rect().Contains(
- render_surface->GetRenderSurface()->content_rect()));
+ GetRenderSurface(render_surface)->content_rect()));
}
TEST_F(LayerTreeHostCommonTest, ClipParentWithInterveningRenderSurface) {
@@ -5830,16 +5245,16 @@ TEST_F(LayerTreeHostCommonTest, ClipParentWithInterveningRenderSurface) {
clip_child->SetBounds(gfx::Size(60, 60));
ExecuteCalculateDrawProperties(root);
- EXPECT_TRUE(root->GetRenderSurface());
- EXPECT_TRUE(render_surface1->GetRenderSurface());
- EXPECT_TRUE(render_surface2->GetRenderSurface());
+ EXPECT_TRUE(GetRenderSurface(root));
+ EXPECT_TRUE(GetRenderSurface(render_surface1));
+ EXPECT_TRUE(GetRenderSurface(render_surface2));
// render_surface1 should apply the clip from clip_parent. Though there is a
// clip child, render_surface1 can apply the clip as there are no clips
// between the clip parent and render_surface1
EXPECT_EQ(gfx::Rect(1, 1, 40, 40),
- render_surface1->GetRenderSurface()->clip_rect());
- EXPECT_TRUE(render_surface1->GetRenderSurface()->is_clipped());
+ GetRenderSurface(render_surface1)->clip_rect());
+ EXPECT_TRUE(GetRenderSurface(render_surface1)->is_clipped());
EXPECT_EQ(gfx::Rect(), render_surface1->clip_rect());
EXPECT_FALSE(render_surface1->is_clipped());
@@ -5848,8 +5263,8 @@ TEST_F(LayerTreeHostCommonTest, ClipParentWithInterveningRenderSurface) {
// So, it should not be clipped (their bounds would no longer be reliable).
// We should resort to layer clipping in this case.
EXPECT_EQ(gfx::Rect(0, 0, 0, 0),
- render_surface2->GetRenderSurface()->clip_rect());
- EXPECT_FALSE(render_surface2->GetRenderSurface()->is_clipped());
+ GetRenderSurface(render_surface2)->clip_rect());
+ EXPECT_FALSE(GetRenderSurface(render_surface2)->is_clipped());
// This value is inherited from the clipping ancestor layer, 'intervening'.
EXPECT_EQ(gfx::Rect(0, 0, 5, 5), render_surface2->clip_rect());
@@ -5858,9 +5273,9 @@ TEST_F(LayerTreeHostCommonTest, ClipParentWithInterveningRenderSurface) {
// The content rects of render_surface2 should have expanded to contain the
// clip child.
EXPECT_EQ(gfx::Rect(0, 0, 40, 40),
- render_surface1->GetRenderSurface()->content_rect());
+ GetRenderSurface(render_surface1)->content_rect());
EXPECT_EQ(gfx::Rect(-10, -10, 60, 60),
- render_surface2->GetRenderSurface()->content_rect());
+ GetRenderSurface(render_surface2)->content_rect());
// The clip child should have inherited the clip parent's clip (projected to
// the right space, of course), but as render_surface1 already applies that
@@ -5916,16 +5331,16 @@ TEST_F(LayerTreeHostCommonTest, ClipParentScrolledInterveningLayer) {
clip_child->SetBounds(gfx::Size(60, 60));
ExecuteCalculateDrawProperties(root);
- EXPECT_TRUE(root->GetRenderSurface());
- EXPECT_TRUE(render_surface1->GetRenderSurface());
- EXPECT_TRUE(render_surface2->GetRenderSurface());
+ EXPECT_TRUE(GetRenderSurface(root));
+ EXPECT_TRUE(GetRenderSurface(render_surface1));
+ EXPECT_TRUE(GetRenderSurface(render_surface2));
// render_surface1 should apply the clip from clip_parent. Though there is a
// clip child, render_surface1 can apply the clip as there are no clips
// between the clip parent and render_surface1
EXPECT_EQ(gfx::Rect(3, 3, 40, 40),
- render_surface1->GetRenderSurface()->clip_rect());
- EXPECT_TRUE(render_surface1->GetRenderSurface()->is_clipped());
+ GetRenderSurface(render_surface1)->clip_rect());
+ EXPECT_TRUE(GetRenderSurface(render_surface1)->is_clipped());
EXPECT_EQ(gfx::Rect(), render_surface1->clip_rect());
EXPECT_FALSE(render_surface1->is_clipped());
@@ -5934,8 +5349,8 @@ TEST_F(LayerTreeHostCommonTest, ClipParentScrolledInterveningLayer) {
// So, it should not be clipped (their bounds would no longer be reliable).
// We should resort to layer clipping in this case.
EXPECT_EQ(gfx::Rect(0, 0, 0, 0),
- render_surface2->GetRenderSurface()->clip_rect());
- EXPECT_FALSE(render_surface2->GetRenderSurface()->is_clipped());
+ GetRenderSurface(render_surface2)->clip_rect());
+ EXPECT_FALSE(GetRenderSurface(render_surface2)->is_clipped());
// This value is inherited from the clipping ancestor layer, 'intervening'.
EXPECT_EQ(gfx::Rect(0, 0, 5, 5), render_surface2->clip_rect());
EXPECT_TRUE(render_surface2->is_clipped());
@@ -5943,9 +5358,9 @@ TEST_F(LayerTreeHostCommonTest, ClipParentScrolledInterveningLayer) {
// The content rects of render_surface2 should have expanded to contain the
// clip child.
EXPECT_EQ(gfx::Rect(0, 0, 40, 40),
- render_surface1->GetRenderSurface()->content_rect());
+ GetRenderSurface(render_surface1)->content_rect());
EXPECT_EQ(gfx::Rect(-10, -10, 60, 60),
- render_surface2->GetRenderSurface()->content_rect());
+ GetRenderSurface(render_surface2)->content_rect());
// The clip child should have inherited the clip parent's clip (projected to
// the right space, of course), but as render_surface1 already applies that
@@ -5987,7 +5402,7 @@ TEST_F(LayerTreeHostCommonTest, DescendantsOfClipChildren) {
ExecuteCalculateDrawProperties(root);
- EXPECT_TRUE(root->GetRenderSurface());
+ EXPECT_TRUE(GetRenderSurface(root));
// Neither the clip child nor its descendant should have inherited the clip
// from |intervening|.
@@ -6046,9 +5461,9 @@ TEST_F(LayerTreeHostCommonTest,
ExecuteCalculateDrawProperties(root);
- EXPECT_TRUE(root->GetRenderSurface());
- EXPECT_TRUE(render_surface1->GetRenderSurface());
- EXPECT_TRUE(render_surface2->GetRenderSurface());
+ EXPECT_TRUE(GetRenderSurface(root));
+ EXPECT_TRUE(GetRenderSurface(render_surface1));
+ EXPECT_TRUE(GetRenderSurface(render_surface2));
EXPECT_EQ(gfx::Rect(-5, -5, 10, 10), render_surface1->clip_rect());
EXPECT_TRUE(render_surface1->is_clipped());
@@ -6056,23 +5471,23 @@ TEST_F(LayerTreeHostCommonTest,
// The render surface should not clip (it has unclipped descendants), instead
// it should rely on layer clipping.
EXPECT_EQ(gfx::Rect(0, 0, 0, 0),
- render_surface1->GetRenderSurface()->clip_rect());
- EXPECT_FALSE(render_surface1->GetRenderSurface()->is_clipped());
+ GetRenderSurface(render_surface1)->clip_rect());
+ EXPECT_FALSE(GetRenderSurface(render_surface1)->is_clipped());
// That said, it should have grown to accomodate the unclipped descendant and
// its own size.
EXPECT_EQ(gfx::Rect(-1, 0, 6, 5),
- render_surface1->GetRenderSurface()->content_rect());
+ GetRenderSurface(render_surface1)->content_rect());
// This render surface should clip. It has no unclipped descendants.
EXPECT_EQ(gfx::Rect(0, 0, 10, 10),
- render_surface2->GetRenderSurface()->clip_rect());
- EXPECT_TRUE(render_surface2->GetRenderSurface()->is_clipped());
+ GetRenderSurface(render_surface2)->clip_rect());
+ EXPECT_TRUE(GetRenderSurface(render_surface2)->is_clipped());
EXPECT_FALSE(render_surface2->is_clipped());
// It also shouldn't have grown to accomodate the clip child.
EXPECT_EQ(gfx::Rect(0, 0, 5, 5),
- render_surface2->GetRenderSurface()->content_rect());
+ GetRenderSurface(render_surface2)->content_rect());
}
TEST_F(LayerTreeHostCommonTest,
@@ -6101,113 +5516,10 @@ TEST_F(LayerTreeHostCommonTest,
ExecuteCalculateDrawPropertiesAndSaveUpdateLayerList(root);
// Verify which render surfaces were created.
- EXPECT_TRUE(root->GetRenderSurface());
- EXPECT_FALSE(child1->GetRenderSurface());
- EXPECT_TRUE(child2->GetRenderSurface());
- EXPECT_FALSE(child3->GetRenderSurface());
-}
-
-TEST_F(LayerTreeHostCommonTest, CanRenderToSeparateSurface) {
- FakeImplTaskRunnerProvider task_runner_provider;
- TestTaskGraphRunner task_graph_runner;
- FakeLayerTreeHostImpl host_impl(&task_runner_provider, &task_graph_runner);
-
- std::unique_ptr<LayerImpl> root =
- LayerImpl::Create(host_impl.active_tree(), 12345);
- std::unique_ptr<LayerImpl> child1 =
- LayerImpl::Create(host_impl.active_tree(), 123456);
- std::unique_ptr<LayerImpl> child2 =
- LayerImpl::Create(host_impl.active_tree(), 1234567);
- std::unique_ptr<LayerImpl> child3 =
- LayerImpl::Create(host_impl.active_tree(), 12345678);
-
- gfx::Size bounds(100, 100);
-
- root->SetBounds(bounds);
- root->SetDrawsContent(true);
-
- // This layer structure normally forces render surface due to preserves3d
- // behavior.
- child1->SetBounds(bounds);
- child1->SetDrawsContent(true);
- child1->test_properties()->should_flatten_transform = false;
- child1->test_properties()->sorting_context_id = 1;
- child2->SetBounds(bounds);
- child2->SetDrawsContent(true);
- child2->test_properties()->sorting_context_id = 1;
- child3->SetBounds(bounds);
- child3->SetDrawsContent(true);
- child3->test_properties()->sorting_context_id = 1;
-
- child2->test_properties()->AddChild(std::move(child3));
- child1->test_properties()->AddChild(std::move(child2));
- root->test_properties()->AddChild(std::move(child1));
- LayerImpl* root_layer = root.get();
- root_layer->layer_tree_impl()->SetRootLayerForTesting(std::move(root));
-
- {
- LayerImplList render_surface_layer_list;
- LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root_layer, root_layer->bounds(), &render_surface_layer_list);
- inputs.can_render_to_separate_surface = true;
- LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
-
- EXPECT_EQ(2u, render_surface_layer_list.size());
-
- int count_represents_target_render_surface = 0;
- int count_represents_contributing_render_surface = 0;
- int count_represents_itself = 0;
- for (EffectTreeLayerListIterator it(host_impl.active_tree());
- it.state() != EffectTreeLayerListIterator::State::END; ++it) {
- if (it.state() == EffectTreeLayerListIterator::State::TARGET_SURFACE) {
- count_represents_target_render_surface++;
- } else if (it.state() ==
- EffectTreeLayerListIterator::State::CONTRIBUTING_SURFACE) {
- count_represents_contributing_render_surface++;
- } else {
- count_represents_itself++;
- }
- }
-
- // Two render surfaces.
- EXPECT_EQ(2, count_represents_target_render_surface);
- // Second render surface contributes to root render surface.
- EXPECT_EQ(1, count_represents_contributing_render_surface);
- // All 4 layers represent itself.
- EXPECT_EQ(4, count_represents_itself);
- }
-
- {
- LayerImplList render_surface_layer_list;
- LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root_layer, root_layer->bounds(), &render_surface_layer_list);
- inputs.can_render_to_separate_surface = false;
- LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
-
- EXPECT_EQ(1u, render_surface_layer_list.size());
-
- int count_represents_target_render_surface = 0;
- int count_represents_contributing_render_surface = 0;
- int count_represents_itself = 0;
- for (EffectTreeLayerListIterator it(host_impl.active_tree());
- it.state() != EffectTreeLayerListIterator::State::END; ++it) {
- if (it.state() == EffectTreeLayerListIterator::State::TARGET_SURFACE) {
- count_represents_target_render_surface++;
- } else if (it.state() ==
- EffectTreeLayerListIterator::State::CONTRIBUTING_SURFACE) {
- count_represents_contributing_render_surface++;
- } else {
- count_represents_itself++;
- }
- }
-
- // Only root layer has a render surface.
- EXPECT_EQ(1, count_represents_target_render_surface);
- // No layer contributes a render surface to root render surface.
- EXPECT_EQ(0, count_represents_contributing_render_surface);
- // All 4 layers represent itself.
- EXPECT_EQ(4, count_represents_itself);
- }
+ EXPECT_TRUE(GetRenderSurface(root));
+ EXPECT_EQ(GetRenderSurface(child1), GetRenderSurface(root));
+ EXPECT_NE(GetRenderSurface(child2), GetRenderSurface(root));
+ EXPECT_EQ(GetRenderSurface(child3), GetRenderSurface(child2));
}
TEST_F(LayerTreeHostCommonTest, DoNotIncludeBackfaceInvisibleSurfaces) {
@@ -6243,19 +5555,9 @@ TEST_F(LayerTreeHostCommonTest, DoNotIncludeBackfaceInvisibleSurfaces) {
ExecuteCalculateDrawProperties(root);
- EXPECT_EQ(3u, render_surface_layer_list_impl()->size());
- EXPECT_EQ(2u,
- render_surface_layer_list_impl()
- ->at(0)
- ->GetRenderSurface()
- ->layer_list()
- .size());
- EXPECT_EQ(1u,
- render_surface_layer_list_impl()
- ->at(1)
- ->GetRenderSurface()
- ->layer_list()
- .size());
+ EXPECT_EQ(3u, render_surface_list_impl()->size());
+ EXPECT_EQ(2, render_surface_list_impl()->at(0)->num_contributors());
+ EXPECT_EQ(1, render_surface_list_impl()->at(1)->num_contributors());
gfx::Transform rotation_transform;
rotation_transform.RotateAboutXAxis(180.0);
@@ -6269,13 +5571,8 @@ TEST_F(LayerTreeHostCommonTest, DoNotIncludeBackfaceInvisibleSurfaces) {
// not double sided, so it should not be in RSLL. render_surface2 is also not
// double-sided, but will still be in RSLL as it's in a different 3d rendering
// context.
- EXPECT_EQ(2u, render_surface_layer_list_impl()->size());
- EXPECT_EQ(1u,
- render_surface_layer_list_impl()
- ->at(0)
- ->GetRenderSurface()
- ->layer_list()
- .size());
+ EXPECT_EQ(2u, render_surface_list_impl()->size());
+ EXPECT_EQ(1, render_surface_list_impl()->at(0)->num_contributors());
}
TEST_F(LayerTreeHostCommonTest, DoNotIncludeBackfaceInvisibleLayers) {
@@ -6294,12 +5591,8 @@ TEST_F(LayerTreeHostCommonTest, DoNotIncludeBackfaceInvisibleLayers) {
grand_child->test_properties()->should_flatten_transform = false;
ExecuteCalculateDrawProperties(root);
- EXPECT_EQ(1u, render_surface_layer_list_impl()->size());
- EXPECT_EQ(grand_child,
- render_surface_layer_list_impl()
- ->at(0)
- ->GetRenderSurface()
- ->layer_list()[0]);
+ EXPECT_EQ(1u, render_surface_list_impl()->size());
+ EXPECT_TRUE(grand_child->contributes_to_drawn_render_surface());
// As all layers have identity transform, we shouldn't check for backface
// visibility.
@@ -6321,13 +5614,8 @@ TEST_F(LayerTreeHostCommonTest, DoNotIncludeBackfaceInvisibleLayers) {
child->layer_tree_impl()->property_trees()->needs_rebuild = true;
ExecuteCalculateDrawProperties(root);
- EXPECT_EQ(1u, render_surface_layer_list_impl()->size());
- EXPECT_EQ(0u,
- render_surface_layer_list_impl()
- ->at(0)
- ->GetRenderSurface()
- ->layer_list()
- .size());
+ EXPECT_EQ(1u, render_surface_list_impl()->size());
+ EXPECT_EQ(0, render_surface_list_impl()->at(0)->num_contributors());
// We should check for backface visibilty of child as it has a rotation
// transform. We should also check for grand_child as it uses the backface
@@ -6348,13 +5636,8 @@ TEST_F(LayerTreeHostCommonTest, DoNotIncludeBackfaceInvisibleLayers) {
grand_child->layer_tree_impl()->property_trees()->needs_rebuild = true;
ExecuteCalculateDrawProperties(root);
- EXPECT_EQ(1u, render_surface_layer_list_impl()->size());
- EXPECT_EQ(0u,
- render_surface_layer_list_impl()
- ->at(0)
- ->GetRenderSurface()
- ->layer_list()
- .size());
+ EXPECT_EQ(1u, render_surface_list_impl()->size());
+ EXPECT_EQ(0, render_surface_list_impl()->at(0)->num_contributors());
// We should check the backface visibility of child as it has a rotation
// transform and for grand_child as it is in a 3d rendering context and not
@@ -6456,7 +5739,7 @@ TEST_F(LayerTreeHostCommonTest, ClippedByScrollParent) {
scroll_child->SetBounds(gfx::Size(50, 50));
ExecuteCalculateDrawProperties(root);
- EXPECT_TRUE(root->GetRenderSurface());
+ EXPECT_TRUE(GetRenderSurface(root));
EXPECT_EQ(gfx::Rect(0, 0, 30, 30), scroll_child->clip_rect());
EXPECT_TRUE(scroll_child->is_clipped());
@@ -6490,13 +5773,12 @@ TEST_F(LayerTreeHostCommonTest, ScrollChildAndScrollParentDifferentTargets) {
scroll_parent->SetBounds(gfx::Size(50, 50));
float device_scale_factor = 1.5f;
- LayerImplList render_surface_layer_list_impl;
+ RenderSurfaceList render_surface_list_impl;
gfx::Size device_viewport_size =
gfx::Size(root->bounds().width() * device_scale_factor,
root->bounds().height() * device_scale_factor);
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root, device_viewport_size, gfx::Transform(),
- &render_surface_layer_list_impl);
+ root, device_viewport_size, gfx::Transform(), &render_surface_list_impl);
inputs.device_scale_factor = device_scale_factor;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
@@ -6527,7 +5809,7 @@ TEST_F(LayerTreeHostCommonTest, SingularTransformSubtreesDoNotDraw) {
child->test_properties()->sorting_context_id = 1;
ExecuteCalculateDrawProperties(root);
- EXPECT_EQ(3u, render_surface_layer_list_impl()->size());
+ EXPECT_EQ(3u, render_surface_list_impl()->size());
gfx::Transform singular_transform;
singular_transform.Scale3d(
@@ -6538,7 +5820,7 @@ TEST_F(LayerTreeHostCommonTest, SingularTransformSubtreesDoNotDraw) {
root->layer_tree_impl()->property_trees()->needs_rebuild = true;
ExecuteCalculateDrawProperties(root);
- EXPECT_EQ(2u, render_surface_layer_list_impl()->size());
+ EXPECT_EQ(2u, render_surface_list_impl()->size());
// Ensure that the entire subtree under a layer with singular transform does
// not get rendered.
@@ -6548,7 +5830,7 @@ TEST_F(LayerTreeHostCommonTest, SingularTransformSubtreesDoNotDraw) {
root->layer_tree_impl()->property_trees()->needs_rebuild = true;
ExecuteCalculateDrawProperties(root);
- EXPECT_EQ(1u, render_surface_layer_list_impl()->size());
+ EXPECT_EQ(1u, render_surface_list_impl()->size());
}
TEST_F(LayerTreeHostCommonTest, ClippedByOutOfOrderScrollParent) {
@@ -6584,7 +5866,7 @@ TEST_F(LayerTreeHostCommonTest, ClippedByOutOfOrderScrollParent) {
ExecuteCalculateDrawProperties(root);
- EXPECT_TRUE(root->GetRenderSurface());
+ EXPECT_TRUE(GetRenderSurface(root));
EXPECT_EQ(gfx::Rect(0, 0, 30, 30), scroll_child->clip_rect());
EXPECT_TRUE(scroll_child->is_clipped());
@@ -6642,17 +5924,17 @@ TEST_F(LayerTreeHostCommonTest, ClippedByOutOfOrderScrollGrandparent) {
ExecuteCalculateDrawProperties(root);
- EXPECT_TRUE(root->GetRenderSurface());
+ EXPECT_TRUE(GetRenderSurface(root));
EXPECT_EQ(gfx::Rect(0, 0, 20, 20), scroll_child->clip_rect());
EXPECT_TRUE(scroll_child->is_clipped());
// Despite the fact that we visited the above layers out of order to get the
// correct clip, the layer lists should be unaffected.
- EXPECT_EQ(3u, root->GetRenderSurface()->layer_list().size());
- EXPECT_EQ(scroll_child, root->GetRenderSurface()->layer_list().at(0));
- EXPECT_EQ(scroll_parent, root->GetRenderSurface()->layer_list().at(1));
- EXPECT_EQ(scroll_grandparent, root->GetRenderSurface()->layer_list().at(2));
+ EXPECT_EQ(3, GetRenderSurface(root)->num_contributors());
+ EXPECT_TRUE(scroll_child->contributes_to_drawn_render_surface());
+ EXPECT_TRUE(scroll_parent->contributes_to_drawn_render_surface());
+ EXPECT_TRUE(scroll_grandparent->contributes_to_drawn_render_surface());
}
TEST_F(LayerTreeHostCommonTest, OutOfOrderClippingRequiresRSLLSorting) {
@@ -6719,20 +6001,19 @@ TEST_F(LayerTreeHostCommonTest, OutOfOrderClippingRequiresRSLLSorting) {
ExecuteCalculateDrawProperties(root);
- EXPECT_TRUE(root->GetRenderSurface());
+ EXPECT_TRUE(GetRenderSurface(root));
EXPECT_EQ(gfx::Rect(0, 0, 20, 20), scroll_child->clip_rect());
EXPECT_TRUE(scroll_child->is_clipped());
// Despite the fact that we had to process the layers out of order to get the
- // right clip, our render_surface_layer_list's order should be unaffected.
- EXPECT_EQ(3u, render_surface_layer_list_impl()->size());
- EXPECT_EQ(root, render_surface_layer_list_impl()->at(0));
- EXPECT_EQ(render_surface2, render_surface_layer_list_impl()->at(1));
- EXPECT_EQ(render_surface1, render_surface_layer_list_impl()->at(2));
- EXPECT_TRUE(render_surface_layer_list_impl()->at(0)->GetRenderSurface());
- EXPECT_TRUE(render_surface_layer_list_impl()->at(1)->GetRenderSurface());
- EXPECT_TRUE(render_surface_layer_list_impl()->at(2)->GetRenderSurface());
+ // right clip, our render_surface_list's order should be unaffected.
+ EXPECT_EQ(3u, render_surface_list_impl()->size());
+ EXPECT_EQ(GetRenderSurface(root), render_surface_list_impl()->at(0));
+ EXPECT_EQ(GetRenderSurface(render_surface2),
+ render_surface_list_impl()->at(1));
+ EXPECT_EQ(GetRenderSurface(render_surface1),
+ render_surface_list_impl()->at(2));
}
TEST_F(LayerTreeHostCommonTest, FixedPositionWithInterveningRenderSurface) {
@@ -6858,9 +6139,9 @@ TEST_F(LayerTreeHostCommonTest, ScrollCompensationWithRounding) {
gfx::Vector2dF scroll_delta(3.0, 5.0);
SetScrollOffsetDelta(scroll_layer, scroll_delta);
- LayerImplList render_surface_layer_list;
+ RenderSurfaceList render_surface_list;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root, root->bounds(), &render_surface_layer_list);
+ root, root->bounds(), &render_surface_list);
root->layer_tree_impl()
->property_trees()
->transform_tree.set_source_to_parent_updates_allowed(false);
@@ -6884,9 +6165,9 @@ TEST_F(LayerTreeHostCommonTest, ScrollCompensationWithRounding) {
gfx::Vector2dF rounded_scroll_delta(4.f, 8.f);
- LayerImplList render_surface_layer_list;
+ RenderSurfaceList render_surface_list;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root, root->bounds(), &render_surface_layer_list);
+ root, root->bounds(), &render_surface_list);
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
EXPECT_TRANSFORMATION_MATRIX_EQ(
@@ -6912,9 +6193,9 @@ TEST_F(LayerTreeHostCommonTest, ScrollCompensationWithRounding) {
gfx::Vector2dF scroll_delta(4.5f, 8.5f);
SetScrollOffsetDelta(scroll_layer, scroll_delta);
- LayerImplList render_surface_layer_list;
+ RenderSurfaceList render_surface_list;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root, root->bounds(), &render_surface_layer_list);
+ root, root->bounds(), &render_surface_list);
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
EXPECT_TRANSFORMATION_MATRIX_EQ(
@@ -7308,7 +6589,11 @@ TEST_F(LayerTreeHostCommonTest, StickyPositionBottomInnerViewportDelta) {
scroller->AddChild(sticky_pos);
host()->SetRootLayer(root);
scroller->SetScrollClipLayerId(root->id());
- host()->RegisterViewportLayers(nullptr, root, scroller, nullptr);
+ LayerTreeHost::ViewportLayers viewport_layers;
+ viewport_layers.page_scale = root;
+ viewport_layers.inner_viewport_container = root;
+ viewport_layers.inner_viewport_scroll = scroller;
+ host()->RegisterViewportLayers(viewport_layers);
LayerStickyPositionConstraint sticky_position;
sticky_position.is_sticky = true;
@@ -7343,7 +6628,7 @@ TEST_F(LayerTreeHostCommonTest, StickyPositionBottomInnerViewportDelta) {
// We start to hide the toolbar, but not far enough that the sticky element
// should be moved up yet.
- root_impl->SetBoundsDelta(gfx::Vector2dF(0.f, -10.f));
+ root_impl->SetViewportBoundsDelta(gfx::Vector2dF(0.f, -10.f));
ExecuteCalculateDrawProperties(root_impl, 1.f, 1.f, root_impl, inner_scroll,
nullptr);
EXPECT_VECTOR2DF_EQ(
@@ -7351,7 +6636,7 @@ TEST_F(LayerTreeHostCommonTest, StickyPositionBottomInnerViewportDelta) {
sticky_pos_impl->ScreenSpaceTransform().To2dTranslation());
// On hiding more of the toolbar the sticky element starts to stick.
- root_impl->SetBoundsDelta(gfx::Vector2dF(0.f, -20.f));
+ root_impl->SetViewportBoundsDelta(gfx::Vector2dF(0.f, -20.f));
ExecuteCalculateDrawProperties(root_impl, 1.f, 1.f, root_impl, inner_scroll,
nullptr);
EXPECT_VECTOR2DF_EQ(
@@ -7360,7 +6645,7 @@ TEST_F(LayerTreeHostCommonTest, StickyPositionBottomInnerViewportDelta) {
// On hiding more the sticky element stops moving as it has reached its
// limit.
- root_impl->SetBoundsDelta(gfx::Vector2dF(0.f, -30.f));
+ root_impl->SetViewportBoundsDelta(gfx::Vector2dF(0.f, -30.f));
ExecuteCalculateDrawProperties(root_impl, 1.f, 1.f, root_impl, inner_scroll,
nullptr);
EXPECT_VECTOR2DF_EQ(
@@ -7381,7 +6666,13 @@ TEST_F(LayerTreeHostCommonTest, StickyPositionBottomOuterViewportDelta) {
host()->SetRootLayer(root);
scroller->SetScrollClipLayerId(root->id());
outer_viewport->SetScrollClipLayerId(outer_clip->id());
- host()->RegisterViewportLayers(nullptr, root, scroller, outer_viewport);
+ LayerTreeHost::ViewportLayers viewport_layers;
+ viewport_layers.page_scale = root;
+ viewport_layers.inner_viewport_container = root;
+ viewport_layers.outer_viewport_container = outer_clip;
+ viewport_layers.inner_viewport_scroll = scroller;
+ viewport_layers.outer_viewport_scroll = outer_viewport;
+ host()->RegisterViewportLayers(viewport_layers);
LayerStickyPositionConstraint sticky_position;
sticky_position.is_sticky = true;
@@ -7420,7 +6711,7 @@ TEST_F(LayerTreeHostCommonTest, StickyPositionBottomOuterViewportDelta) {
// We start to hide the toolbar, but not far enough that the sticky element
// should be moved up yet.
- outer_clip_impl->SetBoundsDelta(gfx::Vector2dF(0.f, -10.f));
+ outer_clip_impl->SetViewportBoundsDelta(gfx::Vector2dF(0.f, -10.f));
ExecuteCalculateDrawProperties(root_impl, 1.f, 1.f, root_impl, inner_scroll,
outer_scroll);
EXPECT_VECTOR2DF_EQ(
@@ -7428,7 +6719,7 @@ TEST_F(LayerTreeHostCommonTest, StickyPositionBottomOuterViewportDelta) {
sticky_pos_impl->ScreenSpaceTransform().To2dTranslation());
// On hiding more of the toolbar the sticky element starts to stick.
- outer_clip_impl->SetBoundsDelta(gfx::Vector2dF(0.f, -20.f));
+ outer_clip_impl->SetViewportBoundsDelta(gfx::Vector2dF(0.f, -20.f));
ExecuteCalculateDrawProperties(root_impl, 1.f, 1.f, root_impl, inner_scroll,
outer_scroll);
@@ -7438,7 +6729,7 @@ TEST_F(LayerTreeHostCommonTest, StickyPositionBottomOuterViewportDelta) {
gfx::Vector2dF(0.f, 60.f),
sticky_pos_impl->ScreenSpaceTransform().To2dTranslation());
- outer_clip_impl->SetBoundsDelta(gfx::Vector2dF(0.f, -30.f));
+ outer_clip_impl->SetViewportBoundsDelta(gfx::Vector2dF(0.f, -30.f));
ExecuteCalculateDrawProperties(root_impl, 1.f, 1.f, root_impl, inner_scroll,
outer_scroll);
@@ -8402,11 +7693,11 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceLayerListMembership) {
// Start with nothing being drawn.
ExecuteCalculateDrawProperties(grand_parent_raw);
- EXPECT_FALSE(grand_parent_raw->is_drawn_render_surface_layer_list_member());
- EXPECT_FALSE(parent_raw->is_drawn_render_surface_layer_list_member());
- EXPECT_FALSE(child_raw->is_drawn_render_surface_layer_list_member());
- EXPECT_FALSE(grand_child1_raw->is_drawn_render_surface_layer_list_member());
- EXPECT_FALSE(grand_child2_raw->is_drawn_render_surface_layer_list_member());
+ EXPECT_FALSE(grand_parent_raw->contributes_to_drawn_render_surface());
+ EXPECT_FALSE(parent_raw->contributes_to_drawn_render_surface());
+ EXPECT_FALSE(child_raw->contributes_to_drawn_render_surface());
+ EXPECT_FALSE(grand_child1_raw->contributes_to_drawn_render_surface());
+ EXPECT_FALSE(grand_child2_raw->contributes_to_drawn_render_surface());
std::set<LayerImpl*> expected;
std::set<LayerImpl*> actual;
@@ -8420,11 +7711,11 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceLayerListMembership) {
ExecuteCalculateDrawProperties(grand_parent_raw);
- EXPECT_FALSE(grand_parent_raw->is_drawn_render_surface_layer_list_member());
- EXPECT_FALSE(parent_raw->is_drawn_render_surface_layer_list_member());
- EXPECT_FALSE(child_raw->is_drawn_render_surface_layer_list_member());
- EXPECT_FALSE(grand_child1_raw->is_drawn_render_surface_layer_list_member());
- EXPECT_FALSE(grand_child2_raw->is_drawn_render_surface_layer_list_member());
+ EXPECT_FALSE(grand_parent_raw->contributes_to_drawn_render_surface());
+ EXPECT_FALSE(parent_raw->contributes_to_drawn_render_surface());
+ EXPECT_FALSE(child_raw->contributes_to_drawn_render_surface());
+ EXPECT_FALSE(grand_child1_raw->contributes_to_drawn_render_surface());
+ EXPECT_FALSE(grand_child2_raw->contributes_to_drawn_render_surface());
expected.clear();
actual.clear();
@@ -8437,11 +7728,11 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceLayerListMembership) {
ExecuteCalculateDrawProperties(grand_parent_raw);
- EXPECT_FALSE(grand_parent_raw->is_drawn_render_surface_layer_list_member());
- EXPECT_FALSE(parent_raw->is_drawn_render_surface_layer_list_member());
- EXPECT_FALSE(child_raw->is_drawn_render_surface_layer_list_member());
- EXPECT_TRUE(grand_child1_raw->is_drawn_render_surface_layer_list_member());
- EXPECT_FALSE(grand_child2_raw->is_drawn_render_surface_layer_list_member());
+ EXPECT_FALSE(grand_parent_raw->contributes_to_drawn_render_surface());
+ EXPECT_FALSE(parent_raw->contributes_to_drawn_render_surface());
+ EXPECT_FALSE(child_raw->contributes_to_drawn_render_surface());
+ EXPECT_TRUE(grand_child1_raw->contributes_to_drawn_render_surface());
+ EXPECT_FALSE(grand_child2_raw->contributes_to_drawn_render_surface());
expected.clear();
expected.insert(grand_child1_raw);
@@ -8460,11 +7751,11 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceLayerListMembership) {
ExecuteCalculateDrawProperties(grand_parent_raw);
- EXPECT_FALSE(grand_parent_raw->is_drawn_render_surface_layer_list_member());
- EXPECT_FALSE(parent_raw->is_drawn_render_surface_layer_list_member());
- EXPECT_FALSE(child_raw->is_drawn_render_surface_layer_list_member());
- EXPECT_FALSE(grand_child1_raw->is_drawn_render_surface_layer_list_member());
- EXPECT_TRUE(grand_child2_raw->is_drawn_render_surface_layer_list_member());
+ EXPECT_FALSE(grand_parent_raw->contributes_to_drawn_render_surface());
+ EXPECT_FALSE(parent_raw->contributes_to_drawn_render_surface());
+ EXPECT_FALSE(child_raw->contributes_to_drawn_render_surface());
+ EXPECT_FALSE(grand_child1_raw->contributes_to_drawn_render_surface());
+ EXPECT_TRUE(grand_child2_raw->contributes_to_drawn_render_surface());
expected.clear();
expected.insert(grand_child2_raw);
@@ -8480,13 +7771,13 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceLayerListMembership) {
ExecuteCalculateDrawProperties(grand_parent_raw);
- EXPECT_FALSE(grand_parent_raw->is_drawn_render_surface_layer_list_member());
- EXPECT_FALSE(parent_raw->is_drawn_render_surface_layer_list_member());
- EXPECT_FALSE(child_raw->is_drawn_render_surface_layer_list_member());
+ EXPECT_FALSE(grand_parent_raw->contributes_to_drawn_render_surface());
+ EXPECT_FALSE(parent_raw->contributes_to_drawn_render_surface());
+ EXPECT_FALSE(child_raw->contributes_to_drawn_render_surface());
EXPECT_TRUE(child_raw->test_properties()
- ->mask_layer->is_drawn_render_surface_layer_list_member());
- EXPECT_FALSE(grand_child1_raw->is_drawn_render_surface_layer_list_member());
- EXPECT_TRUE(grand_child2_raw->is_drawn_render_surface_layer_list_member());
+ ->mask_layer->contributes_to_drawn_render_surface());
+ EXPECT_FALSE(grand_child1_raw->contributes_to_drawn_render_surface());
+ EXPECT_TRUE(grand_child2_raw->contributes_to_drawn_render_surface());
expected.clear();
expected.insert(grand_child2_raw);
@@ -8502,13 +7793,13 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceLayerListMembership) {
ExecuteCalculateDrawProperties(grand_parent_raw);
- EXPECT_FALSE(grand_parent_raw->is_drawn_render_surface_layer_list_member());
- EXPECT_FALSE(parent_raw->is_drawn_render_surface_layer_list_member());
- EXPECT_FALSE(child_raw->is_drawn_render_surface_layer_list_member());
+ EXPECT_FALSE(grand_parent_raw->contributes_to_drawn_render_surface());
+ EXPECT_FALSE(parent_raw->contributes_to_drawn_render_surface());
+ EXPECT_FALSE(child_raw->contributes_to_drawn_render_surface());
EXPECT_TRUE(child_raw->test_properties()
- ->mask_layer->is_drawn_render_surface_layer_list_member());
- EXPECT_FALSE(grand_child1_raw->is_drawn_render_surface_layer_list_member());
- EXPECT_TRUE(grand_child2_raw->is_drawn_render_surface_layer_list_member());
+ ->mask_layer->contributes_to_drawn_render_surface());
+ EXPECT_FALSE(grand_child1_raw->contributes_to_drawn_render_surface());
+ EXPECT_TRUE(grand_child2_raw->contributes_to_drawn_render_surface());
expected.clear();
expected.insert(grand_child2_raw);
@@ -8525,13 +7816,13 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceLayerListMembership) {
ExecuteCalculateDrawProperties(grand_parent_raw);
- EXPECT_FALSE(grand_parent_raw->is_drawn_render_surface_layer_list_member());
- EXPECT_FALSE(parent_raw->is_drawn_render_surface_layer_list_member());
- EXPECT_FALSE(child_raw->is_drawn_render_surface_layer_list_member());
+ EXPECT_FALSE(grand_parent_raw->contributes_to_drawn_render_surface());
+ EXPECT_FALSE(parent_raw->contributes_to_drawn_render_surface());
+ EXPECT_FALSE(child_raw->contributes_to_drawn_render_surface());
EXPECT_FALSE(child_raw->test_properties()
- ->mask_layer->is_drawn_render_surface_layer_list_member());
- EXPECT_FALSE(grand_child1_raw->is_drawn_render_surface_layer_list_member());
- EXPECT_FALSE(grand_child2_raw->is_drawn_render_surface_layer_list_member());
+ ->mask_layer->contributes_to_drawn_render_surface());
+ EXPECT_FALSE(grand_child1_raw->contributes_to_drawn_render_surface());
+ EXPECT_FALSE(grand_child2_raw->contributes_to_drawn_render_surface());
expected.clear();
actual.clear();
@@ -8544,13 +7835,13 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceLayerListMembership) {
ExecuteCalculateDrawProperties(grand_parent_raw);
- EXPECT_FALSE(grand_parent_raw->is_drawn_render_surface_layer_list_member());
- EXPECT_FALSE(parent_raw->is_drawn_render_surface_layer_list_member());
- EXPECT_TRUE(child_raw->is_drawn_render_surface_layer_list_member());
+ EXPECT_FALSE(grand_parent_raw->contributes_to_drawn_render_surface());
+ EXPECT_FALSE(parent_raw->contributes_to_drawn_render_surface());
+ EXPECT_TRUE(child_raw->contributes_to_drawn_render_surface());
EXPECT_TRUE(child_raw->test_properties()
- ->mask_layer->is_drawn_render_surface_layer_list_member());
- EXPECT_FALSE(grand_child1_raw->is_drawn_render_surface_layer_list_member());
- EXPECT_FALSE(grand_child2_raw->is_drawn_render_surface_layer_list_member());
+ ->mask_layer->contributes_to_drawn_render_surface());
+ EXPECT_FALSE(grand_child1_raw->contributes_to_drawn_render_surface());
+ EXPECT_FALSE(grand_child2_raw->contributes_to_drawn_render_surface());
expected.clear();
expected.insert(child_raw);
@@ -8571,11 +7862,11 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceLayerListMembership) {
ExecuteCalculateDrawProperties(grand_parent_raw);
- EXPECT_TRUE(grand_parent_raw->is_drawn_render_surface_layer_list_member());
- EXPECT_TRUE(parent_raw->is_drawn_render_surface_layer_list_member());
- EXPECT_TRUE(child_raw->is_drawn_render_surface_layer_list_member());
- EXPECT_TRUE(grand_child1_raw->is_drawn_render_surface_layer_list_member());
- EXPECT_TRUE(grand_child2_raw->is_drawn_render_surface_layer_list_member());
+ EXPECT_TRUE(grand_parent_raw->contributes_to_drawn_render_surface());
+ EXPECT_TRUE(parent_raw->contributes_to_drawn_render_surface());
+ EXPECT_TRUE(child_raw->contributes_to_drawn_render_surface());
+ EXPECT_TRUE(grand_child1_raw->contributes_to_drawn_render_surface());
+ EXPECT_TRUE(grand_child2_raw->contributes_to_drawn_render_surface());
expected.clear();
expected.insert(grand_parent_raw);
@@ -8659,12 +7950,12 @@ TEST_F(LayerTreeHostCommonTest, DrawPropertyScales) {
float page_scale_factor = 3.f;
float device_scale_factor = 1.0f;
- std::vector<LayerImpl*> render_surface_layer_list;
+ RenderSurfaceList render_surface_list;
gfx::Size device_viewport_size =
gfx::Size(root_layer->bounds().width() * device_scale_factor,
root_layer->bounds().height() * device_scale_factor);
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root_layer, device_viewport_size, &render_surface_layer_list);
+ root_layer, device_viewport_size, &render_surface_list);
inputs.page_scale_factor = page_scale_factor;
inputs.can_adjust_raster_scales = true;
@@ -8839,10 +8130,9 @@ TEST_F(LayerTreeHostCommonTest, VisibleContentRectInChildRenderSurface) {
content->test_properties()->force_render_surface = true;
gfx::Size device_viewport_size(768, 582);
- LayerImplList render_surface_layer_list_impl;
+ RenderSurfaceList render_surface_list_impl;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root, device_viewport_size, gfx::Transform(),
- &render_surface_layer_list_impl);
+ root, device_viewport_size, gfx::Transform(), &render_surface_list_impl);
inputs.device_scale_factor = 2.f;
inputs.page_scale_factor = 1.f;
inputs.page_scale_layer = nullptr;
@@ -8857,7 +8147,7 @@ TEST_F(LayerTreeHostCommonTest, VisibleContentRectInChildRenderSurface) {
EXPECT_EQ(gfx::Rect(768 / 2, 582 / 2), content->visible_layer_rect());
}
-TEST_F(LayerTreeHostCommonTest, BoundsDeltaAffectVisibleContentRect) {
+TEST_F(LayerTreeHostCommonTest, ViewportBoundsDeltaAffectVisibleContentRect) {
FakeImplTaskRunnerProvider task_runner_provider;
TestTaskGraphRunner task_graph_runner;
FakeLayerTreeHostImpl host_impl(&task_runner_provider, &task_graph_runner);
@@ -8881,6 +8171,12 @@ TEST_F(LayerTreeHostCommonTest, BoundsDeltaAffectVisibleContentRect) {
root->SetBounds(root_size);
root->SetMasksToBounds(true);
+ // Make root the inner viewport scroll layer. This ensures the later call to
+ // |SetViewportBoundsDelta| will be on a viewport layer.
+ LayerTreeImpl::ViewportLayerIds viewport_ids;
+ viewport_ids.inner_viewport_scroll = root->id();
+ host_impl.active_tree()->SetViewportLayersFromIds(viewport_ids);
+
root->test_properties()->AddChild(
LayerImpl::Create(host_impl.active_tree(), 2));
@@ -8890,14 +8186,14 @@ TEST_F(LayerTreeHostCommonTest, BoundsDeltaAffectVisibleContentRect) {
host_impl.active_tree()->BuildPropertyTreesForTesting();
- LayerImplList layer_impl_list;
+ RenderSurfaceList render_surface_list;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root, device_viewport_size, &layer_impl_list);
+ root, device_viewport_size, &render_surface_list);
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
EXPECT_EQ(gfx::Rect(root_size), sublayer->visible_layer_rect());
- root->SetBoundsDelta(gfx::Vector2dF(0.0, 50.0));
+ root->SetViewportBoundsDelta(gfx::Vector2dF(0.0, 50.0));
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
gfx::Rect affected_by_delta(0, 0, root_size.width(),
@@ -8905,7 +8201,7 @@ TEST_F(LayerTreeHostCommonTest, BoundsDeltaAffectVisibleContentRect) {
EXPECT_EQ(affected_by_delta, sublayer->visible_layer_rect());
}
-TEST_F(LayerTreeHostCommonTest, NodesAffectedByBoundsDeltaGetUpdated) {
+TEST_F(LayerTreeHostCommonTest, NodesAffectedByViewportBoundsDeltaGetUpdated) {
scoped_refptr<Layer> root = Layer::Create();
scoped_refptr<Layer> inner_viewport_container_layer = Layer::Create();
scoped_refptr<Layer> inner_viewport_scroll_layer = Layer::Create();
@@ -8926,8 +8222,13 @@ TEST_F(LayerTreeHostCommonTest, NodesAffectedByBoundsDeltaGetUpdated) {
outer_viewport_scroll_layer->SetIsContainerForFixedPositionLayers(true);
host()->SetRootLayer(root);
- host()->RegisterViewportLayers(nullptr, root, inner_viewport_scroll_layer,
- outer_viewport_scroll_layer);
+ LayerTreeHost::ViewportLayers viewport_layers;
+ viewport_layers.page_scale = root;
+ viewport_layers.inner_viewport_container = inner_viewport_container_layer;
+ viewport_layers.outer_viewport_container = outer_viewport_container_layer;
+ viewport_layers.inner_viewport_scroll = inner_viewport_scroll_layer;
+ viewport_layers.outer_viewport_scroll = outer_viewport_scroll_layer;
+ host()->RegisterViewportLayers(viewport_layers);
scoped_refptr<Layer> fixed_to_inner = Layer::Create();
scoped_refptr<Layer> fixed_to_outer = Layer::Create();
@@ -8994,14 +8295,31 @@ TEST_F(LayerTreeHostCommonTest, VisibleContentRectForAnimatedLayer) {
TEST_F(LayerTreeHostCommonTest,
VisibleContentRectForAnimatedLayerWithSingularTransform) {
- LayerImpl* root = root_layer_for_testing();
- LayerImpl* clip = AddChild<LayerImpl>(root);
- LayerImpl* animated = AddChild<LayerImpl>(clip);
- LayerImpl* surface = AddChild<LayerImpl>(animated);
- LayerImpl* descendant_of_animation = AddChild<LayerImpl>(surface);
+ host_impl()->CreatePendingTree();
+ std::unique_ptr<LayerImpl> root_ptr =
+ LayerImpl::Create(host_impl()->pending_tree(), 1);
+ LayerImpl* root = root_ptr.get();
+ host_impl()->pending_tree()->SetRootLayerForTesting(std::move(root_ptr));
+ std::unique_ptr<LayerImpl> clip_ptr =
+ LayerImpl::Create(host_impl()->pending_tree(), 2);
+ LayerImpl* clip = clip_ptr.get();
+ root->test_properties()->AddChild(std::move(clip_ptr));
+ std::unique_ptr<LayerImpl> animated_ptr =
+ LayerImpl::Create(host_impl()->pending_tree(), 3);
+ LayerImpl* animated = animated_ptr.get();
+ clip->test_properties()->AddChild(std::move(animated_ptr));
+ std::unique_ptr<LayerImpl> surface_ptr =
+ LayerImpl::Create(host_impl()->pending_tree(), 4);
+ LayerImpl* surface = surface_ptr.get();
+ animated->test_properties()->AddChild(std::move(surface_ptr));
+ std::unique_ptr<LayerImpl> descendant_of_animation_ptr =
+ LayerImpl::Create(host_impl()->pending_tree(), 5);
+ LayerImpl* descendant_of_animation = descendant_of_animation_ptr.get();
+ surface->test_properties()->AddChild(std::move(descendant_of_animation_ptr));
- SetElementIdsForTesting();
+ host_impl()->pending_tree()->SetElementIdsForTesting();
+ root->SetDrawsContent(true);
animated->SetDrawsContent(true);
surface->SetDrawsContent(true);
descendant_of_animation->SetDrawsContent(true);
@@ -9025,7 +8343,11 @@ TEST_F(LayerTreeHostCommonTest,
AddAnimatedTransformToElementWithPlayer(
animated->element_id(), timeline_impl(), 10.0, start_transform_operations,
end_transform_operations);
- ExecuteCalculateDrawPropertiesAndSaveUpdateLayerList(root);
+ ExecuteCalculateDrawProperties(root);
+ // Since animated has singular transform, it is not be part of render
+ // surface layer list but should be rastered.
+ EXPECT_FALSE(animated->contributes_to_drawn_render_surface());
+ EXPECT_TRUE(animated->raster_even_if_not_in_rsll());
// The animated layer has a singular transform and maps to a non-empty rect in
// clipped target space, so is treated as fully visible.
@@ -9040,7 +8362,7 @@ TEST_F(LayerTreeHostCommonTest,
zero_matrix.Scale3d(0.f, 0.f, 0.f);
root->layer_tree_impl()->SetTransformMutated(animated->element_id(),
zero_matrix);
- ExecuteCalculateDrawPropertiesAndSaveUpdateLayerList(root);
+ ExecuteCalculateDrawProperties(root);
// The animated layer will be treated as fully visible when we combine clips
// in screen space.
@@ -9051,6 +8373,22 @@ TEST_F(LayerTreeHostCommonTest,
// |surface| and layers that draw into it as having empty visible rect.
EXPECT_EQ(gfx::Rect(100, 100), surface->visible_layer_rect());
EXPECT_EQ(gfx::Rect(200, 200), descendant_of_animation->visible_layer_rect());
+
+ host_impl()->ActivateSyncTree();
+ LayerImpl* active_root = host_impl()->active_tree()->LayerById(root->id());
+ ExecuteCalculateDrawProperties(active_root);
+
+ // Since the animated has singular transform, it is not be part of render
+ // surface layer list.
+ LayerImpl* active_animated =
+ host_impl()->active_tree()->LayerById(animated->id());
+ EXPECT_TRUE(active_root->contributes_to_drawn_render_surface());
+ EXPECT_FALSE(active_animated->contributes_to_drawn_render_surface());
+
+ // Since animated has singular transform, it is not be part of render
+ // surface layer list but should be rastered.
+ EXPECT_TRUE(animated->raster_even_if_not_in_rsll());
+ EXPECT_EQ(gfx::Rect(120, 120), active_animated->visible_layer_rect());
}
// Verify that having animated opacity but current opacity 1 still creates
@@ -9072,9 +8410,14 @@ TEST_F(LayerTreeHostCommonTest, AnimatedOpacityCreatesRenderSurface) {
ExecuteCalculateDrawProperties(root);
EXPECT_EQ(1.f, child->Opacity());
- EXPECT_TRUE(root->GetRenderSurface());
- EXPECT_TRUE(child->GetRenderSurface());
- EXPECT_FALSE(grandchild->GetRenderSurface());
+ EXPECT_TRUE(GetRenderSurface(root));
+ EXPECT_NE(GetRenderSurface(child), GetRenderSurface(root));
+ EXPECT_EQ(GetRenderSurface(grandchild), GetRenderSurface(child));
+}
+
+static bool FilterIsAnimating(LayerImpl* layer) {
+ return layer->GetMutatorHost()->IsAnimatingFilterProperty(
+ layer->element_id(), layer->GetElementTypeForAnimation());
}
// Verify that having an animated filter (but no current filter, as these
@@ -9093,16 +8436,16 @@ TEST_F(LayerTreeHostCommonTest, AnimatedFilterCreatesRenderSurface) {
10.0, 0.1f, 0.2f);
ExecuteCalculateDrawProperties(root);
- EXPECT_TRUE(root->GetRenderSurface());
- EXPECT_TRUE(child->GetRenderSurface());
- EXPECT_FALSE(grandchild->GetRenderSurface());
+ EXPECT_TRUE(GetRenderSurface(root));
+ EXPECT_NE(GetRenderSurface(child), GetRenderSurface(root));
+ EXPECT_EQ(GetRenderSurface(grandchild), GetRenderSurface(child));
- EXPECT_TRUE(root->GetRenderSurface()->Filters().IsEmpty());
- EXPECT_TRUE(child->GetRenderSurface()->Filters().IsEmpty());
+ EXPECT_TRUE(GetRenderSurface(root)->Filters().IsEmpty());
+ EXPECT_TRUE(GetRenderSurface(child)->Filters().IsEmpty());
- EXPECT_FALSE(root->FilterIsAnimating());
- EXPECT_TRUE(child->FilterIsAnimating());
- EXPECT_FALSE(grandchild->FilterIsAnimating());
+ EXPECT_FALSE(FilterIsAnimating(root));
+ EXPECT_TRUE(FilterIsAnimating(child));
+ EXPECT_FALSE(FilterIsAnimating(grandchild));
}
// Verify that having a filter animation with a delayed start time creates a
@@ -9137,18 +8480,18 @@ TEST_F(LayerTreeHostCommonTest, DelayedFilterAnimationCreatesRenderSurface) {
std::move(animation));
ExecuteCalculateDrawProperties(root);
- EXPECT_TRUE(root->GetRenderSurface());
- EXPECT_TRUE(child->GetRenderSurface());
- EXPECT_FALSE(grandchild->GetRenderSurface());
+ EXPECT_TRUE(GetRenderSurface(root));
+ EXPECT_NE(GetRenderSurface(child), GetRenderSurface(root));
+ EXPECT_EQ(GetRenderSurface(grandchild), GetRenderSurface(child));
- EXPECT_TRUE(root->GetRenderSurface()->Filters().IsEmpty());
- EXPECT_TRUE(child->GetRenderSurface()->Filters().IsEmpty());
+ EXPECT_TRUE(GetRenderSurface(root)->Filters().IsEmpty());
+ EXPECT_TRUE(GetRenderSurface(child)->Filters().IsEmpty());
- EXPECT_FALSE(root->FilterIsAnimating());
+ EXPECT_FALSE(FilterIsAnimating(root));
EXPECT_FALSE(root->HasPotentiallyRunningFilterAnimation());
- EXPECT_FALSE(child->FilterIsAnimating());
+ EXPECT_FALSE(FilterIsAnimating(child));
EXPECT_TRUE(child->HasPotentiallyRunningFilterAnimation());
- EXPECT_FALSE(grandchild->FilterIsAnimating());
+ EXPECT_FALSE(FilterIsAnimating(grandchild));
EXPECT_FALSE(grandchild->HasPotentiallyRunningFilterAnimation());
}
@@ -9344,14 +8687,7 @@ TEST_F(LayerTreeHostCommonTest, UpdateScrollChildPosition) {
static void CopyOutputCallback(std::unique_ptr<CopyOutputResult> result) {}
-TEST_F(LayerTreeHostCommonTest, NumCopyRequestsInTargetSubtree) {
- // If the layer has a node in effect_tree, the return value of
- // num_copy_requests_in_target_subtree() must be equal to the actual number
- // of copy requests in the sub-layer_tree; Otherwise, the number is expected
- // to be the value of its nearest ancestor that owns an effect node and
- // greater than or equal to the actual number of copy requests in the
- // sub-layer_tree.
-
+TEST_F(LayerTreeHostCommonTest, HasCopyRequestsInTargetSubtree) {
scoped_refptr<Layer> root = Layer::Create();
scoped_refptr<Layer> child1 = Layer::Create();
scoped_refptr<Layer> child2 = Layer::Create();
@@ -9371,11 +8707,11 @@ TEST_F(LayerTreeHostCommonTest, NumCopyRequestsInTargetSubtree) {
child2->SetOpacity(0.f);
ExecuteCalculateDrawPropertiesAndSaveUpdateLayerList(root.get());
- EXPECT_EQ(root->num_copy_requests_in_target_subtree(), 2);
- EXPECT_EQ(child1->num_copy_requests_in_target_subtree(), 2);
- EXPECT_EQ(child2->num_copy_requests_in_target_subtree(), 0);
- EXPECT_EQ(grandchild->num_copy_requests_in_target_subtree(), 2);
- EXPECT_EQ(greatgrandchild->num_copy_requests_in_target_subtree(), 1);
+ EXPECT_TRUE(root->has_copy_requests_in_target_subtree());
+ EXPECT_TRUE(child1->has_copy_requests_in_target_subtree());
+ EXPECT_FALSE(child2->has_copy_requests_in_target_subtree());
+ EXPECT_TRUE(grandchild->has_copy_requests_in_target_subtree());
+ EXPECT_TRUE(greatgrandchild->has_copy_requests_in_target_subtree());
}
TEST_F(LayerTreeHostCommonTest, SkippingSubtreeMain) {
@@ -9781,10 +9117,10 @@ TEST_F(LayerTreeHostCommonTest, LayerTreeRebuildTest) {
CopyOutputRequest::CreateRequest(base::Bind(&EmptyCopyOutputCallback)));
ExecuteCalculateDrawPropertiesAndSaveUpdateLayerList(root.get());
- EXPECT_GT(root->num_copy_requests_in_target_subtree(), 0);
+ EXPECT_TRUE(root->has_copy_requests_in_target_subtree());
ExecuteCalculateDrawPropertiesAndSaveUpdateLayerList(root.get());
- EXPECT_GT(root->num_copy_requests_in_target_subtree(), 0);
+ EXPECT_TRUE(root->has_copy_requests_in_target_subtree());
}
TEST_F(LayerTreeHostCommonTest, ResetPropertyTreeIndices) {
@@ -9856,11 +9192,11 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceClipsSubtree) {
transform_tree.Node(significant_transform->transform_tree_index());
EXPECT_EQ(transform_node->owning_layer_id, significant_transform->id());
- EXPECT_TRUE(root->GetRenderSurface());
- EXPECT_FALSE(significant_transform->GetRenderSurface());
- EXPECT_TRUE(layer_clips_subtree->GetRenderSurface());
- EXPECT_TRUE(render_surface->GetRenderSurface());
- EXPECT_FALSE(test_layer->GetRenderSurface());
+ EXPECT_TRUE(GetRenderSurface(root));
+ EXPECT_EQ(GetRenderSurface(significant_transform), GetRenderSurface(root));
+ EXPECT_TRUE(GetRenderSurface(layer_clips_subtree));
+ EXPECT_NE(GetRenderSurface(render_surface), GetRenderSurface(root));
+ EXPECT_EQ(GetRenderSurface(test_layer), GetRenderSurface(render_surface));
EXPECT_EQ(gfx::Rect(30, 20), test_layer->visible_layer_rect());
}
@@ -10066,13 +9402,13 @@ TEST_F(LayerTreeHostCommonTest, RenderSurfaceContentRectWithMultipleSurfaces) {
ExecuteCalculateDrawProperties(root);
EXPECT_EQ(gfx::Rect(50, 50),
- unclipped_surface->GetRenderSurface()->content_rect());
+ GetRenderSurface(unclipped_surface)->content_rect());
EXPECT_EQ(gfx::Rect(50, 50),
- unclipped_desc_surface->GetRenderSurface()->content_rect());
+ GetRenderSurface(unclipped_desc_surface)->content_rect());
EXPECT_EQ(gfx::Rect(60, 60),
- unclipped_desc_surface2->GetRenderSurface()->content_rect());
+ GetRenderSurface(unclipped_desc_surface2)->content_rect());
EXPECT_EQ(gfx::Rect(50, 50),
- clipped_surface->GetRenderSurface()->content_rect());
+ GetRenderSurface(clipped_surface)->content_rect());
}
TEST_F(LayerTreeHostCommonTest, ClipBetweenClipChildTargetAndClipParentTarget) {
@@ -10114,7 +9450,7 @@ TEST_F(LayerTreeHostCommonTest, ClipBetweenClipChildTargetAndClipParentTarget) {
ExecuteCalculateDrawProperties(root);
EXPECT_EQ(gfx::Rect(10, 10),
- unclipped_desc_surface->GetRenderSurface()->content_rect());
+ GetRenderSurface(unclipped_desc_surface)->content_rect());
}
TEST_F(LayerTreeHostCommonTest, VisibleRectForDescendantOfScaledSurface) {
@@ -10278,13 +9614,13 @@ TEST_F(LayerTreeHostCommonTest, SubtreeIsHiddenTest) {
ExecuteCalculateDrawProperties(root);
EXPECT_EQ(0.f,
- test->GetRenderSurface()->OwningEffectNode()->screen_space_opacity);
+ GetRenderSurface(test)->OwningEffectNode()->screen_space_opacity);
hidden->test_properties()->hide_layer_and_subtree = false;
root->layer_tree_impl()->property_trees()->needs_rebuild = true;
ExecuteCalculateDrawProperties(root);
EXPECT_EQ(1.f,
- test->GetRenderSurface()->OwningEffectNode()->screen_space_opacity);
+ GetRenderSurface(test)->OwningEffectNode()->screen_space_opacity);
}
TEST_F(LayerTreeHostCommonTest, TwoUnclippedRenderSurfaces) {
@@ -10338,9 +9674,10 @@ TEST_F(LayerTreeHostCommonTest, MaskLayerDrawProperties) {
ExecuteCalculateDrawProperties(root);
// The render surface created for the mask has no contributing content, so the
- // mask isn't a drawn RSLL member. This means it has an empty visible rect,
- // but its screen space transform can still be computed correctly on-demand.
- EXPECT_FALSE(mask->is_drawn_render_surface_layer_list_member());
+ // mask doesn't contribute to a drawn render surface. This means it has an
+ // empty visible rect, but its screen space transform can still be computed
+ // correctly on-demand.
+ EXPECT_FALSE(mask->contributes_to_drawn_render_surface());
EXPECT_EQ(gfx::Rect(), mask->visible_layer_rect());
EXPECT_TRANSFORMATION_MATRIX_EQ(transform, mask->ScreenSpaceTransform());
@@ -10348,7 +9685,7 @@ TEST_F(LayerTreeHostCommonTest, MaskLayerDrawProperties) {
child->SetDrawsContent(true);
root->layer_tree_impl()->property_trees()->needs_rebuild = true;
ExecuteCalculateDrawProperties(root);
- EXPECT_TRUE(mask->is_drawn_render_surface_layer_list_member());
+ EXPECT_TRUE(mask->contributes_to_drawn_render_surface());
EXPECT_EQ(gfx::Rect(20, 20), mask->visible_layer_rect());
EXPECT_TRANSFORMATION_MATRIX_EQ(transform, mask->ScreenSpaceTransform());
@@ -10471,7 +9808,7 @@ TEST_F(LayerTreeHostCommonTest, LargeTransformTest) {
ExecuteCalculateDrawProperties(root);
EXPECT_EQ(gfx::RectF(),
- render_surface1->GetRenderSurface()->DrawableContentRect());
+ GetRenderSurface(render_surface1)->DrawableContentRect());
bool is_inf_or_nan = std::isinf(child->DrawTransform().matrix().get(0, 0)) ||
std::isnan(child->DrawTransform().matrix().get(0, 0));
@@ -10481,9 +9818,10 @@ TEST_F(LayerTreeHostCommonTest, LargeTransformTest) {
std::isnan(child->DrawTransform().matrix().get(1, 1));
EXPECT_TRUE(is_inf_or_nan);
- // The root layer should be in the RenderSurfaceLayerListImpl.
- const auto* rsll = render_surface_layer_list_impl();
- EXPECT_NE(std::find(rsll->begin(), rsll->end(), root), rsll->end());
+ // The root layer should be in the RenderSurfaceList.
+ const auto* rsl = render_surface_list_impl();
+ EXPECT_NE(std::find(rsl->begin(), rsl->end(), GetRenderSurface(root)),
+ rsl->end());
}
TEST_F(LayerTreeHostCommonTest, PropertyTreesRebuildWithOpacityChanges) {
@@ -10717,7 +10055,11 @@ TEST_F(LayerTreeHostCommonTest, ScrollTreeBuilderTest) {
parent5->SetNonFastScrollableRegion(gfx::Rect(0, 0, 50, 50));
parent5->SetBounds(gfx::Size(10, 10));
- host()->RegisterViewportLayers(nullptr, page_scale_layer, parent2, nullptr);
+ LayerTreeHost::ViewportLayers viewport_layers;
+ viewport_layers.page_scale = page_scale_layer;
+ viewport_layers.inner_viewport_container = root1;
+ viewport_layers.inner_viewport_scroll = parent2;
+ host()->RegisterViewportLayers(viewport_layers);
ExecuteCalculateDrawPropertiesAndSaveUpdateLayerList(root1.get());
const int kRootPropertyTreeNodeId = 0;
@@ -10860,10 +10202,10 @@ TEST_F(LayerTreeHostCommonTest, CanAdjustRasterScaleTest) {
// Check surface draw properties.
EXPECT_EQ(gfx::Rect(10, 10),
- render_surface->GetRenderSurface()->content_rect());
- EXPECT_EQ(transform, render_surface->GetRenderSurface()->draw_transform());
+ GetRenderSurface(render_surface)->content_rect());
+ EXPECT_EQ(transform, GetRenderSurface(render_surface)->draw_transform());
EXPECT_EQ(gfx::RectF(50.0f, 50.0f),
- render_surface->GetRenderSurface()->DrawableContentRect());
+ GetRenderSurface(render_surface)->DrawableContentRect());
// Check child layer draw properties.
EXPECT_EQ(gfx::Rect(10, 10), child->visible_layer_rect());
diff --git a/chromium/cc/trees/layer_tree_host_impl.cc b/chromium/cc/trees/layer_tree_host_impl.cc
index 05e4e3add0a..359d56d6e43 100644
--- a/chromium/cc/trees/layer_tree_host_impl.cc
+++ b/chromium/cc/trees/layer_tree_host_impl.cc
@@ -16,7 +16,7 @@
#include "base/auto_reset.h"
#include "base/bind.h"
-#include "base/containers/small_map.h"
+#include "base/containers/flat_map.h"
#include "base/json/json_writer.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram.h"
@@ -36,6 +36,7 @@
#include "cc/input/scroll_elasticity_helper.h"
#include "cc/input/scroll_state.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"
@@ -162,7 +163,7 @@ DEFINE_SCOPED_UMA_HISTOGRAM_TIMER(PendingTreeDurationHistogramTimer,
"Scheduling.%s.PendingTreeDuration");
LayerTreeHostImpl::FrameData::FrameData()
- : render_surface_layer_list(nullptr),
+ : render_surface_list(nullptr),
has_no_damage(false),
may_contain_video(false) {}
@@ -206,8 +207,6 @@ LayerTreeHostImpl::LayerTreeHostImpl(
did_lock_scrolling_layer_(false),
wheel_scrolling_(false),
scroll_affects_scroll_handler_(false),
- scroll_layer_id_mouse_currently_over_(Layer::INVALID_ID),
- scroll_layer_id_mouse_currently_captured_(Layer::INVALID_ID),
tile_priorities_dirty_(false),
settings_(settings),
visible_(false),
@@ -243,7 +242,8 @@ LayerTreeHostImpl::LayerTreeHostImpl(
scroll_animating_latched_node_id_(ScrollTree::kInvalidNodeId),
has_scrolled_by_wheel_(false),
has_scrolled_by_touch_(false),
- touchpad_and_wheel_scroll_latching_enabled_(false) {
+ touchpad_and_wheel_scroll_latching_enabled_(false),
+ impl_thread_phase_(ImplThreadPhase::IDLE) {
DCHECK(mutator_host_);
mutator_host_->SetMutatorHostClient(this);
@@ -325,15 +325,6 @@ void LayerTreeHostImpl::BeginMainFrameAborted(
void LayerTreeHostImpl::BeginCommit() {
TRACE_EVENT0("cc", "LayerTreeHostImpl::BeginCommit");
- // Ensure all textures are returned so partial texture updates can happen
- // during the commit.
- // TODO(ericrk): We should not need to ForceReclaimResources when using
- // Impl-side-painting as it doesn't upload during commits. However,
- // Display::Draw currently relies on resource being reclaimed to block drawing
- // between BeginCommit / Swap. See crbug.com/489515.
- if (compositor_frame_sink_)
- compositor_frame_sink_->ForceReclaimResources();
-
if (!CommitToActiveTree())
CreatePendingTree();
}
@@ -341,6 +332,11 @@ void LayerTreeHostImpl::BeginCommit() {
void LayerTreeHostImpl::CommitComplete() {
TRACE_EVENT0("cc", "LayerTreeHostImpl::CommitComplete");
+ // 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_ && impl_thread_phase_ == ImplThreadPhase::IDLE)
+ input_handler_client_->DeliverInputForBeginFrame();
+
UpdateSyncTreeAfterCommitOrImplSideInvalidation();
micro_benchmark_controller_.DidCompleteCommit();
}
@@ -350,6 +346,8 @@ void LayerTreeHostImpl::UpdateSyncTreeAfterCommitOrImplSideInvalidation() {
tile_manager_.TakeImagesToInvalidateOnSyncTree());
if (CommitToActiveTree()) {
+ active_tree_->HandleScrollbarShowRequestsFromMain();
+
// We have to activate animations here or "IsActive()" is true on the layers
// but the animations aren't activated yet so they get ignored by
// UpdateDrawProperties.
@@ -416,7 +414,7 @@ bool LayerTreeHostImpl::CanDraw() const {
if (resourceless_software_draw_)
return true;
- if (DrawViewportSize().IsEmpty()) {
+ if (DeviceViewport().IsEmpty()) {
TRACE_EVENT_INSTANT0("cc", "LayerTreeHostImpl::CanDraw empty viewport",
TRACE_EVENT_SCOPE_THREAD);
return false;
@@ -577,21 +575,20 @@ bool LayerTreeHostImpl::IsCurrentlyScrollingLayerAt(
bool scroll_on_main_thread = false;
uint32_t main_thread_scrolling_reasons;
- LayerImpl* test_layer_impl = FindScrollLayerForDeviceViewportPoint(
+ auto* test_scroll_node = FindScrollNodeForDeviceViewportPoint(
device_viewport_point, type, layer_impl, &scroll_on_main_thread,
&main_thread_scrolling_reasons);
if (scroll_on_main_thread)
return false;
- int test_scroll_tree_index = test_layer_impl->scroll_tree_index();
- if (scrolling_node->id == test_scroll_tree_index)
+ if (scrolling_node == test_scroll_node)
return true;
// For active scrolling state treat the inner/outer viewports interchangeably.
if (scrolling_node->scrolls_inner_viewport ||
scrolling_node->scrolls_outer_viewport) {
- return test_layer_impl == viewport()->MainScrollLayer();
+ return test_scroll_node == OuterViewportScrollNode();
}
return false;
@@ -707,27 +704,6 @@ void LayerTreeHostImpl::QueueSwapPromiseForMainThreadScrollUpdate(
std::move(swap_promise));
}
-void LayerTreeHostImpl::TrackDamageForAllSurfaces(
- const LayerImplList& render_surface_layer_list) {
- // For now, we use damage tracking to compute a global scissor. To do this, we
- // must compute all damage tracking before drawing anything, so that we know
- // the root damage rect. The root damage rect is then used to scissor each
- // surface.
- size_t render_surface_layer_list_size = render_surface_layer_list.size();
- for (size_t i = 0; i < render_surface_layer_list_size; ++i) {
- size_t surface_index = render_surface_layer_list_size - 1 - i;
- LayerImpl* render_surface_layer = render_surface_layer_list[surface_index];
- RenderSurfaceImpl* render_surface =
- render_surface_layer->GetRenderSurface();
- DCHECK(render_surface);
- render_surface->damage_tracker()->UpdateDamageTrackingState(
- render_surface->layer_list(), render_surface,
- render_surface->SurfacePropertyChangedOnlyFromDescendant(),
- render_surface->content_rect(), render_surface->MaskLayer(),
- render_surface->Filters());
- }
-}
-
void LayerTreeHostImpl::FrameData::AsValueInto(
base::trace_event::TracedValue* value) const {
value->SetBoolean("has_no_damage", has_no_damage);
@@ -758,11 +734,12 @@ DrawMode LayerTreeHostImpl::GetDrawMode() const {
}
}
-static void AppendQuadsToFillScreen(const gfx::Rect& root_scroll_layer_rect,
- RenderPass* target_render_pass,
- RenderSurfaceImpl* root_render_surface,
- SkColor screen_background_color,
- const Region& fill_region) {
+static void AppendQuadsToFillScreen(
+ const gfx::Rect& root_scroll_layer_rect,
+ RenderPass* target_render_pass,
+ const RenderSurfaceImpl* root_render_surface,
+ SkColor screen_background_color,
+ const Region& fill_region) {
if (!root_render_surface || !SkColorGetA(screen_background_color))
return;
if (fill_region.IsEmpty())
@@ -778,7 +755,7 @@ static void AppendQuadsToFillScreen(const gfx::Rect& root_scroll_layer_rect,
int sorting_context_id = 0;
SharedQuadState* shared_quad_state =
target_render_pass->CreateAndAppendSharedQuadState();
- shared_quad_state->SetAll(gfx::Transform(), root_target_rect.size(),
+ shared_quad_state->SetAll(gfx::Transform(), root_target_rect,
root_target_rect, root_target_rect, false, opacity,
SkBlendMode::kSrcOver, sorting_context_id);
@@ -807,19 +784,24 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) {
DCHECK(CanDraw());
DCHECK(!active_tree_->LayerListIsEmpty());
- TrackDamageForAllSurfaces(*frame->render_surface_layer_list);
+ // For now, we use damage tracking to compute a global scissor. To do this, we
+ // must compute all damage tracking before drawing anything, so that we know
+ // the root damage rect. The root damage rect is then used to scissor each
+ // surface.
+ DamageTracker::UpdateDamageTracking(active_tree_.get(),
+ active_tree_->GetRenderSurfaceList());
// If the root render surface has no visible damage, then don't generate a
// frame at all.
- RenderSurfaceImpl* root_surface = active_tree_->RootRenderSurface();
+ const RenderSurfaceImpl* root_surface = active_tree_->RootRenderSurface();
bool root_surface_has_no_visible_damage =
!root_surface->GetDamageRect().Intersects(root_surface->content_rect());
bool root_surface_has_contributing_layers =
- !root_surface->layer_list().empty();
+ !!root_surface->num_contributors();
bool hud_wants_to_draw_ = active_tree_->hud_layer() &&
active_tree_->hud_layer()->IsAnimatingHUDContents();
- bool resources_must_be_resent =
- compositor_frame_sink_->capabilities().can_force_reclaim_resources;
+ bool must_always_swap =
+ compositor_frame_sink_->capabilities().must_always_swap;
// When touch handle visibility changes there is no visible damage
// because touch handles are composited in the browser. However we
// still want the browser to be notified that the handles changed
@@ -830,8 +812,7 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) {
if (root_surface_has_contributing_layers &&
root_surface_has_no_visible_damage &&
!active_tree_->property_trees()->effect_tree.HasCopyRequests() &&
- !resources_must_be_resent && !hud_wants_to_draw_ &&
- !handle_visibility_changed) {
+ !must_always_swap && !hud_wants_to_draw_ && !handle_visibility_changed) {
TRACE_EVENT0("cc",
"LayerTreeHostImpl::CalculateRenderPasses::EmptyDamageRect");
frame->has_no_damage = true;
@@ -839,25 +820,22 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) {
return DRAW_SUCCESS;
}
- TRACE_EVENT_BEGIN2(
- "cc", "LayerTreeHostImpl::CalculateRenderPasses",
- "render_surface_layer_list.size()",
- static_cast<uint64_t>(frame->render_surface_layer_list->size()),
- "RequiresHighResToDraw", RequiresHighResToDraw());
+ TRACE_EVENT_BEGIN2("cc", "LayerTreeHostImpl::CalculateRenderPasses",
+ "render_surface_list.size()",
+ static_cast<uint64_t>(frame->render_surface_list->size()),
+ "RequiresHighResToDraw", RequiresHighResToDraw());
// Create the render passes in dependency order.
- size_t render_surface_layer_list_size =
- frame->render_surface_layer_list->size();
- for (size_t i = 0; i < render_surface_layer_list_size; ++i) {
- size_t surface_index = render_surface_layer_list_size - 1 - i;
- LayerImpl* render_surface_layer =
- (*frame->render_surface_layer_list)[surface_index];
+ size_t render_surface_list_size = frame->render_surface_list->size();
+ for (size_t i = 0; i < render_surface_list_size; ++i) {
+ size_t surface_index = render_surface_list_size - 1 - i;
RenderSurfaceImpl* render_surface =
- render_surface_layer->GetRenderSurface();
+ (*frame->render_surface_list)[surface_index];
+ bool is_root_surface =
+ render_surface->EffectTreeIndex() == EffectTree::kContentsRootNodeId;
bool should_draw_into_render_pass =
- active_tree_->IsRootLayer(render_surface_layer) ||
- render_surface->contributes_to_drawn_surface() ||
+ is_root_surface || render_surface->contributes_to_drawn_surface() ||
render_surface->HasCopyRequest();
if (should_draw_into_render_pass)
frame->render_passes.push_back(render_surface->CreateRenderPass());
@@ -967,15 +945,13 @@ DrawResult LayerTreeHostImpl::CalculateRenderPasses(FrameData* frame) {
append_quads_data.checkerboarded_needs_raster_content_area;
if (append_quads_data.num_missing_tiles > 0) {
have_missing_animated_tiles |=
- !layer->was_ever_ready_since_last_transform_animation() ||
layer->screen_space_transform_is_animating();
- } else {
- layer->set_was_ever_ready_since_last_transform_animation(true);
}
}
- frame->embedded_surfaces.insert(frame->embedded_surfaces.end(),
- append_quads_data.embedded_surfaces.begin(),
- append_quads_data.embedded_surfaces.end());
+ frame->activation_dependencies.insert(
+ frame->activation_dependencies.end(),
+ append_quads_data.activation_dependencies.begin(),
+ append_quads_data.activation_dependencies.end());
}
// If CommitToActiveTree() is true, then we wait to draw until
@@ -1091,6 +1067,19 @@ void LayerTreeHostImpl::InvalidateContentOnImplSide() {
if (!CommitToActiveTree())
CreatePendingTree();
+
+ // The state of PropertyTrees on the recycle tree can be stale if scrolling
+ // and animation updates were made on the active tree, since these are not
+ // replicated on the recycle tree. We use the function below to handle the
+ // similar case for updates from the main thread not being in sync with
+ // changes made on the active tree.
+ // Note that while in practice only the scroll state should need to be
+ // updated, since the animation state is updated both on the recycle and
+ // active tree. We use the same function as for main thread commits for
+ // consistency.
+ bool is_impl_side_update = true;
+ sync_tree()->UpdatePropertyTreeScrollingAndAnimationFromMainThread(
+ is_impl_side_update);
UpdateSyncTreeAfterCommitOrImplSideInvalidation();
}
@@ -1128,7 +1117,7 @@ DrawResult LayerTreeHostImpl::PrepareToDraw(FrameData* frame) {
// they appear as part of the current frame being drawn.
tile_manager_.Flush();
- frame->render_surface_layer_list = &active_tree_->RenderSurfaceLayerList();
+ frame->render_surface_list = &active_tree_->GetRenderSurfaceList();
frame->render_passes.clear();
frame->will_draw_layers.clear();
frame->has_no_damage = false;
@@ -1158,10 +1147,10 @@ void LayerTreeHostImpl::RemoveRenderPasses(FrameData* frame) {
DCHECK_GE(frame->render_passes.size(), 1u);
// A set of RenderPasses that we have seen.
- std::set<int> pass_exists;
+ base::flat_set<int> pass_exists;
// A set of RenderPassDrawQuads that we have seen (stored by the RenderPasses
// they refer to).
- base::SmallMap<std::unordered_map<int, int>> pass_references;
+ base::flat_map<int, int> pass_references;
// Iterate RenderPasses in draw order, removing empty render passes (except
// the root RenderPass).
@@ -1296,6 +1285,14 @@ void LayerTreeHostImpl::UpdateTileManagerMemoryPolicy(
// running work.
if (image_decode_cache_)
image_decode_cache_->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
+ // images that have been displayed since the resources, if held by the
+ // browser, may be re-used. Which is why its important to maintain the
+ // decode policy tracking.
+ bool can_clear_decode_policy_tracking = false;
+ tile_manager_.ClearCheckerImageTracking(can_clear_decode_policy_tracking);
}
DCHECK(resource_pool_);
@@ -1352,11 +1349,23 @@ void LayerTreeHostImpl::SetIsLikelyToRequireADraw(
}
gfx::ColorSpace LayerTreeHostImpl::GetRasterColorSpace() const {
+ gfx::ColorSpace result;
if (!settings_.enable_color_correct_rasterization)
- return gfx::ColorSpace();
- if (!sync_tree())
- return gfx::ColorSpace::CreateSRGB();
- return sync_tree()->raster_color_space();
+ return result;
+
+ // The pending tree will have the most recently updated color space, so
+ // prefer that.
+ if (pending_tree_)
+ result = pending_tree_->raster_color_space();
+ else if (active_tree_)
+ result = active_tree_->raster_color_space();
+
+ // Always specify a color space if color correct rasterization is requested
+ // (not specifying a color space indicates that no color conversion is
+ // required).
+ if (!result.IsValid())
+ result = gfx::ColorSpace::CreateSRGB();
+ return result;
}
void LayerTreeHostImpl::RequestImplSideInvalidation() {
@@ -1674,8 +1683,8 @@ bool LayerTreeHostImpl::DrawLayers(FrameData* frame) {
if (debug_state_.ShowHudRects()) {
debug_rect_history_->SaveDebugRectsForCurrentFrame(
- active_tree(), active_tree_->hud_layer(),
- *frame->render_surface_layer_list, debug_state_);
+ active_tree(), active_tree_->hud_layer(), *frame->render_surface_list,
+ debug_state_);
}
bool is_new_trace;
@@ -1709,7 +1718,7 @@ bool LayerTreeHostImpl::DrawLayers(FrameData* frame) {
CompositorFrameMetadata metadata = MakeCompositorFrameMetadata();
metadata.may_contain_video = frame->may_contain_video;
- metadata.embedded_surfaces = std::move(frame->embedded_surfaces);
+ metadata.activation_dependencies = std::move(frame->activation_dependencies);
active_tree()->FinishSwapPromises(&metadata);
for (auto& latency : metadata.latency_info) {
TRACE_EVENT_WITH_FLOW1("input,benchmark", "LatencyInfo.Flow",
@@ -1745,7 +1754,8 @@ bool LayerTreeHostImpl::DrawLayers(FrameData* frame) {
compositor_frame.render_pass_list = std::move(frame->render_passes);
// TODO(fsamuel): Once all clients get their LocalSurfaceId from their parent,
// the LocalSurfaceId should hang off CompositorFrameMetadata.
- if (active_tree()->local_surface_id().is_valid()) {
+ if (settings_.enable_surface_synchronization &&
+ active_tree()->local_surface_id().is_valid()) {
compositor_frame_sink_->SetLocalSurfaceId(
active_tree()->local_surface_id());
}
@@ -1759,8 +1769,8 @@ bool LayerTreeHostImpl::DrawLayers(FrameData* frame) {
// are noted as they occur.
// TODO(boliu): If we did a temporary software renderer frame, propogate the
// damage forward to the next frame.
- for (size_t i = 0; i < frame->render_surface_layer_list->size(); i++) {
- auto* surface = (*frame->render_surface_layer_list)[i]->GetRenderSurface();
+ for (size_t i = 0; i < frame->render_surface_list->size(); i++) {
+ auto* surface = (*frame->render_surface_list)[i];
surface->damage_tracker()->DidDrawDamagedArea();
}
active_tree_->ResetAllChangeTracking();
@@ -1857,14 +1867,13 @@ bool LayerTreeHostImpl::UpdateGpuRasterizationStatus() {
gpu_rasterization_status_ = GpuRasterizationStatus::OFF_DEVICE;
} else if (!has_gpu_rasterization_trigger_) {
gpu_rasterization_status_ = GpuRasterizationStatus::OFF_VIEWPORT;
- } else if (content_is_suitable_for_gpu_rasterization_) {
- use_gpu = true;
- gpu_rasterization_status_ = GpuRasterizationStatus::ON;
- } else if (using_msaa_for_complex_content) {
+ } else if (!content_is_suitable_for_gpu_rasterization_ &&
+ using_msaa_for_complex_content) {
use_gpu = use_msaa = true;
gpu_rasterization_status_ = GpuRasterizationStatus::MSAA_CONTENT;
} else {
- gpu_rasterization_status_ = GpuRasterizationStatus::OFF_CONTENT;
+ use_gpu = true;
+ gpu_rasterization_status_ = GpuRasterizationStatus::ON;
}
if (use_gpu && !use_gpu_rasterization_) {
@@ -1929,13 +1938,21 @@ void LayerTreeHostImpl::WillBeginImplFrame(const BeginFrameArgs& args) {
for (auto* it : video_frame_controllers_)
it->OnBeginFrame(args);
+
+ impl_thread_phase_ = ImplThreadPhase::INSIDE_IMPL_FRAME;
}
void LayerTreeHostImpl::DidFinishImplFrame() {
+ impl_thread_phase_ = ImplThreadPhase::IDLE;
current_begin_frame_tracker_.Finish();
decoded_image_tracker_.NotifyFrameFinished();
}
+void LayerTreeHostImpl::DidNotProduceFrame(const BeginFrameAck& ack) {
+ if (compositor_frame_sink_)
+ compositor_frame_sink_->DidNotProduceFrame(ack);
+}
+
void LayerTreeHostImpl::UpdateViewportContainerSizes() {
LayerImpl* inner_container = active_tree_->InnerViewportContainerLayer();
LayerImpl* outer_container = active_tree_->OuterViewportContainerLayer();
@@ -1964,7 +1981,7 @@ void LayerTreeHostImpl::UpdateViewportContainerSizes() {
// for changes in the size (e.g. browser controls) since the last resize from
// Blink.
gfx::Vector2dF amount_to_expand(0.f, delta_from_top_controls);
- inner_container->SetBoundsDelta(amount_to_expand);
+ inner_container->SetViewportBoundsDelta(amount_to_expand);
if (outer_container && !outer_container->BoundsForScrolling().IsEmpty()) {
// Adjust the outer viewport container as well, since adjusting only the
@@ -1972,8 +1989,8 @@ void LayerTreeHostImpl::UpdateViewportContainerSizes() {
// clamping.
gfx::Vector2dF amount_to_expand_scaled = gfx::ScaleVector2d(
amount_to_expand, 1.f / active_tree_->min_page_scale_factor());
- outer_container->SetBoundsDelta(amount_to_expand_scaled);
- active_tree_->InnerViewportScrollLayer()->SetBoundsDelta(
+ outer_container->SetViewportBoundsDelta(amount_to_expand_scaled);
+ active_tree_->InnerViewportScrollLayer()->SetViewportBoundsDelta(
amount_to_expand_scaled);
anchor.ResetViewportToAnchoredPosition();
@@ -2049,9 +2066,38 @@ void LayerTreeHostImpl::CreatePendingTree() {
pending_tree_duration_timer_.reset(new PendingTreeDurationHistogramTimer());
}
+void LayerTreeHostImpl::PushScrollbarOpacitiesFromActiveToPending() {
+ if (!active_tree())
+ return;
+ for (auto& pair : scrollbar_animation_controllers_) {
+ for (auto* scrollbar : pair.second->Scrollbars()) {
+ if (const EffectNode* source_effect_node =
+ active_tree()
+ ->property_trees()
+ ->effect_tree.FindNodeFromElementId(
+ scrollbar->element_id())) {
+ if (EffectNode* target_effect_node =
+ pending_tree()
+ ->property_trees()
+ ->effect_tree.FindNodeFromElementId(
+ scrollbar->element_id())) {
+ DCHECK(target_effect_node);
+ float source_opacity = source_effect_node->opacity;
+ float target_opacity = target_effect_node->opacity;
+ if (source_opacity == target_opacity)
+ continue;
+ target_effect_node->opacity = source_opacity;
+ pending_tree()->property_trees()->effect_tree.set_needs_update(true);
+ }
+ }
+ }
+ }
+}
+
void LayerTreeHostImpl::ActivateSyncTree() {
if (pending_tree_) {
TRACE_EVENT_ASYNC_END0("cc", "PendingTree:waiting", pending_tree_.get());
+ active_tree_->lifecycle().AdvanceTo(LayerTreeLifecycle::kBeginningSync);
DCHECK(pending_tree_duration_timer_);
// Reset will call the destructor and log the timer histogram.
@@ -2067,25 +2113,21 @@ void LayerTreeHostImpl::ActivateSyncTree() {
active_tree_.get());
}
- // Property trees may store damage status. We preserve the active tree
- // damage status by pushing the damage status from active tree property
- // trees to pending tree property trees or by moving it onto the layers.
- if (active_tree_->property_trees()->changed) {
- if (pending_tree_->property_trees()->sequence_number ==
- active_tree_->property_trees()->sequence_number)
- active_tree_->property_trees()->PushChangeTrackingTo(
- pending_tree_->property_trees());
- else
- active_tree_->MoveChangeTrackingToLayers();
- }
+ PushScrollbarOpacitiesFromActiveToPending();
+ pending_tree_->PushPropertyTreesTo(active_tree_.get());
+ active_tree_->lifecycle().AdvanceTo(
+ LayerTreeLifecycle::kSyncedPropertyTrees);
+
TreeSynchronizer::PushLayerProperties(pending_tree(), active_tree());
- active_tree_->property_trees()->PushOpacityIfNeeded(
- pending_tree_->property_trees());
+ active_tree_->lifecycle().AdvanceTo(
+ LayerTreeLifecycle::kSyncedLayerProperties);
pending_tree_->PushPropertiesTo(active_tree_.get());
if (!pending_tree_->LayerListIsEmpty())
pending_tree_->property_trees()->ResetAllChangeTracking();
+ active_tree_->lifecycle().AdvanceTo(LayerTreeLifecycle::kNotSyncing);
+
// Now that we've synced everything from the pending tree to the active
// tree, rename the pending tree the recycle tree so we can reuse it on the
// next sync.
@@ -2264,7 +2306,8 @@ void LayerTreeHostImpl::CreateResourceAndRasterBufferProvider(
*resource_pool =
ResourcePool::Create(resource_provider_.get(), GetTaskRunner(),
ResourceProvider::TEXTURE_HINT_IMMUTABLE,
- ResourcePool::kDefaultExpirationDelay);
+ ResourcePool::kDefaultExpirationDelay,
+ settings_.disallow_non_exact_resource_reuse);
*raster_buffer_provider =
BitmapRasterBufferProvider::Create(resource_provider_.get());
@@ -2279,7 +2322,8 @@ void LayerTreeHostImpl::CreateResourceAndRasterBufferProvider(
*resource_pool = ResourcePool::Create(
resource_provider_.get(), GetTaskRunner(),
ResourceProvider::TEXTURE_HINT_IMMUTABLE_FRAMEBUFFER,
- ResourcePool::kDefaultExpirationDelay);
+ ResourcePool::kDefaultExpirationDelay,
+ settings_.disallow_non_exact_resource_reuse);
int msaa_sample_count = use_msaa_ ? RequestedMSAASampleCount() : 0;
@@ -2304,7 +2348,8 @@ void LayerTreeHostImpl::CreateResourceAndRasterBufferProvider(
*resource_pool = ResourcePool::CreateForGpuMemoryBufferResources(
resource_provider_.get(), GetTaskRunner(),
gfx::BufferUsage::GPU_READ_CPU_READ_WRITE,
- ResourcePool::kDefaultExpirationDelay);
+ ResourcePool::kDefaultExpirationDelay,
+ settings_.disallow_non_exact_resource_reuse);
*raster_buffer_provider = ZeroCopyRasterBufferProvider::Create(
resource_provider_.get(),
@@ -2315,7 +2360,8 @@ void LayerTreeHostImpl::CreateResourceAndRasterBufferProvider(
*resource_pool =
ResourcePool::Create(resource_provider_.get(), GetTaskRunner(),
ResourceProvider::TEXTURE_HINT_IMMUTABLE,
- ResourcePool::kDefaultExpirationDelay);
+ ResourcePool::kDefaultExpirationDelay,
+ settings_.disallow_non_exact_resource_reuse);
const int max_copy_texture_chromium_size =
compositor_context_provider->ContextCapabilities()
@@ -2367,6 +2413,10 @@ LayerTreeHostImpl::TakeCompletedImageDecodeCallbacks() {
}
void LayerTreeHostImpl::ClearImageCacheOnNavigation() {
+ // It is safe to clear the decode policy tracking on navigations since it
+ // 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();
}
@@ -2514,17 +2564,6 @@ void LayerTreeHostImpl::SetViewportSize(const gfx::Size& device_viewport_size) {
active_tree_->set_needs_update_draw_properties();
}
-const gfx::Rect LayerTreeHostImpl::ViewportRectForTilePriority() const {
- if (viewport_rect_for_tile_priority_.IsEmpty())
- return DeviceViewport();
-
- return viewport_rect_for_tile_priority_;
-}
-
-gfx::Size LayerTreeHostImpl::DrawViewportSize() const {
- return DeviceViewport().size();
-}
-
gfx::Rect LayerTreeHostImpl::DeviceViewport() const {
if (external_viewport_.IsEmpty())
return gfx::Rect(device_viewport_size_);
@@ -2532,6 +2571,13 @@ gfx::Rect LayerTreeHostImpl::DeviceViewport() const {
return external_viewport_;
}
+const gfx::Rect LayerTreeHostImpl::ViewportRectForTilePriority() const {
+ if (viewport_rect_for_tile_priority_.IsEmpty())
+ return DeviceViewport();
+
+ return viewport_rect_for_tile_priority_;
+}
+
const gfx::Transform& LayerTreeHostImpl::DrawTransform() const {
return external_transform_;
}
@@ -2656,7 +2702,7 @@ static bool IsMainThreadScrolling(const InputHandler::ScrollStatus& status,
return false;
}
-LayerImpl* LayerTreeHostImpl::FindScrollLayerForDeviceViewportPoint(
+ScrollNode* LayerTreeHostImpl::FindScrollNodeForDeviceViewportPoint(
const gfx::PointF& device_viewport_point,
InputHandler::ScrollInputType type,
LayerImpl* layer_impl,
@@ -2681,7 +2727,7 @@ LayerImpl* LayerTreeHostImpl::FindScrollLayerForDeviceViewportPoint(
if (IsMainThreadScrolling(status, scroll_node)) {
*scroll_on_main_thread = true;
*main_thread_scrolling_reasons = status.main_thread_scrolling_reasons;
- return active_tree_->LayerById(scroll_node->owning_layer_id);
+ return scroll_node;
}
if (status.thread == InputHandler::SCROLL_ON_IMPL_THREAD &&
@@ -2711,11 +2757,7 @@ LayerImpl* LayerTreeHostImpl::FindScrollLayerForDeviceViewportPoint(
}
}
- // TODO(pdr): Refactor this function to directly return |impl_scroll_node|
- // instead of using ScrollNode's owning_layer_id to return a LayerImpl.
- if (!impl_scroll_node)
- return nullptr;
- return active_tree_->LayerById(impl_scroll_node->owning_layer_id);
+ return impl_scroll_node;
}
InputHandler::ScrollStatus LayerTreeHostImpl::ScrollBeginImpl(
@@ -2800,13 +2842,25 @@ InputHandler::ScrollStatus LayerTreeHostImpl::ScrollBegin(
}
}
- auto* scrolling_layer = FindScrollLayerForDeviceViewportPoint(
+ scrolling_node = FindScrollNodeForDeviceViewportPoint(
device_viewport_point, type, layer_impl, &scroll_on_main_thread,
&scroll_status.main_thread_scrolling_reasons);
- ScrollTree& scroll_tree = active_tree_->property_trees()->scroll_tree;
- scrolling_node =
- scrolling_layer ? scroll_tree.Node(scrolling_layer->scroll_tree_index())
- : nullptr;
+ if (!scroll_on_main_thread && scrolling_node &&
+ (settings_.is_layer_tree_for_subframe ||
+ (!scrolling_node->scrolls_outer_viewport &&
+ !scrolling_node->scrolls_inner_viewport))) {
+ if (IsWheelBasedScroll(type)) {
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ "Event.Scroll.ScrollerSize.OnScroll_Wheel",
+ scrolling_node->scroll_clip_layer_bounds.GetArea(), 1,
+ kScrollerSizeLargestBucket, kScrollerSizeBucketCount);
+ } else {
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ "Event.Scroll.ScrollerSize.OnScroll_Touch",
+ scrolling_node->scroll_clip_layer_bounds.GetArea(), 1,
+ kScrollerSizeLargestBucket, kScrollerSizeBucketCount);
+ }
+ }
}
if (scroll_on_main_thread) {
@@ -2946,8 +3000,14 @@ bool LayerTreeHostImpl::ScrollAnimationCreate(ScrollNode* scroll_node,
active_tree()->LayerById(scroll_node->owning_layer_id)->element_id()),
scroll_node->element_id);
+ // Start the animation one full frame in. Without any offset, the animation
+ // doesn't start until next frame, increasing latency, and preventing our
+ // input latency tracking architecture from working.
+ base::TimeDelta animation_start_offset = CurrentBeginFrameArgs().interval;
+
mutator_host_->ImplOnlyScrollAnimationCreate(
- scroll_node->element_id, target_offset, current_offset, delayed_by);
+ scroll_node->element_id, target_offset, current_offset, delayed_by,
+ animation_start_offset);
SetNeedsOneBeginImplFrame();
@@ -2967,7 +3027,7 @@ InputHandler::ScrollStatus LayerTreeHostImpl::ScrollAnimated(
if (scroll_node) {
// Flash the overlay scrollbar even if the scroll dalta is 0.
ScrollbarAnimationController* animation_controller =
- ScrollbarAnimationControllerForId(scroll_node->owning_layer_id);
+ ScrollbarAnimationControllerForElementId(scroll_node->element_id);
if (animation_controller)
animation_controller->WillUpdateScroll();
@@ -3018,7 +3078,7 @@ InputHandler::ScrollStatus LayerTreeHostImpl::ScrollAnimated(
if (scrolls_main_viewport_scroll_layer) {
// Flash the overlay scrollbar even if the scroll dalta is 0.
ScrollbarAnimationController* animation_controller =
- ScrollbarAnimationControllerForId(scroll_node->owning_layer_id);
+ ScrollbarAnimationControllerForElementId(scroll_node->element_id);
if (animation_controller)
animation_controller->WillUpdateScroll();
@@ -3286,7 +3346,7 @@ InputHandlerScrollResult LayerTreeHostImpl::ScrollBy(
return InputHandlerScrollResult();
ScrollbarAnimationController* animation_controller =
- ScrollbarAnimationControllerForId(scroll_node->owning_layer_id);
+ ScrollbarAnimationControllerForElementId(scroll_node->element_id);
if (animation_controller)
animation_controller->WillUpdateScroll();
@@ -3302,8 +3362,9 @@ InputHandlerScrollResult LayerTreeHostImpl::ScrollBy(
DistributeScrollDelta(scroll_state);
- active_tree_->SetCurrentlyScrollingNode(
- scroll_state->current_native_scrolling_node());
+ ScrollNode* current_scrolling_node =
+ scroll_state->current_native_scrolling_node();
+ active_tree_->SetCurrentlyScrollingNode(current_scrolling_node);
did_lock_scrolling_layer_ =
scroll_state->delta_consumed_for_scroll_sequence();
@@ -3311,6 +3372,8 @@ InputHandlerScrollResult LayerTreeHostImpl::ScrollBy(
bool did_scroll_y = scroll_state->caused_scroll_y();
bool did_scroll_content = did_scroll_x || did_scroll_y;
if (did_scroll_content) {
+ ShowScrollbarsForImplScroll(current_scrolling_node->element_id);
+
// If we are scrolling with an active scroll handler, forward latency
// tracking information to the main thread so the delay introduced by the
// handler is accounted for.
@@ -3371,6 +3434,7 @@ void LayerTreeHostImpl::SetSynchronousInputHandlerRootScrollOffset(
if (!changed)
return;
+ ShowScrollbarsForImplScroll(OuterViewportScrollLayer()->element_id());
client_->SetNeedsCommitOnImplThread();
// After applying the synchronous input handler's scroll offset, tell it what
// we ended up with.
@@ -3409,38 +3473,24 @@ InputHandler::ScrollStatus LayerTreeHostImpl::FlingScrollBegin() {
return scroll_status;
}
-float LayerTreeHostImpl::DeviceSpaceDistanceToLayer(
- const gfx::PointF& device_viewport_point,
- LayerImpl* layer_impl) {
- if (!layer_impl)
- return std::numeric_limits<float>::max();
-
- gfx::Rect layer_impl_bounds(layer_impl->bounds());
-
- gfx::RectF device_viewport_layer_impl_bounds = MathUtil::MapClippedRect(
- layer_impl->ScreenSpaceTransform(), gfx::RectF(layer_impl_bounds));
-
- return device_viewport_layer_impl_bounds.ManhattanDistanceToPoint(
- device_viewport_point);
-}
-
void LayerTreeHostImpl::MouseDown() {
ScrollbarAnimationController* animation_controller =
- ScrollbarAnimationControllerForId(scroll_layer_id_mouse_currently_over_);
+ ScrollbarAnimationControllerForElementId(
+ scroll_element_id_mouse_currently_over_);
if (animation_controller) {
animation_controller->DidMouseDown();
- scroll_layer_id_mouse_currently_captured_ =
- scroll_layer_id_mouse_currently_over_;
+ scroll_element_id_mouse_currently_captured_ =
+ scroll_element_id_mouse_currently_over_;
}
}
void LayerTreeHostImpl::MouseUp() {
- if (scroll_layer_id_mouse_currently_captured_ != Layer::INVALID_ID) {
+ if (scroll_element_id_mouse_currently_captured_) {
ScrollbarAnimationController* animation_controller =
- ScrollbarAnimationControllerForId(
- scroll_layer_id_mouse_currently_captured_);
+ ScrollbarAnimationControllerForElementId(
+ scroll_element_id_mouse_currently_captured_);
- scroll_layer_id_mouse_currently_captured_ = Layer::INVALID_ID;
+ scroll_element_id_mouse_currently_captured_ = ElementId();
if (animation_controller)
animation_controller->DidMouseUp();
@@ -3455,52 +3505,48 @@ void LayerTreeHostImpl::MouseMoveAt(const gfx::Point& viewport_point) {
// Check if mouse is over a scrollbar or not.
// TODO(sahel): get rid of this extera checking when
- // FindScrollLayerForDeviceViewportPoint finds the proper layer for
- // scrolling on main thread when mouse is over scrollbar as well.
- int new_id = Layer::INVALID_ID;
+ // FindScrollNodeForDeviceViewportPoint finds the proper node for scrolling on
+ // the main thread when the mouse is over a scrollbar as well.
+ ElementId scroll_element_id;
if (layer_impl && layer_impl->ToScrollbarLayer())
- new_id = layer_impl->ToScrollbarLayer()->ScrollLayerId();
- if (new_id == Layer::INVALID_ID) {
+ scroll_element_id = layer_impl->ToScrollbarLayer()->scroll_element_id();
+ if (!scroll_element_id) {
bool scroll_on_main_thread = false;
uint32_t main_thread_scrolling_reasons;
- LayerImpl* scroll_layer_impl = FindScrollLayerForDeviceViewportPoint(
+ auto* scroll_node = FindScrollNodeForDeviceViewportPoint(
device_viewport_point, InputHandler::TOUCHSCREEN, layer_impl,
&scroll_on_main_thread, &main_thread_scrolling_reasons);
+ if (scroll_node)
+ scroll_element_id = scroll_node->element_id;
// Scrollbars for the viewport are registered with the outer viewport layer.
- if (scroll_layer_impl == InnerViewportScrollLayer())
- scroll_layer_impl = OuterViewportScrollLayer();
-
- new_id = scroll_layer_impl ? scroll_layer_impl->id() : Layer::INVALID_ID;
+ if (InnerViewportScrollLayer() && OuterViewportScrollLayer() &&
+ scroll_element_id == InnerViewportScrollLayer()->element_id())
+ scroll_element_id = OuterViewportScrollLayer()->element_id();
}
- if (new_id != scroll_layer_id_mouse_currently_over_) {
+ if (scroll_element_id != scroll_element_id_mouse_currently_over_) {
ScrollbarAnimationController* old_animation_controller =
- ScrollbarAnimationControllerForId(
- scroll_layer_id_mouse_currently_over_);
+ ScrollbarAnimationControllerForElementId(
+ scroll_element_id_mouse_currently_over_);
if (old_animation_controller) {
old_animation_controller->DidMouseLeave();
}
- scroll_layer_id_mouse_currently_over_ = new_id;
+ scroll_element_id_mouse_currently_over_ = scroll_element_id;
}
ScrollbarAnimationController* new_animation_controller =
- ScrollbarAnimationControllerForId(new_id);
+ ScrollbarAnimationControllerForElementId(scroll_element_id);
if (!new_animation_controller)
return;
- for (ScrollbarLayerImplBase* scrollbar : ScrollbarsFor(new_id)) {
- new_animation_controller->DidMouseMoveNear(
- scrollbar->orientation(),
- DeviceSpaceDistanceToLayer(device_viewport_point, scrollbar) /
- active_tree_->device_scale_factor());
- }
+ new_animation_controller->DidMouseMove(device_viewport_point);
}
void LayerTreeHostImpl::MouseLeave() {
for (auto& pair : scrollbar_animation_controllers_)
pair.second->DidMouseLeave();
- scroll_layer_id_mouse_currently_over_ = Layer::INVALID_ID;
+ scroll_element_id_mouse_currently_over_ = ElementId();
}
void LayerTreeHostImpl::PinchGestureBegin() {
@@ -3569,8 +3615,9 @@ static void CollectScrollDeltas(ScrollAndScaleSet* scroll_info,
static void CollectScrollbarUpdates(
ScrollAndScaleSet* scroll_info,
- std::unordered_map<int, std::unique_ptr<ScrollbarAnimationController>>*
- controllers) {
+ std::unordered_map<ElementId,
+ std::unique_ptr<ScrollbarAnimationController>,
+ ElementIdHash>* controllers) {
scroll_info->scrollbars.reserve(controllers->size());
for (auto& pair : *controllers) {
scroll_info->scrollbars.push_back(LayerTreeHostCommon::ScrollbarsUpdateInfo(
@@ -3600,7 +3647,7 @@ std::unique_ptr<ScrollAndScaleSet> LayerTreeHostImpl::ProcessScrollDeltas() {
}
void LayerTreeHostImpl::SetFullViewportDamage() {
- SetViewportDamage(gfx::Rect(DrawViewportSize()));
+ SetViewportDamage(gfx::Rect(DeviceViewport().size()));
}
bool LayerTreeHostImpl::AnimatePageScale(base::TimeTicks monotonic_time) {
@@ -3714,29 +3761,30 @@ std::string LayerTreeHostImpl::LayerTreeAsJson() const {
}
void LayerTreeHostImpl::RegisterScrollbarAnimationController(
- int scroll_layer_id) {
- if (settings().scrollbar_animator == LayerTreeSettings::NO_ANIMATOR)
- return;
- if (ScrollbarAnimationControllerForId(scroll_layer_id))
+ ElementId scroll_element_id,
+ float scrollbar_opacity) {
+ if (ScrollbarAnimationControllerForElementId(scroll_element_id))
return;
- scrollbar_animation_controllers_[scroll_layer_id] =
- active_tree_->CreateScrollbarAnimationController(scroll_layer_id);
+
+ scrollbar_animation_controllers_[scroll_element_id] =
+ active_tree_->CreateScrollbarAnimationController(scroll_element_id,
+ scrollbar_opacity);
}
void LayerTreeHostImpl::UnregisterScrollbarAnimationController(
- int scroll_layer_id) {
- scrollbar_animation_controllers_.erase(scroll_layer_id);
+ ElementId scroll_element_id) {
+ scrollbar_animation_controllers_.erase(scroll_element_id);
}
ScrollbarAnimationController*
-LayerTreeHostImpl::ScrollbarAnimationControllerForId(
- int scroll_layer_id) const {
+LayerTreeHostImpl::ScrollbarAnimationControllerForElementId(
+ ElementId scroll_element_id) const {
// The viewport layers have only one set of scrollbars and their controller
// is registered with the outer viewport.
if (InnerViewportScrollLayer() && OuterViewportScrollLayer() &&
- scroll_layer_id == InnerViewportScrollLayer()->id())
- scroll_layer_id = OuterViewportScrollLayer()->id();
- auto i = scrollbar_animation_controllers_.find(scroll_layer_id);
+ scroll_element_id == InnerViewportScrollLayer()->element_id())
+ scroll_element_id = OuterViewportScrollLayer()->element_id();
+ auto i = scrollbar_animation_controllers_.find(scroll_element_id);
if (i == scrollbar_animation_controllers_.end())
return nullptr;
return i->second.get();
@@ -3761,8 +3809,8 @@ void LayerTreeHostImpl::SetNeedsRedrawForScrollbarAnimation() {
SetNeedsRedraw();
}
-ScrollbarSet LayerTreeHostImpl::ScrollbarsFor(int scroll_layer_id) const {
- return active_tree_->ScrollbarsFor(scroll_layer_id);
+ScrollbarSet LayerTreeHostImpl::ScrollbarsFor(ElementId id) const {
+ return active_tree_->ScrollbarsFor(id);
}
void LayerTreeHostImpl::AddVideoFrameController(
@@ -3920,9 +3968,7 @@ void LayerTreeHostImpl::CreateUIResource(UIResourceId uid,
gfx::ColorSpace::CreateSRGB());
if (!scaled) {
- AutoLockUIResourceBitmap bitmap_lock(bitmap);
- auto* pixels = bitmap_lock.GetPixels();
- resource_provider_->CopyToResource(id, pixels, source_size);
+ resource_provider_->CopyToResource(id, bitmap.GetPixels(), source_size);
} else {
// Only support auto-resizing for N32 textures (since this is primarily for
// scrollbars). Users of other types need to ensure they are not too big.
@@ -3939,10 +3985,9 @@ void LayerTreeHostImpl::CreateUIResource(UIResourceId uid,
source_size.width(), source_size.height(), kPremul_SkAlphaType);
int row_bytes = source_size.width() * 4;
- AutoLockUIResourceBitmap bitmap_lock(bitmap);
SkBitmap source_bitmap;
source_bitmap.setInfo(info, row_bytes);
- source_bitmap.setPixels(const_cast<uint8_t*>(bitmap_lock.GetPixels()));
+ source_bitmap.setPixels(const_cast<uint8_t*>(bitmap.GetPixels()));
// This applies the scale to draw the |bitmap| into |scaled_bitmap|.
SkBitmap scaled_bitmap;
@@ -3956,7 +4001,6 @@ void LayerTreeHostImpl::CreateUIResource(UIResourceId uid,
scaled_canvas.clear(SK_ColorTRANSPARENT);
scaled_canvas.drawBitmap(source_bitmap, 0, 0);
- SkAutoLockPixels scaled_bitmap_lock(scaled_bitmap);
auto* pixels = static_cast<uint8_t*>(scaled_bitmap.getPixels());
resource_provider_->CopyToResource(id, pixels, upload_size);
}
@@ -4172,6 +4216,7 @@ void LayerTreeHostImpl::SetElementScrollOffsetMutated(
const gfx::ScrollOffset& scroll_offset) {
if (list_type == ElementListType::ACTIVE) {
SetTreeLayerScrollOffsetMutated(element_id, active_tree(), scroll_offset);
+ ShowScrollbarsForImplScroll(element_id);
} else {
SetTreeLayerScrollOffsetMutated(element_id, pending_tree(), scroll_offset);
SetTreeLayerScrollOffsetMutated(element_id, recycle_tree(), scroll_offset);
@@ -4213,12 +4258,6 @@ void LayerTreeHostImpl::ElementIsAnimatingChanged(
list_type);
property_trees->transform_tree.set_needs_update(true);
tree->set_needs_update_draw_properties();
- // TODO(crbug.com/702777):
- // was_ever_ready_since_last_transform_animation should not live on
- // layers.
- if (LayerImpl* layer = tree->LayerByElementId(element_id)) {
- layer->set_was_ever_ready_since_last_transform_animation(false);
- }
}
}
break;
@@ -4324,4 +4363,12 @@ void LayerTreeHostImpl::UpdateScrollSourceInfo(bool is_wheel_scroll) {
has_scrolled_by_touch_ = true;
}
+void LayerTreeHostImpl::ShowScrollbarsForImplScroll(ElementId element_id) {
+ if (!element_id)
+ return;
+ if (ScrollbarAnimationController* animation_controller =
+ ScrollbarAnimationControllerForElementId(element_id))
+ animation_controller->DidScrollUpdate();
+}
+
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_impl.h b/chromium/cc/trees/layer_tree_host_impl.h
index 0b72dc47333..b8553cb323b 100644
--- a/chromium/cc/trees/layer_tree_host_impl.h
+++ b/chromium/cc/trees/layer_tree_host_impl.h
@@ -16,6 +16,7 @@
#include "base/callback.h"
#include "base/macros.h"
+#include "base/sequenced_task_runner.h"
#include "base/time/time.h"
#include "cc/base/synced_property.h"
#include "cc/benchmarks/micro_benchmark_controller_impl.h"
@@ -86,7 +87,11 @@ enum class GpuRasterizationStatus {
OFF_DEVICE,
OFF_VIEWPORT,
MSAA_CONTENT,
- OFF_CONTENT
+};
+
+enum class ImplThreadPhase {
+ IDLE,
+ INSIDE_IMPL_FRAME,
};
// LayerTreeHost->Proxy callback interface.
@@ -223,11 +228,11 @@ class CC_EXPORT LayerTreeHostImpl
~FrameData();
void AsValueInto(base::trace_event::TracedValue* value) const;
- std::vector<SurfaceId> embedded_surfaces;
+ std::vector<SurfaceId> activation_dependencies;
std::vector<gfx::Rect> occluding_screen_space_rects;
std::vector<gfx::Rect> non_occluding_screen_space_rects;
RenderPassList render_passes;
- const LayerImplList* render_surface_layer_list;
+ const RenderSurfaceList* render_surface_list;
LayerImplList will_draw_layers;
bool has_no_damage;
bool may_contain_video;
@@ -322,20 +327,14 @@ class CC_EXPORT LayerTreeHostImpl
size_t SourceAnimationFrameNumberForTesting() const;
- void RegisterScrollbarAnimationController(int scroll_layer_id);
- void UnregisterScrollbarAnimationController(int scroll_layer_id);
- ScrollbarAnimationController* ScrollbarAnimationControllerForId(
- int scroll_layer_id) const;
+ void RegisterScrollbarAnimationController(ElementId scroll_element_id,
+ float initial_opacity);
+ void UnregisterScrollbarAnimationController(ElementId scroll_element_id);
+ ScrollbarAnimationController* ScrollbarAnimationControllerForElementId(
+ ElementId scroll_element_id) const;
DrawMode GetDrawMode() const;
- // Viewport size in draw space: this size is in physical pixels and is used
- // for draw properties, tilings, quads and render passes.
- gfx::Size DrawViewportSize() const;
-
- // Viewport rect in view space used for tiling prioritization.
- const gfx::Rect ViewportRectForTilePriority() const;
-
// TileManagerClient implementation.
void NotifyReadyToActivate() override;
void NotifyReadyToDraw() override;
@@ -355,7 +354,7 @@ class CC_EXPORT LayerTreeHostImpl
base::TimeDelta delay) override;
void SetNeedsAnimateForScrollbarAnimation() override;
void SetNeedsRedrawForScrollbarAnimation() override;
- ScrollbarSet ScrollbarsFor(int scroll_layer_id) const override;
+ ScrollbarSet ScrollbarsFor(ElementId scroll_element_id) const override;
void DidChangeScrollbarVisibility() override;
// VideoBeginFrameSource implementation.
@@ -416,6 +415,7 @@ class CC_EXPORT LayerTreeHostImpl
virtual void WillBeginImplFrame(const BeginFrameArgs& args);
virtual void DidFinishImplFrame();
+ void DidNotProduceFrame(const BeginFrameAck& ack);
void DidModifyTilePriorities();
LayerTreeImpl* active_tree() { return active_tree_.get(); }
@@ -538,9 +538,13 @@ class CC_EXPORT LayerTreeHostImpl
void ScheduleMicroBenchmark(std::unique_ptr<MicroBenchmarkImpl> benchmark);
CompositorFrameMetadata MakeCompositorFrameMetadata() const;
+
// Viewport rectangle and clip in device space. These rects are used to
// prioritize raster and determine what is submitted in a CompositorFrame.
gfx::Rect DeviceViewport() const;
+ // Viewport rect to be used for tiling prioritization instead of the
+ // DeviceViewport().
+ const gfx::Rect ViewportRectForTilePriority() const;
// When a SwapPromiseMonitor is created on the impl thread, it calls
// InsertSwapPromiseMonitor() to register itself with LayerTreeHostImpl.
@@ -665,9 +669,6 @@ class CC_EXPORT LayerTreeHostImpl
bool AnimateScrollbars(base::TimeTicks monotonic_time);
bool AnimateBrowserControls(base::TimeTicks monotonic_time);
- void TrackDamageForAllSurfaces(
- const LayerImplList& render_surface_layer_list);
-
void UpdateTileManagerMemoryPolicy(const ManagedMemoryPolicy& policy);
// This function should only be called from PrepareToDraw, as DidDrawAllLayers
@@ -677,14 +678,12 @@ class CC_EXPORT LayerTreeHostImpl
void ClearCurrentlyScrollingNode();
- LayerImpl* FindScrollLayerForDeviceViewportPoint(
+ ScrollNode* FindScrollNodeForDeviceViewportPoint(
const gfx::PointF& device_viewport_point,
InputHandler::ScrollInputType type,
LayerImpl* layer_hit_by_point,
bool* scroll_on_main_thread,
uint32_t* main_thread_scrolling_reason) const;
- float DeviceSpaceDistanceToLayer(const gfx::PointF& device_viewport_point,
- LayerImpl* layer_impl);
void StartScrollbarFadeRecursive(LayerImpl* layer);
void SetManagedMemoryPolicy(const ManagedMemoryPolicy& policy);
@@ -713,6 +712,11 @@ class CC_EXPORT LayerTreeHostImpl
void UpdateScrollSourceInfo(bool is_wheel_scroll);
bool IsScrolledBy(LayerImpl* child, ScrollNode* ancestor);
+ void ShowScrollbarsForImplScroll(ElementId element_id);
+
+ // Copy any opacity values already in the active tree to the pending
+ // tree, because the active tree value always takes precedence for scrollbars.
+ void PushScrollbarOpacitiesFromActiveToPending();
using UIResourceMap = std::unordered_map<UIResourceId, UIResourceData>;
UIResourceMap ui_resource_map_;
@@ -763,8 +767,8 @@ class CC_EXPORT LayerTreeHostImpl
bool did_lock_scrolling_layer_;
bool wheel_scrolling_;
bool scroll_affects_scroll_handler_;
- int scroll_layer_id_mouse_currently_over_;
- int scroll_layer_id_mouse_currently_captured_;
+ ElementId scroll_element_id_mouse_currently_over_;
+ ElementId scroll_element_id_mouse_currently_captured_;
std::vector<std::unique_ptr<SwapPromise>>
swap_promises_for_main_thread_scroll_update_;
@@ -824,9 +828,11 @@ class CC_EXPORT LayerTreeHostImpl
std::unique_ptr<MutatorHost> mutator_host_;
std::set<VideoFrameController*> video_frame_controllers_;
- // Map from scroll layer ID to scrollbar animation controller.
+ // Map from scroll element ID to scrollbar animation controller.
// There is one animation controller per pair of overlay scrollbars.
- std::unordered_map<int, std::unique_ptr<ScrollbarAnimationController>>
+ std::unordered_map<ElementId,
+ std::unique_ptr<ScrollbarAnimationController>,
+ ElementIdHash>
scrollbar_animation_controllers_;
RenderingStatsInstrumentation* rendering_stats_instrumentation_;
@@ -872,6 +878,8 @@ class CC_EXPORT LayerTreeHostImpl
bool touchpad_and_wheel_scroll_latching_enabled_;
+ ImplThreadPhase impl_thread_phase_;
+
DISALLOW_COPY_AND_ASSIGN(LayerTreeHostImpl);
};
diff --git a/chromium/cc/trees/layer_tree_host_impl_unittest.cc b/chromium/cc/trees/layer_tree_host_impl_unittest.cc
index a52bdf7996c..e8eba4fd251 100644
--- a/chromium/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/chromium/cc/trees/layer_tree_host_impl_unittest.cc
@@ -15,6 +15,7 @@
#include "base/location.h"
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
+#include "base/test/histogram_tester.h"
#include "base/threading/thread_task_runner_handle.h"
#include "cc/animation/animation_host.h"
#include "cc/animation/animation_id_provider.h"
@@ -127,6 +128,7 @@ class LayerTreeHostImplTest : public testing::Test,
LayerTreeSettings DefaultSettings() {
LayerTreeSettings settings;
+ settings.enable_surface_synchronization = true;
settings.minimum_occlusion_tracking_size = gfx::Size();
settings.renderer_settings.texture_id_allocation_chunk_size = 1;
settings.renderer_settings.buffer_to_texture_target_map =
@@ -305,6 +307,10 @@ class LayerTreeHostImplTest : public testing::Test,
LayerImpl* CreateScrollAndContentsLayers(LayerTreeImpl* layer_tree_impl,
const gfx::Size& content_size) {
+ // Clear any existing viewport layers that were setup so this function can
+ // be called multiple times.
+ layer_tree_impl->ClearViewportLayers();
+
// Create both an inner viewport scroll layer and an outer viewport scroll
// layer. The MaxScrollOffset of the outer viewport scroll layer will be
// 0x0, so the scrolls will be applied directly to the inner viewport.
@@ -376,9 +382,13 @@ class LayerTreeHostImplTest : public testing::Test,
layer_tree_impl->SetRootLayerForTesting(std::move(root));
layer_tree_impl->BuildPropertyTreesForTesting();
- layer_tree_impl->SetViewportLayersFromIds(
- Layer::INVALID_ID, kPageScaleLayerId, kInnerViewportScrollLayerId,
- kOuterViewportScrollLayerId);
+ LayerTreeImpl::ViewportLayerIds viewport_ids;
+ viewport_ids.page_scale = kPageScaleLayerId;
+ viewport_ids.inner_viewport_container = kInnerViewportClipLayerId;
+ viewport_ids.outer_viewport_container = kOuterViewportClipLayerId;
+ viewport_ids.inner_viewport_scroll = kInnerViewportScrollLayerId;
+ viewport_ids.outer_viewport_scroll = kOuterViewportScrollLayerId;
+ layer_tree_impl->SetViewportLayersFromIds(viewport_ids);
layer_tree_impl->DidBecomeActive();
return layer_tree_impl->InnerViewportScrollLayer();
@@ -754,6 +764,66 @@ TEST_F(LayerTreeHostImplTest, ScrollDeltaRepeatedScrolls) {
scroll_delta + scroll_delta2));
}
+TEST_F(LayerTreeHostImplTest, ScrollerSizeOfCCScrollingHistogramRecordingTest) {
+ const gfx::Size content_size(800, 600);
+ const gfx::Size viewport_size(500, 500);
+ CreateBasicVirtualViewportLayers(viewport_size, content_size);
+
+ LayerImpl* outer_viewport_scroll_layer =
+ host_impl_->active_tree()->OuterViewportScrollLayer();
+ int id = outer_viewport_scroll_layer->id();
+ std::unique_ptr<LayerImpl> child =
+ LayerImpl::Create(host_impl_->active_tree(), id + 2);
+ std::unique_ptr<LayerImpl> child_clip =
+ LayerImpl::Create(host_impl_->active_tree(), id + 3);
+
+ child_clip->SetBounds(gfx::Size(100, 100));
+
+ child->SetScrollClipLayer(child_clip->id());
+ child->SetElementId(LayerIdToElementIdForTesting(child->id()));
+ child->SetBounds(gfx::Size(100, 400));
+ child->SetPosition(gfx::PointF());
+ child->SetDrawsContent(true);
+
+ child_clip->test_properties()->AddChild(std::move(child));
+ outer_viewport_scroll_layer->test_properties()->AddChild(
+ std::move(child_clip));
+ host_impl_->active_tree()->BuildPropertyTreesForTesting();
+
+ base::HistogramTester histogram_tester;
+
+ // Test touch scroll.
+ InputHandler::ScrollStatus status = host_impl_->ScrollBegin(
+ BeginState(gfx::Point()).get(), InputHandler::TOUCHSCREEN);
+ EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread);
+ EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain,
+ status.main_thread_scrolling_reasons);
+ host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get());
+ host_impl_->ScrollEnd(EndState().get());
+
+ histogram_tester.ExpectBucketCount("Event.Scroll.ScrollerSize.OnScroll_Touch",
+ 10000, 1);
+ histogram_tester.ExpectTotalCount("Event.Scroll.ScrollerSize.OnScroll_Touch",
+ 1);
+
+ // Scrolling root layer doesn't add to count.
+ host_impl_->ScrollBegin(BeginState(gfx::Point(450, 450)).get(),
+ InputHandler::TOUCHSCREEN);
+ host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get());
+ host_impl_->ScrollEnd(EndState().get());
+ histogram_tester.ExpectTotalCount("Event.Scroll.ScrollerSize.OnScroll_Touch",
+ 1);
+
+ // Test wheel scroll.
+ host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), InputHandler::WHEEL);
+ host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get());
+ host_impl_->ScrollEnd(EndState().get());
+ histogram_tester.ExpectBucketCount("Event.Scroll.ScrollerSize.OnScroll_Wheel",
+ 10000, 1);
+ histogram_tester.ExpectTotalCount("Event.Scroll.ScrollerSize.OnScroll_Wheel",
+ 1);
+}
+
TEST_F(LayerTreeHostImplTest, ScrollRootCallsCommitAndRedraw) {
SetupScrollAndContentsLayers(gfx::Size(100, 100));
host_impl_->active_tree()->BuildPropertyTreesForTesting();
@@ -1041,7 +1111,7 @@ TEST_F(LayerTreeHostImplTest, ScrollWithOverlappingNonScrollableLayer) {
false, true);
scrollbar->SetBounds(scrollbar_size);
scrollbar->SetPosition(gfx::PointF(345, 0));
- scrollbar->SetScrollLayerId(scroll->id());
+ scrollbar->SetScrollElementId(scroll->element_id());
scrollbar->SetDrawsContent(true);
scrollbar->test_properties()->opacity = 1.f;
@@ -1113,7 +1183,7 @@ TEST_F(LayerTreeHostImplTest, ScrolledOverlappingDrawnScrollbarLayer) {
false, true);
drawn_scrollbar->SetBounds(scrollbar_size);
drawn_scrollbar->SetPosition(gfx::PointF(345, 0));
- drawn_scrollbar->SetScrollLayerId(scroll->id());
+ drawn_scrollbar->SetScrollElementId(scroll->element_id());
drawn_scrollbar->SetDrawsContent(true);
drawn_scrollbar->test_properties()->opacity = 1.f;
@@ -1559,7 +1629,7 @@ TEST_F(LayerTreeHostImplTest, AnimationSchedulingCommitToActiveTree) {
// Set up the property trees so that UpdateDrawProperties will work in
// CommitComplete below.
- LayerImplList list;
+ RenderSurfaceList list;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
root, gfx::Size(50, 50), &list);
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
@@ -1657,91 +1727,6 @@ class MissingTilesLayer : public LayerImpl {
bool has_missing_tiles_;
};
-TEST_F(LayerTreeHostImplTest, AnimationMarksLayerNotReady) {
- host_impl_->SetViewportSize(gfx::Size(50, 50));
-
- host_impl_->active_tree()->SetRootLayerForTesting(
- LayerImpl::Create(host_impl_->active_tree(), 1));
- LayerImpl* root = *host_impl_->active_tree()->begin();
- root->SetBounds(gfx::Size(50, 50));
-
- root->test_properties()->AddChild(std::unique_ptr<MissingTilesLayer>(
- new MissingTilesLayer(host_impl_->active_tree(), 2)));
- MissingTilesLayer* child =
- static_cast<MissingTilesLayer*>(root->test_properties()->children[0]);
- child->SetBounds(gfx::Size(10, 10));
- child->draw_properties().visible_layer_rect = gfx::Rect(10, 10);
- child->SetDrawsContent(true);
-
- host_impl_->active_tree()->SetElementIdsForTesting();
-
- EXPECT_TRUE(child->was_ever_ready_since_last_transform_animation());
-
- // Add a translate from 6,7 to 8,9.
- TransformOperations start;
- start.AppendTranslate(6.f, 7.f, 0.f);
- TransformOperations end;
- end.AppendTranslate(8.f, 9.f, 0.f);
- int animation_id = AddAnimatedTransformToElementWithPlayer(
- child->element_id(), timeline(), 4.0, start, end);
- host_impl_->active_tree()->BuildPropertyTreesForTesting();
-
- base::TimeTicks now = base::TimeTicks::Now();
- host_impl_->WillBeginImplFrame(
- CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 2, now));
-
- host_impl_->ActivateAnimations();
- host_impl_->Animate();
-
- EXPECT_FALSE(child->was_ever_ready_since_last_transform_animation());
-
- host_impl_->ResetRequiresHighResToDraw();
-
- // Child layer has an animating transform but missing tiles.
- TestFrameData frame;
- DrawResult result = host_impl_->PrepareToDraw(&frame);
- EXPECT_EQ(DRAW_ABORTED_CHECKERBOARD_ANIMATIONS, result);
- host_impl_->DidDrawAllLayers(frame);
-
- child->set_has_missing_tiles(false);
-
- // Child layer has an animating and no missing tiles.
- result = host_impl_->PrepareToDraw(&frame);
- EXPECT_EQ(DRAW_SUCCESS, result);
- EXPECT_TRUE(child->was_ever_ready_since_last_transform_animation());
- host_impl_->DidDrawAllLayers(frame);
-
- // Remove the animation.
- child->set_has_missing_tiles(true);
- RemoveAnimationFromElementWithExistingPlayer(child->element_id(), timeline(),
- animation_id);
- child->draw_properties().screen_space_transform_is_animating = false;
-
- // Child layer doesn't have an animation, but was never ready since the last
- // time it animated (and has missing tiles).
- result = host_impl_->PrepareToDraw(&frame);
- EXPECT_EQ(DRAW_ABORTED_CHECKERBOARD_ANIMATIONS, result);
- EXPECT_FALSE(child->was_ever_ready_since_last_transform_animation());
- host_impl_->DidDrawAllLayers(frame);
-
- child->set_has_missing_tiles(false);
-
- // Child layer doesn't have an animation and all tiles are ready.
- result = host_impl_->PrepareToDraw(&frame);
- EXPECT_EQ(DRAW_SUCCESS, result);
- EXPECT_TRUE(child->was_ever_ready_since_last_transform_animation());
- host_impl_->DidDrawAllLayers(frame);
-
- child->set_has_missing_tiles(true);
-
- // Child layer doesn't have an animation, and was ready at least once since
- // the last time it animated.
- result = host_impl_->PrepareToDraw(&frame);
- EXPECT_EQ(DRAW_SUCCESS, result);
- EXPECT_TRUE(child->was_ever_ready_since_last_transform_animation());
- host_impl_->DidDrawAllLayers(frame);
-}
-
TEST_F(LayerTreeHostImplTest, ImplPinchZoom) {
LayerImpl* scroll_layer = SetupScrollAndContentsLayers(gfx::Size(100, 100));
host_impl_->active_tree()->BuildPropertyTreesForTesting();
@@ -2769,7 +2754,7 @@ TEST_F(LayerTreeHostImplTest, PageScaleAnimationCompletedNotification) {
host_impl_->DidFinishImplFrame();
}
-TEST_F(LayerTreeHostImplTest, MaxScrollOffsetAffectedByBoundsDelta) {
+TEST_F(LayerTreeHostImplTest, MaxScrollOffsetAffectedByViewportBoundsDelta) {
SetupScrollAndContentsLayers(gfx::Size(100, 100));
host_impl_->SetViewportSize(gfx::Size(50, 50));
host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 0.5f, 4.f);
@@ -2782,17 +2767,17 @@ TEST_F(LayerTreeHostImplTest, MaxScrollOffsetAffectedByBoundsDelta) {
DCHECK(inner_container);
EXPECT_EQ(gfx::ScrollOffset(50, 50), inner_scroll->MaxScrollOffset());
- inner_container->SetBoundsDelta(gfx::Vector2dF(15.f, 15.f));
- inner_scroll->SetBoundsDelta(gfx::Vector2dF(7.f, 7.f));
+ inner_container->SetViewportBoundsDelta(gfx::Vector2dF(15.f, 15.f));
+ inner_scroll->SetViewportBoundsDelta(gfx::Vector2dF(7.f, 7.f));
EXPECT_EQ(gfx::ScrollOffset(42, 42), inner_scroll->MaxScrollOffset());
- inner_container->SetBoundsDelta(gfx::Vector2dF());
- inner_scroll->SetBoundsDelta(gfx::Vector2dF());
+ inner_container->SetViewportBoundsDelta(gfx::Vector2dF());
+ inner_scroll->SetViewportBoundsDelta(gfx::Vector2dF());
inner_scroll->SetBounds(gfx::Size());
host_impl_->active_tree()->BuildPropertyTreesForTesting();
DrawFrame();
- inner_scroll->SetBoundsDelta(gfx::Vector2dF(60.f, 60.f));
+ inner_scroll->SetViewportBoundsDelta(gfx::Vector2dF(60.f, 60.f));
EXPECT_EQ(gfx::ScrollOffset(10, 10), inner_scroll->MaxScrollOffset());
}
@@ -2856,13 +2841,14 @@ class LayerTreeHostImplTestScrollbarAnimation : public LayerTreeHostImplTest {
LayerImpl* scroll = host_impl_->active_tree()->OuterViewportScrollLayer();
LayerImpl* root = host_impl_->active_tree()->InnerViewportContainerLayer();
- scrollbar->SetScrollLayerId(scroll->id());
+ scrollbar->SetScrollElementId(scroll->element_id());
root->test_properties()->AddChild(std::move(scrollbar));
host_impl_->active_tree()->BuildPropertyTreesForTesting();
host_impl_->active_tree()->DidBecomeActive();
+ host_impl_->active_tree()->HandleScrollbarShowRequestsFromMain();
DrawFrame();
- // SetScrollLayerId will initialize the scrollbar which will cause it to
+ // SetScrollElementId will initialize the scrollbar which will cause it to
// show and request a redraw.
did_request_redraw_ = false;
}
@@ -2871,8 +2857,6 @@ class LayerTreeHostImplTestScrollbarAnimation : public LayerTreeHostImplTest {
LayerTreeSettings settings = DefaultSettings();
settings.scrollbar_animator = animator;
settings.scrollbar_fade_delay = base::TimeDelta::FromMilliseconds(20);
- settings.scrollbar_fade_out_resize_delay =
- base::TimeDelta::FromMilliseconds(20);
settings.scrollbar_fade_duration = base::TimeDelta::FromMilliseconds(20);
// If no animator is set, scrollbar won't show and no animation is expected.
@@ -2882,7 +2866,8 @@ class LayerTreeHostImplTestScrollbarAnimation : public LayerTreeHostImplTest {
base::TimeTicks fake_now = base::TimeTicks::Now();
- if (expecting_animations) {
+ // Android Overlay Scrollbar does not have a initial show and fade out.
+ if (animator == LayerTreeSettings::AURA_OVERLAY) {
// A task will be posted to fade the initial scrollbar.
EXPECT_FALSE(did_request_next_frame_);
EXPECT_FALSE(did_request_redraw_);
@@ -2995,8 +2980,8 @@ class LayerTreeHostImplTestScrollbarAnimation : public LayerTreeHostImplTest {
host_impl_->DidFinishImplFrame();
}
- // Setting the scroll offset outside a scroll should also cause the
- // scrollbar to appear and to schedule a scrollbar animation.
+ // Setting the scroll offset outside a scroll should not cause the
+ // scrollbar to appear or schedule a scrollbar animation.
if (host_impl_->active_tree()
->property_trees()
->scroll_tree.UpdateScrollOffsetBaseForTesting(
@@ -3006,57 +2991,9 @@ class LayerTreeHostImplTestScrollbarAnimation : public LayerTreeHostImplTest {
host_impl_->InnerViewportScrollLayer()->id());
EXPECT_FALSE(did_request_next_frame_);
EXPECT_FALSE(did_request_redraw_);
- if (expecting_animations) {
- EXPECT_EQ(base::TimeDelta::FromMilliseconds(20),
- requested_animation_delay_);
- EXPECT_FALSE(animation_task_.Equals(base::Closure()));
- requested_animation_delay_ = base::TimeDelta();
- animation_task_ = base::Closure();
- } else {
- EXPECT_EQ(base::TimeDelta(), requested_animation_delay_);
- EXPECT_TRUE(animation_task_.Equals(base::Closure()));
- }
-
- if (expecting_animations) {
- // Scrolling should have stopped the animation, so we should not be
- // getting redraws.
- begin_frame_args =
- CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 5, fake_now);
- host_impl_->WillBeginImplFrame(begin_frame_args);
- host_impl_->Animate();
- EXPECT_FALSE(did_request_next_frame_);
- did_request_next_frame_ = false;
- EXPECT_FALSE(did_request_redraw_);
- did_request_redraw_ = false;
- host_impl_->DidFinishImplFrame();
- }
-
- // For Andrdoid, scrollbar animation is not triggered unnecessarily.
- // For Aura Overlay Scrollbar, scrollbar appears even if scroll offset did
- // not change.
- host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
- InputHandler::WHEEL);
- host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2dF(5, 0)).get());
- EXPECT_FALSE(did_request_next_frame_);
- EXPECT_TRUE(did_request_redraw_);
- did_request_redraw_ = false;
EXPECT_EQ(base::TimeDelta(), requested_animation_delay_);
EXPECT_TRUE(animation_task_.Equals(base::Closure()));
- host_impl_->ScrollEnd(EndState().get());
- EXPECT_FALSE(did_request_next_frame_);
- EXPECT_FALSE(did_request_redraw_);
- if (animator == LayerTreeSettings::AURA_OVERLAY) {
- EXPECT_EQ(base::TimeDelta::FromMilliseconds(20),
- requested_animation_delay_);
- EXPECT_FALSE(animation_task_.Equals(base::Closure()));
- requested_animation_delay_ = base::TimeDelta();
- animation_task_ = base::Closure();
- } else {
- EXPECT_EQ(base::TimeDelta(), requested_animation_delay_);
- EXPECT_TRUE(animation_task_.Equals(base::Closure()));
- }
-
// Changing page scale triggers scrollbar animation.
host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 1.f, 4.f);
host_impl_->active_tree()->SetPageScaleOnActiveTree(1.1f);
@@ -3109,7 +3046,9 @@ class LayerTreeHostImplTestScrollbarOpacity : public LayerTreeHostImplTest {
LayerImpl* scroll = host_impl_->pending_tree()->OuterViewportScrollLayer();
LayerImpl* container =
host_impl_->pending_tree()->InnerViewportContainerLayer();
- scrollbar->SetScrollLayerId(scroll->id());
+ scrollbar->SetScrollElementId(scroll->element_id());
+ scrollbar->SetBounds(gfx::Size(10, 100));
+ scrollbar->SetPosition(gfx::PointF(90, 0));
container->test_properties()->AddChild(std::move(scrollbar));
host_impl_->pending_tree()->PushPageScaleFromMainThread(1.f, 1.f, 1.f);
host_impl_->pending_tree()->BuildPropertyTreesForTesting();
@@ -3125,11 +3064,11 @@ class LayerTreeHostImplTestScrollbarOpacity : public LayerTreeHostImplTest {
active_tree_node->opacity);
if (expecting_animations) {
- host_impl_->ScrollbarAnimationControllerForId(scroll->id())
- ->DidMouseMoveNear(VERTICAL, 0);
+ host_impl_->ScrollbarAnimationControllerForElementId(scroll->element_id())
+ ->DidMouseMove(gfx::PointF(0, 90));
} else {
- EXPECT_EQ(nullptr,
- host_impl_->ScrollbarAnimationControllerForId(scroll->id()));
+ EXPECT_EQ(nullptr, host_impl_->ScrollbarAnimationControllerForElementId(
+ scroll->element_id()));
}
host_impl_->ScrollBegin(BeginState(gfx::Point()).get(),
InputHandler::WHEEL);
@@ -3149,9 +3088,6 @@ class LayerTreeHostImplTestScrollbarOpacity : public LayerTreeHostImplTest {
EffectNode* pending_tree_node =
host_impl_->pending_tree()->property_trees()->effect_tree.Node(
pending_scrollbar_layer->effect_tree_index());
- host_impl_->pending_tree()
- ->property_trees()
- ->always_use_active_tree_opacity_effect_ids.push_back(400);
if (expecting_animations) {
EXPECT_FLOAT_EQ(1.f, active_tree_node->opacity);
EXPECT_FLOAT_EQ(1.f, active_scrollbar_layer->Opacity());
@@ -3203,14 +3139,17 @@ TEST_F(LayerTreeHostImplTest, ScrollbarVisibilityChangeCausesRedrawAndCommit) {
LayerImpl* scroll = host_impl_->pending_tree()->OuterViewportScrollLayer();
LayerImpl* container =
host_impl_->pending_tree()->InnerViewportContainerLayer();
- scrollbar->SetScrollLayerId(scroll->id());
+ scrollbar->SetScrollElementId(scroll->element_id());
+ scrollbar->SetBounds(gfx::Size(10, 100));
+ scrollbar->SetPosition(gfx::PointF(90, 0));
container->test_properties()->AddChild(std::move(scrollbar));
host_impl_->pending_tree()->PushPageScaleFromMainThread(1.f, 1.f, 1.f);
host_impl_->pending_tree()->BuildPropertyTreesForTesting();
host_impl_->ActivateSyncTree();
ScrollbarAnimationController* scrollbar_controller =
- host_impl_->ScrollbarAnimationControllerForId(scroll->id());
+ host_impl_->ScrollbarAnimationControllerForElementId(
+ scroll->element_id());
// Scrollbars will flash shown but we should have a fade out animation
// queued. Run it and fade out the scrollbars.
@@ -3228,10 +3167,10 @@ TEST_F(LayerTreeHostImplTest, ScrollbarVisibilityChangeCausesRedrawAndCommit) {
}
// Move the mouse over the scrollbar region. This should post a delayed fade
- // in task. Execute it to show the scrollbars.
+ // in task. Execute it to fade in the scrollbars.
{
animation_task_ = base::Closure();
- scrollbar_controller->DidMouseMoveNear(VERTICAL, 0);
+ scrollbar_controller->DidMouseMove(gfx::PointF(90, 0));
ASSERT_FALSE(animation_task_.Equals(base::Closure()));
ASSERT_FALSE(animation_task_.IsCancelled());
}
@@ -3284,7 +3223,7 @@ TEST_F(LayerTreeHostImplTest, ScrollbarInnerLargerThanOuter) {
LayerImpl::Create(host_impl_->active_tree(), child_clip_id);
child->SetBounds(inner_viewport_size);
- horiz_scrollbar->SetScrollLayerId(root_scroll->id());
+ horiz_scrollbar->SetScrollElementId(root_scroll->element_id());
EXPECT_EQ(300, horiz_scrollbar->clip_layer_length());
}
@@ -3307,22 +3246,36 @@ TEST_F(LayerTreeHostImplTest, ScrollbarRegistration) {
const int child_scroll_id = 15;
CreateScrollAndContentsLayers(host_impl_->active_tree(), content_size);
- host_impl_->active_tree()->InnerViewportContainerLayer()->SetBounds(
- viewport_size);
+ LayerImpl* container =
+ host_impl_->active_tree()->InnerViewportContainerLayer();
+ container->SetBounds(viewport_size);
LayerImpl* root_scroll =
host_impl_->active_tree()->OuterViewportScrollLayer();
- std::unique_ptr<SolidColorScrollbarLayerImpl> vert_1_scrollbar =
- SolidColorScrollbarLayerImpl::Create(host_impl_->active_tree(), vert_1_id,
- VERTICAL, 5, 5, true, true);
- std::unique_ptr<SolidColorScrollbarLayerImpl> horiz_1_scrollbar =
- SolidColorScrollbarLayerImpl::Create(
- host_impl_->active_tree(), horiz_1_id, HORIZONTAL, 5, 5, true, true);
- std::unique_ptr<SolidColorScrollbarLayerImpl> vert_2_scrollbar =
- SolidColorScrollbarLayerImpl::Create(host_impl_->active_tree(), vert_2_id,
- VERTICAL, 5, 5, true, true);
- std::unique_ptr<SolidColorScrollbarLayerImpl> horiz_2_scrollbar =
- SolidColorScrollbarLayerImpl::Create(
- host_impl_->active_tree(), horiz_2_id, HORIZONTAL, 5, 5, true, true);
+
+ container->test_properties()->AddChild(SolidColorScrollbarLayerImpl::Create(
+ host_impl_->active_tree(), vert_1_id, VERTICAL, 5, 5, true, true));
+ SolidColorScrollbarLayerImpl* vert_1_scrollbar =
+ static_cast<SolidColorScrollbarLayerImpl*>(
+ container->test_properties()->children[1]);
+
+ container->test_properties()->AddChild(SolidColorScrollbarLayerImpl::Create(
+ host_impl_->active_tree(), horiz_1_id, HORIZONTAL, 5, 5, true, true));
+ SolidColorScrollbarLayerImpl* horiz_1_scrollbar =
+ static_cast<SolidColorScrollbarLayerImpl*>(
+ container->test_properties()->children[2]);
+
+ container->test_properties()->AddChild(SolidColorScrollbarLayerImpl::Create(
+ host_impl_->active_tree(), vert_2_id, VERTICAL, 5, 5, true, true));
+ SolidColorScrollbarLayerImpl* vert_2_scrollbar =
+ static_cast<SolidColorScrollbarLayerImpl*>(
+ container->test_properties()->children[3]);
+
+ container->test_properties()->AddChild(SolidColorScrollbarLayerImpl::Create(
+ host_impl_->active_tree(), horiz_2_id, HORIZONTAL, 5, 5, true, true));
+ SolidColorScrollbarLayerImpl* horiz_2_scrollbar =
+ static_cast<SolidColorScrollbarLayerImpl*>(
+ container->test_properties()->children[4]);
+
std::unique_ptr<LayerImpl> child =
LayerImpl::Create(host_impl_->active_tree(), child_scroll_id);
child->SetBounds(content_size);
@@ -3332,75 +3285,75 @@ TEST_F(LayerTreeHostImplTest, ScrollbarRegistration) {
LayerImpl* child_ptr = child.get();
LayerImpl* child_clip_ptr = child_clip.get();
+ host_impl_->active_tree()->BuildPropertyTreesForTesting();
+
// Check scrollbar registration on the viewport layers.
- EXPECT_EQ(0ul, host_impl_->ScrollbarsFor(root_scroll->id()).size());
- EXPECT_EQ(nullptr,
- host_impl_->ScrollbarAnimationControllerForId(root_scroll->id()));
- vert_1_scrollbar->SetScrollLayerId(root_scroll->id());
- EXPECT_EQ(1ul, host_impl_->ScrollbarsFor(root_scroll->id()).size());
- EXPECT_TRUE(host_impl_->ScrollbarAnimationControllerForId(root_scroll->id()));
- horiz_1_scrollbar->SetScrollLayerId(root_scroll->id());
- EXPECT_EQ(2ul, host_impl_->ScrollbarsFor(root_scroll->id()).size());
- EXPECT_TRUE(host_impl_->ScrollbarAnimationControllerForId(root_scroll->id()));
-
- // Changing one of the viewport layers should result in a scrollbar animation
- // update.
+ EXPECT_EQ(0ul, host_impl_->ScrollbarsFor(root_scroll->element_id()).size());
+ EXPECT_EQ(nullptr, host_impl_->ScrollbarAnimationControllerForElementId(
+ root_scroll->element_id()));
+ vert_1_scrollbar->SetScrollElementId(root_scroll->element_id());
+ EXPECT_EQ(1ul, host_impl_->ScrollbarsFor(root_scroll->element_id()).size());
+ EXPECT_TRUE(host_impl_->ScrollbarAnimationControllerForElementId(
+ root_scroll->element_id()));
+ horiz_1_scrollbar->SetScrollElementId(root_scroll->element_id());
+ EXPECT_EQ(2ul, host_impl_->ScrollbarsFor(root_scroll->element_id()).size());
+ EXPECT_TRUE(host_impl_->ScrollbarAnimationControllerForElementId(
+ root_scroll->element_id()));
+
+ // Scrolling the viewport should result in a scrollbar animation update.
animation_task_ = base::Closure();
- host_impl_->active_tree()->InnerViewportContainerLayer()->SetBoundsDelta(
- gfx::Vector2dF(10, 10));
- EXPECT_FALSE(animation_task_.Equals(base::Closure()));
- animation_task_ = base::Closure();
- host_impl_->active_tree()->OuterViewportScrollLayer()->SetCurrentScrollOffset(
- gfx::ScrollOffset(10, 10));
- EXPECT_FALSE(animation_task_.Equals(base::Closure()));
- animation_task_ = base::Closure();
- host_impl_->active_tree()->InnerViewportScrollLayer()->SetCurrentScrollOffset(
- gfx::ScrollOffset(10, 10));
+ host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), InputHandler::WHEEL);
+ host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(10, 10)).get());
+ host_impl_->ScrollEnd(EndState().get());
EXPECT_FALSE(animation_task_.Equals(base::Closure()));
animation_task_ = base::Closure();
// Check scrollbar registration on a sublayer.
child->SetScrollClipLayer(child_clip->id());
child->SetElementId(LayerIdToElementIdForTesting(child->id()));
+ ElementId child_scroll_element_id = child->element_id();
child_clip->test_properties()->AddChild(std::move(child));
root_scroll->test_properties()->AddChild(std::move(child_clip));
- EXPECT_EQ(0ul, host_impl_->ScrollbarsFor(child_scroll_id).size());
- EXPECT_EQ(nullptr,
- host_impl_->ScrollbarAnimationControllerForId(child_scroll_id));
- vert_2_scrollbar->SetScrollLayerId(child_scroll_id);
- EXPECT_EQ(1ul, host_impl_->ScrollbarsFor(child_scroll_id).size());
- EXPECT_TRUE(host_impl_->ScrollbarAnimationControllerForId(child_scroll_id));
- horiz_2_scrollbar->SetScrollLayerId(child_scroll_id);
- EXPECT_EQ(2ul, host_impl_->ScrollbarsFor(child_scroll_id).size());
- EXPECT_TRUE(host_impl_->ScrollbarAnimationControllerForId(child_scroll_id));
+ EXPECT_EQ(0ul, host_impl_->ScrollbarsFor(child_scroll_element_id).size());
+ EXPECT_EQ(nullptr, host_impl_->ScrollbarAnimationControllerForElementId(
+ child_scroll_element_id));
+ vert_2_scrollbar->SetScrollElementId(child_scroll_element_id);
+ EXPECT_EQ(1ul, host_impl_->ScrollbarsFor(child_scroll_element_id).size());
+ EXPECT_TRUE(host_impl_->ScrollbarAnimationControllerForElementId(
+ child_scroll_element_id));
+ horiz_2_scrollbar->SetScrollElementId(child_scroll_element_id);
+ EXPECT_EQ(2ul, host_impl_->ScrollbarsFor(child_scroll_element_id).size());
+ EXPECT_TRUE(host_impl_->ScrollbarAnimationControllerForElementId(
+ child_scroll_element_id));
// Changing one of the child layers should result in a scrollbar animation
// update.
animation_task_ = base::Closure();
child_clip_ptr->SetBounds(gfx::Size(200, 200));
- EXPECT_FALSE(animation_task_.Equals(base::Closure()));
- animation_task_ = base::Closure();
- child_ptr->SetCurrentScrollOffset(gfx::ScrollOffset(10, 10));
+ child_ptr->set_needs_show_scrollbars(true);
+ host_impl_->active_tree()->HandleScrollbarShowRequestsFromMain();
EXPECT_FALSE(animation_task_.Equals(base::Closure()));
animation_task_ = base::Closure();
// Check scrollbar unregistration.
- vert_1_scrollbar.reset();
- EXPECT_EQ(1ul, host_impl_->ScrollbarsFor(root_scroll->id()).size());
- EXPECT_TRUE(host_impl_->ScrollbarAnimationControllerForId(root_scroll->id()));
- horiz_1_scrollbar.reset();
- EXPECT_EQ(0ul, host_impl_->ScrollbarsFor(root_scroll->id()).size());
- EXPECT_EQ(nullptr,
- host_impl_->ScrollbarAnimationControllerForId(root_scroll->id()));
-
- EXPECT_EQ(2ul, host_impl_->ScrollbarsFor(child_scroll_id).size());
- vert_2_scrollbar.reset();
- EXPECT_EQ(1ul, host_impl_->ScrollbarsFor(child_scroll_id).size());
- EXPECT_TRUE(host_impl_->ScrollbarAnimationControllerForId(child_scroll_id));
- horiz_2_scrollbar.reset();
- EXPECT_EQ(0ul, host_impl_->ScrollbarsFor(child_scroll_id).size());
- EXPECT_EQ(nullptr,
- host_impl_->ScrollbarAnimationControllerForId(root_scroll->id()));
+ container->test_properties()->RemoveChild(vert_1_scrollbar);
+ EXPECT_EQ(1ul, host_impl_->ScrollbarsFor(root_scroll->element_id()).size());
+ EXPECT_TRUE(host_impl_->ScrollbarAnimationControllerForElementId(
+ root_scroll->element_id()));
+ container->test_properties()->RemoveChild(horiz_1_scrollbar);
+ EXPECT_EQ(0ul, host_impl_->ScrollbarsFor(root_scroll->element_id()).size());
+ EXPECT_EQ(nullptr, host_impl_->ScrollbarAnimationControllerForElementId(
+ root_scroll->element_id()));
+
+ EXPECT_EQ(2ul, host_impl_->ScrollbarsFor(child_scroll_element_id).size());
+ container->test_properties()->RemoveChild(vert_2_scrollbar);
+ EXPECT_EQ(1ul, host_impl_->ScrollbarsFor(child_scroll_element_id).size());
+ EXPECT_TRUE(host_impl_->ScrollbarAnimationControllerForElementId(
+ child_scroll_element_id));
+ container->test_properties()->RemoveChild(horiz_2_scrollbar);
+ EXPECT_EQ(0ul, host_impl_->ScrollbarsFor(child_scroll_element_id).size());
+ EXPECT_EQ(nullptr, host_impl_->ScrollbarAnimationControllerForElementId(
+ root_scroll->element_id()));
// Changing scroll offset should no longer trigger any animation.
host_impl_->active_tree()->InnerViewportScrollLayer()->SetCurrentScrollOffset(
@@ -3435,8 +3388,8 @@ void LayerTreeHostImplTest::SetupMouseMoveAtWithDeviceScale(
// The scrollbar is on the left side.
std::unique_ptr<SolidColorScrollbarLayerImpl> scrollbar =
SolidColorScrollbarLayerImpl::Create(host_impl_->active_tree(), 6,
- VERTICAL, 5, 5, true, true);
- scrollbar->SetScrollLayerId(root_scroll->id());
+ VERTICAL, 15, 0, true, true);
+ scrollbar->SetScrollElementId(root_scroll->element_id());
scrollbar->SetDrawsContent(true);
scrollbar->SetBounds(scrollbar_size);
scrollbar->SetTouchEventHandlerRegion(gfx::Rect(scrollbar_size));
@@ -3451,32 +3404,46 @@ void LayerTreeHostImplTest::SetupMouseMoveAtWithDeviceScale(
host_impl_->active_tree()->UpdateDrawProperties(false);
ScrollbarAnimationController* scrollbar_animation_controller =
- host_impl_->ScrollbarAnimationControllerForId(root_scroll->id());
+ host_impl_->ScrollbarAnimationControllerForElementId(
+ root_scroll->element_id());
+
+ const float kMouseMoveDistanceToTriggerFadeIn =
+ ScrollbarAnimationController::kMouseMoveDistanceToTriggerFadeIn;
- const float kMouseDistanceToTriggerAnimation =
+ const float kMouseMoveDistanceToTriggerExpand =
SingleScrollbarAnimationControllerThinning::
- kDefaultMouseMoveDistanceToTriggerAnimation;
+ kMouseMoveDistanceToTriggerExpand;
host_impl_->MouseMoveAt(
- gfx::Point(15 + kMouseDistanceToTriggerAnimation * 2, 1));
+ gfx::Point(15 + kMouseMoveDistanceToTriggerFadeIn, 1));
EXPECT_FALSE(scrollbar_animation_controller->MouseIsNearScrollbar(VERTICAL));
+ EXPECT_FALSE(
+ scrollbar_animation_controller->MouseIsNearScrollbarThumb(VERTICAL));
host_impl_->MouseMoveAt(
- gfx::Point(15 + kMouseDistanceToTriggerAnimation - 1, 50));
+ gfx::Point(15 + kMouseMoveDistanceToTriggerExpand - 1, 10));
EXPECT_TRUE(scrollbar_animation_controller->MouseIsNearScrollbar(VERTICAL));
+ EXPECT_TRUE(
+ scrollbar_animation_controller->MouseIsNearScrollbarThumb(VERTICAL));
host_impl_->MouseMoveAt(
- gfx::Point(15 + kMouseDistanceToTriggerAnimation, 100));
+ gfx::Point(15 + kMouseMoveDistanceToTriggerFadeIn, 100));
EXPECT_FALSE(scrollbar_animation_controller->MouseIsNearScrollbar(VERTICAL));
+ EXPECT_FALSE(
+ scrollbar_animation_controller->MouseIsNearScrollbarThumb(VERTICAL));
did_request_redraw_ = false;
- EXPECT_FALSE(scrollbar_animation_controller->MouseIsOverScrollbar(VERTICAL));
- host_impl_->MouseMoveAt(gfx::Point(10, 100));
- EXPECT_TRUE(scrollbar_animation_controller->MouseIsOverScrollbar(VERTICAL));
- host_impl_->MouseMoveAt(gfx::Point(10, 120));
- EXPECT_TRUE(scrollbar_animation_controller->MouseIsOverScrollbar(VERTICAL));
+ EXPECT_FALSE(
+ scrollbar_animation_controller->MouseIsOverScrollbarThumb(VERTICAL));
+ host_impl_->MouseMoveAt(gfx::Point(10, 10));
+ EXPECT_TRUE(
+ scrollbar_animation_controller->MouseIsOverScrollbarThumb(VERTICAL));
+ host_impl_->MouseMoveAt(gfx::Point(10, 0));
+ EXPECT_TRUE(
+ scrollbar_animation_controller->MouseIsOverScrollbarThumb(VERTICAL));
host_impl_->MouseMoveAt(gfx::Point(150, 120));
- EXPECT_FALSE(scrollbar_animation_controller->MouseIsOverScrollbar(VERTICAL));
+ EXPECT_FALSE(
+ scrollbar_animation_controller->MouseIsOverScrollbarThumb(VERTICAL));
}
TEST_F(LayerTreeHostImplTest, MouseMoveAtWithDeviceScaleOf1) {
@@ -3487,24 +3454,33 @@ TEST_F(LayerTreeHostImplTest, MouseMoveAtWithDeviceScaleOf2) {
SetupMouseMoveAtWithDeviceScale(2.f);
}
-// This test verifies that only SurfaceLayers in the viewport are included
-// in CompositorFrameMetadata's |embedded_surfaces|.
-TEST_F(LayerTreeHostImplTest, EmbeddedSurfacesInMetadata) {
+// This test verifies that only SurfaceLayers in the viewport and have fallbacks
+// that are different are included in CompositorFrameMetadata's
+// |activation_dependencies|.
+TEST_F(LayerTreeHostImplTest, ActivationDependenciesInMetadata) {
SetupScrollAndContentsLayers(gfx::Size(100, 100));
host_impl_->SetViewportSize(gfx::Size(50, 50));
LayerImpl* root = host_impl_->active_tree()->root_layer_for_testing();
- std::vector<SurfaceId> children = {MakeSurfaceId(FrameSinkId(1, 1), 1),
- MakeSurfaceId(FrameSinkId(2, 2), 2),
- MakeSurfaceId(FrameSinkId(3, 3), 3)};
- for (size_t i = 0; i < children.size(); ++i) {
+ std::vector<SurfaceId> primary_surfaces = {
+ MakeSurfaceId(FrameSinkId(1, 1), 1), MakeSurfaceId(FrameSinkId(2, 2), 2),
+ MakeSurfaceId(FrameSinkId(3, 3), 3)};
+
+ std::vector<SurfaceId> fallback_surfaces = {
+ MakeSurfaceId(FrameSinkId(4, 4), 1), MakeSurfaceId(FrameSinkId(4, 4), 2),
+ MakeSurfaceId(FrameSinkId(4, 4), 3)};
+
+ for (size_t i = 0; i < primary_surfaces.size(); ++i) {
std::unique_ptr<SurfaceLayerImpl> child =
SurfaceLayerImpl::Create(host_impl_->active_tree(), i + 6);
child->SetPosition(gfx::PointF(25.f * i, 0.f));
child->SetBounds(gfx::Size(1, 1));
child->SetDrawsContent(true);
child->SetPrimarySurfaceInfo(
- SurfaceInfo(children[i], 1.f /* device_scale_factor */,
+ SurfaceInfo(primary_surfaces[i], 1.f /* device_scale_factor */,
+ gfx::Size(10, 10) /* size_in_pixels */));
+ child->SetFallbackSurfaceInfo(
+ SurfaceInfo(fallback_surfaces[i], 1.f /* device_scale_factor */,
gfx::Size(10, 10) /* size_in_pixels */));
root->test_properties()->AddChild(std::move(child));
}
@@ -3517,11 +3493,13 @@ TEST_F(LayerTreeHostImplTest, EmbeddedSurfacesInMetadata) {
host_impl_->compositor_frame_sink());
const CompositorFrameMetadata& metadata =
fake_compositor_frame_sink->last_sent_frame()->metadata;
- EXPECT_THAT(metadata.embedded_surfaces,
- testing::UnorderedElementsAre(children[0], children[1]));
+ EXPECT_THAT(
+ metadata.activation_dependencies,
+ testing::UnorderedElementsAre(primary_surfaces[0], primary_surfaces[1]));
EXPECT_THAT(
metadata.referenced_surfaces,
- testing::UnorderedElementsAre(children[0], children[1], children[2]));
+ testing::UnorderedElementsAre(fallback_surfaces[0], fallback_surfaces[1],
+ fallback_surfaces[2]));
}
TEST_F(LayerTreeHostImplTest, CompositorFrameMetadata) {
@@ -3879,8 +3857,8 @@ TEST_F(LayerTreeHostImplTest, DidDrawCalledOnAllLayers) {
EXPECT_TRUE(layer1->did_draw_called());
EXPECT_TRUE(layer2->did_draw_called());
- EXPECT_NE(root->GetRenderSurface(), layer1->GetRenderSurface());
- EXPECT_TRUE(layer1->GetRenderSurface());
+ EXPECT_NE(GetRenderSurface(root), GetRenderSurface(layer1));
+ EXPECT_TRUE(GetRenderSurface(layer1));
}
class MissingTextureAnimatingLayer : public DidDrawCheckLayer {
@@ -4251,6 +4229,8 @@ class LayerTreeHostImplBrowserControlsTest : public LayerTreeHostImplTest {
outer_scroll->test_properties()->is_container_for_fixed_position_layers =
true;
+ int inner_viewport_container_layer_id = root_clip->id();
+ int outer_viewport_container_layer_id = outer_clip->id();
int inner_viewport_scroll_layer_id = root->id();
int outer_viewport_scroll_layer_id = outer_scroll->id();
int page_scale_layer_id = page_scale->id();
@@ -4261,9 +4241,13 @@ class LayerTreeHostImplBrowserControlsTest : public LayerTreeHostImplTest {
root_clip->test_properties()->AddChild(std::move(page_scale));
tree_impl->SetRootLayerForTesting(std::move(root_clip));
- tree_impl->SetViewportLayersFromIds(Layer::INVALID_ID, page_scale_layer_id,
- inner_viewport_scroll_layer_id,
- outer_viewport_scroll_layer_id);
+ LayerTreeImpl::ViewportLayerIds viewport_ids;
+ viewport_ids.page_scale = page_scale_layer_id;
+ viewport_ids.inner_viewport_container = inner_viewport_container_layer_id;
+ viewport_ids.outer_viewport_container = outer_viewport_container_layer_id;
+ viewport_ids.inner_viewport_scroll = inner_viewport_scroll_layer_id;
+ viewport_ids.outer_viewport_scroll = outer_viewport_scroll_layer_id;
+ tree_impl->SetViewportLayersFromIds(viewport_ids);
tree_impl->BuildPropertyTreesForTesting();
host_impl_->SetViewportSize(inner_viewport_size);
@@ -4373,12 +4357,10 @@ TEST_F(LayerTreeHostImplBrowserControlsTest,
host_impl_->browser_controls_manager()->ScrollBy(top_controls_scroll_delta);
host_impl_->browser_controls_manager()->ScrollEnd();
- LayerImpl* inner_viewport_scroll_layer =
- host_impl_->active_tree()->InnerViewportScrollLayer();
- DCHECK(inner_viewport_scroll_layer);
host_impl_->ScrollEnd(EndState().get());
+ auto* property_trees = host_impl_->active_tree()->property_trees();
EXPECT_FLOAT_EQ(top_controls_scroll_delta.y(),
- inner_viewport_scroll_layer->FixedContainerSizeDelta().y());
+ property_trees->inner_viewport_container_bounds_delta().y());
}
// In this test, the outer viewport is initially unscrollable. We test that a
@@ -4479,9 +4461,6 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, FixedContainerDelta) {
host_impl_->active_tree()->PushPageScaleFromMainThread(1.f, 1.f, 2.f);
float page_scale = 1.5f;
- LayerImpl* outer_viewport_scroll_layer =
- host_impl_->active_tree()->OuterViewportScrollLayer();
-
// Zoom in, since the fixed container is the outer viewport, the delta should
// not be scaled.
host_impl_->active_tree()->PushPageScaleFromMainThread(page_scale, 1.f, 2.f);
@@ -4499,8 +4478,10 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, FixedContainerDelta) {
host_impl_->browser_controls_manager()->ScrollBy(top_controls_scroll_delta);
EXPECT_FLOAT_EQ(top_controls_height_ - top_controls_scroll_delta.y(),
host_impl_->browser_controls_manager()->ContentTopOffset());
+
+ auto* property_trees = host_impl_->active_tree()->property_trees();
EXPECT_FLOAT_EQ(top_controls_scroll_delta.y(),
- outer_viewport_scroll_layer->FixedContainerSizeDelta().y());
+ property_trees->outer_viewport_container_bounds_delta().y());
host_impl_->ScrollEnd(EndState().get());
// Scroll past the maximum extent. The delta shouldn't be greater than the
@@ -4511,7 +4492,7 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, FixedContainerDelta) {
host_impl_->browser_controls_manager()->ScrollBy(top_controls_scroll_delta);
EXPECT_EQ(0.f, host_impl_->browser_controls_manager()->ContentTopOffset());
EXPECT_VECTOR_EQ(gfx::Vector2dF(0, top_controls_height_),
- outer_viewport_scroll_layer->FixedContainerSizeDelta());
+ property_trees->outer_viewport_container_bounds_delta());
host_impl_->ScrollEnd(EndState().get());
// Scroll in the direction to make the browser controls show.
@@ -4521,7 +4502,7 @@ TEST_F(LayerTreeHostImplBrowserControlsTest, FixedContainerDelta) {
host_impl_->browser_controls_manager()->ContentTopOffset());
EXPECT_VECTOR_EQ(
gfx::Vector2dF(0, top_controls_height_ - top_controls_scroll_delta.y()),
- outer_viewport_scroll_layer->FixedContainerSizeDelta());
+ property_trees->outer_viewport_container_bounds_delta());
host_impl_->browser_controls_manager()->ScrollEnd();
}
@@ -4755,7 +4736,8 @@ TEST_F(LayerTreeHostImplBrowserControlsTest,
// account for the difference between the layout height and the current
// browser controls offset.
EXPECT_EQ(viewport_size_, inner_clip_ptr->bounds());
- EXPECT_VECTOR_EQ(gfx::Vector2dF(0.f, 50.f), inner_clip_ptr->bounds_delta());
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(0.f, 50.f),
+ inner_clip_ptr->ViewportBoundsDelta());
host_impl_->active_tree()->SetCurrentBrowserControlsShownRatio(1.f);
host_impl_->DidChangeBrowserControlsPosition();
@@ -4764,7 +4746,8 @@ TEST_F(LayerTreeHostImplBrowserControlsTest,
host_impl_->browser_controls_manager()->TopControlsShownRatio());
EXPECT_EQ(50.f, host_impl_->browser_controls_manager()->TopControlsHeight());
EXPECT_EQ(50.f, host_impl_->browser_controls_manager()->ContentTopOffset());
- EXPECT_VECTOR_EQ(gfx::Vector2dF(0.f, 0.f), inner_clip_ptr->bounds_delta());
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(0.f, 0.f),
+ inner_clip_ptr->ViewportBoundsDelta());
EXPECT_EQ(gfx::Size(viewport_size_.width(), viewport_size_.height() - 50.f),
inner_clip_ptr->bounds());
}
@@ -5608,7 +5591,8 @@ TEST_F(LayerTreeHostImplTimelinesTest, ScrollAnimatedLatchToChild) {
host_impl_->Animate();
host_impl_->UpdateAnimationState(true);
- EXPECT_EQ(gfx::ScrollOffset(0, 30), grand_child_layer->CurrentScrollOffset());
+ // Should have started scrolling.
+ EXPECT_NE(gfx::ScrollOffset(0, 30), grand_child_layer->CurrentScrollOffset());
host_impl_->DidFinishImplFrame();
begin_frame_args.frame_time =
@@ -5656,13 +5640,16 @@ TEST_F(LayerTreeHostImplTest, ScrollWithoutBubbling) {
// the scroll doesn't bubble up to the parent layer.
gfx::Size surface_size(20, 20);
gfx::Size viewport_size(10, 10);
+ const int kPageScaleLayerId = 1;
+ const int kViewportClipLayerId = 2;
+ const int kViewportScrollLayerId = 3;
std::unique_ptr<LayerImpl> root_ptr =
- LayerImpl::Create(host_impl_->active_tree(), 1);
+ LayerImpl::Create(host_impl_->active_tree(), kPageScaleLayerId);
std::unique_ptr<LayerImpl> root_clip =
- LayerImpl::Create(host_impl_->active_tree(), 2);
+ LayerImpl::Create(host_impl_->active_tree(), kViewportClipLayerId);
root_clip->test_properties()->force_render_surface = true;
- std::unique_ptr<LayerImpl> root_scrolling =
- CreateScrollableLayer(3, surface_size, root_clip.get());
+ std::unique_ptr<LayerImpl> root_scrolling = CreateScrollableLayer(
+ kViewportScrollLayerId, surface_size, root_clip.get());
root_scrolling->test_properties()->is_container_for_fixed_position_layers =
true;
@@ -5681,8 +5668,11 @@ TEST_F(LayerTreeHostImplTest, ScrollWithoutBubbling) {
root_ptr->test_properties()->AddChild(std::move(root_clip));
host_impl_->active_tree()->SetRootLayerForTesting(std::move(root_ptr));
host_impl_->active_tree()->BuildPropertyTreesForTesting();
- host_impl_->active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 1, 3,
- Layer::INVALID_ID);
+ LayerTreeImpl::ViewportLayerIds viewport_ids;
+ viewport_ids.page_scale = kPageScaleLayerId;
+ viewport_ids.inner_viewport_container = kViewportClipLayerId;
+ viewport_ids.inner_viewport_scroll = kViewportScrollLayerId;
+ host_impl_->active_tree()->SetViewportLayersFromIds(viewport_ids);
host_impl_->active_tree()->DidBecomeActive();
host_impl_->SetViewportSize(viewport_size);
@@ -5801,17 +5791,20 @@ TEST_F(LayerTreeHostImplTest, ScrollEventBubbling) {
// should be applied to one of its ancestors if possible.
gfx::Size surface_size(10, 10);
gfx::Size content_size(20, 20);
+ const int kPageScaleLayerId = 4;
+ const int kViewportClipLayerId = 1;
+ const int kViewportScrollLayerId = 2;
std::unique_ptr<LayerImpl> root_ptr =
- LayerImpl::Create(host_impl_->active_tree(), 4);
+ LayerImpl::Create(host_impl_->active_tree(), kPageScaleLayerId);
std::unique_ptr<LayerImpl> root_clip =
LayerImpl::Create(host_impl_->active_tree(), 3);
root_clip->test_properties()->force_render_surface = true;
- std::unique_ptr<LayerImpl> root_scroll =
- CreateScrollableLayer(1, content_size, root_clip.get());
+ std::unique_ptr<LayerImpl> root_scroll = CreateScrollableLayer(
+ kViewportClipLayerId, content_size, root_clip.get());
// Make 'root' the clip layer for child: since they have the same sizes the
// child will have zero max_scroll_offset and scrolls will bubble.
- std::unique_ptr<LayerImpl> child =
- CreateScrollableLayer(2, content_size, root_scroll.get());
+ std::unique_ptr<LayerImpl> child = CreateScrollableLayer(
+ kViewportScrollLayerId, content_size, root_scroll.get());
child->test_properties()->is_container_for_fixed_position_layers = true;
root_scroll->SetBounds(content_size);
@@ -5821,8 +5814,11 @@ TEST_F(LayerTreeHostImplTest, ScrollEventBubbling) {
root_ptr->test_properties()->AddChild(std::move(root_clip));
host_impl_->active_tree()->SetRootLayerForTesting(std::move(root_ptr));
- host_impl_->active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 4, 2,
- Layer::INVALID_ID);
+ LayerTreeImpl::ViewportLayerIds viewport_ids;
+ viewport_ids.page_scale = kPageScaleLayerId;
+ viewport_ids.inner_viewport_container = kViewportClipLayerId;
+ viewport_ids.inner_viewport_scroll = kViewportScrollLayerId;
+ host_impl_->active_tree()->SetViewportLayersFromIds(viewport_ids);
host_impl_->active_tree()->BuildPropertyTreesForTesting();
host_impl_->active_tree()->DidBecomeActive();
@@ -5849,17 +5845,22 @@ TEST_F(LayerTreeHostImplTest, ScrollEventBubbling) {
}
TEST_F(LayerTreeHostImplTest, ScrollBeforeRedraw) {
+ const int kPageScaleLayerId = 1;
+ const int kInnerViewportClipLayerId = 2;
+ const int kOuterViewportClipLayerId = 7;
+ const int kInnerViewportScrollLayerId = 3;
+ const int kOuterViewportScrollLayerId = 8;
gfx::Size surface_size(10, 10);
std::unique_ptr<LayerImpl> root_ptr =
- LayerImpl::Create(host_impl_->active_tree(), 1);
+ LayerImpl::Create(host_impl_->active_tree(), kPageScaleLayerId);
std::unique_ptr<LayerImpl> inner_clip =
- LayerImpl::Create(host_impl_->active_tree(), 2);
- std::unique_ptr<LayerImpl> inner_scroll =
- CreateScrollableLayer(3, surface_size, inner_clip.get());
+ LayerImpl::Create(host_impl_->active_tree(), kInnerViewportClipLayerId);
+ std::unique_ptr<LayerImpl> inner_scroll = CreateScrollableLayer(
+ kInnerViewportScrollLayerId, surface_size, inner_clip.get());
std::unique_ptr<LayerImpl> outer_clip =
- LayerImpl::Create(host_impl_->active_tree(), 7);
- std::unique_ptr<LayerImpl> outer_scroll =
- CreateScrollableLayer(8, surface_size, outer_clip.get());
+ LayerImpl::Create(host_impl_->active_tree(), kOuterViewportClipLayerId);
+ std::unique_ptr<LayerImpl> outer_scroll = CreateScrollableLayer(
+ kOuterViewportScrollLayerId, surface_size, outer_clip.get());
inner_clip->test_properties()->force_render_surface = true;
inner_scroll->test_properties()->is_container_for_fixed_position_layers =
true;
@@ -5870,8 +5871,13 @@ TEST_F(LayerTreeHostImplTest, ScrollBeforeRedraw) {
inner_clip->test_properties()->AddChild(std::move(inner_scroll));
root_ptr->test_properties()->AddChild(std::move(inner_clip));
host_impl_->active_tree()->SetRootLayerForTesting(std::move(root_ptr));
- host_impl_->active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 1, 3,
- 8);
+ LayerTreeImpl::ViewportLayerIds viewport_ids;
+ viewport_ids.page_scale = kPageScaleLayerId;
+ viewport_ids.inner_viewport_container = kInnerViewportClipLayerId;
+ viewport_ids.outer_viewport_container = kOuterViewportClipLayerId;
+ viewport_ids.inner_viewport_scroll = kInnerViewportScrollLayerId;
+ viewport_ids.outer_viewport_scroll = kOuterViewportScrollLayerId;
+ host_impl_->active_tree()->SetViewportLayersFromIds(viewport_ids);
host_impl_->active_tree()->BuildPropertyTreesForTesting();
host_impl_->active_tree()->DidBecomeActive();
@@ -5881,17 +5887,22 @@ TEST_F(LayerTreeHostImplTest, ScrollBeforeRedraw) {
// synchronization.
DrawFrame();
+ const int kPageScaleLayerId2 = 4;
+ const int kInnerViewportClipLayerId2 = 5;
+ const int kOuterViewportClipLayerId2 = 9;
+ const int kInnerViewportScrollLayerId2 = 6;
+ const int kOuterViewportScrollLayerId2 = 10;
host_impl_->active_tree()->DetachLayers();
std::unique_ptr<LayerImpl> root_ptr2 =
LayerImpl::Create(host_impl_->active_tree(), 4);
std::unique_ptr<LayerImpl> inner_clip2 =
- LayerImpl::Create(host_impl_->active_tree(), 5);
- std::unique_ptr<LayerImpl> inner_scroll2 =
- CreateScrollableLayer(6, surface_size, inner_clip2.get());
+ LayerImpl::Create(host_impl_->active_tree(), kInnerViewportClipLayerId2);
+ std::unique_ptr<LayerImpl> inner_scroll2 = CreateScrollableLayer(
+ kInnerViewportScrollLayerId2, surface_size, inner_clip2.get());
std::unique_ptr<LayerImpl> outer_clip2 =
- LayerImpl::Create(host_impl_->active_tree(), 9);
- std::unique_ptr<LayerImpl> outer_scroll2 =
- CreateScrollableLayer(10, surface_size, outer_clip2.get());
+ LayerImpl::Create(host_impl_->active_tree(), kOuterViewportClipLayerId2);
+ std::unique_ptr<LayerImpl> outer_scroll2 = CreateScrollableLayer(
+ kOuterViewportScrollLayerId2, surface_size, outer_clip2.get());
inner_scroll2->test_properties()->is_container_for_fixed_position_layers =
true;
outer_scroll2->test_properties()->is_container_for_fixed_position_layers =
@@ -5903,8 +5914,13 @@ TEST_F(LayerTreeHostImplTest, ScrollBeforeRedraw) {
root_ptr2->test_properties()->AddChild(std::move(inner_clip2));
host_impl_->active_tree()->SetRootLayerForTesting(std::move(root_ptr2));
host_impl_->active_tree()->BuildPropertyTreesForTesting();
- host_impl_->active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 4, 6,
- 10);
+ LayerTreeImpl::ViewportLayerIds viewport_ids2;
+ viewport_ids2.page_scale = kPageScaleLayerId2;
+ viewport_ids2.inner_viewport_container = kInnerViewportClipLayerId2;
+ viewport_ids2.outer_viewport_container = kOuterViewportClipLayerId2;
+ viewport_ids2.inner_viewport_scroll = kInnerViewportScrollLayerId2;
+ viewport_ids2.outer_viewport_scroll = kOuterViewportScrollLayerId2;
+ host_impl_->active_tree()->SetViewportLayersFromIds(viewport_ids2);
host_impl_->active_tree()->DidBecomeActive();
// Scrolling should still work even though we did not draw yet.
@@ -6471,12 +6487,14 @@ TEST_F(LayerTreeHostImplTest, OverscrollChildWithoutBubbling) {
// overscroll does not accumulate.
InputHandlerScrollResult scroll_result;
gfx::Size surface_size(10, 10);
+ const int kInnerViewportClipLayerId = 4;
+ const int kInnerViewportScrollLayerId = 1;
std::unique_ptr<LayerImpl> root_clip =
- LayerImpl::Create(host_impl_->active_tree(), 4);
+ LayerImpl::Create(host_impl_->active_tree(), kInnerViewportClipLayerId);
root_clip->test_properties()->force_render_surface = true;
- std::unique_ptr<LayerImpl> root =
- CreateScrollableLayer(1, surface_size, root_clip.get());
+ std::unique_ptr<LayerImpl> root = CreateScrollableLayer(
+ kInnerViewportScrollLayerId, surface_size, root_clip.get());
std::unique_ptr<LayerImpl> grand_child =
CreateScrollableLayer(3, surface_size, root_clip.get());
@@ -6486,8 +6504,10 @@ TEST_F(LayerTreeHostImplTest, OverscrollChildWithoutBubbling) {
LayerImpl* grand_child_layer = grand_child.get();
child->test_properties()->AddChild(std::move(grand_child));
- host_impl_->active_tree()->SetViewportLayersFromIds(
- Layer::INVALID_ID, Layer::INVALID_ID, root->id(), Layer::INVALID_ID);
+ LayerTreeImpl::ViewportLayerIds viewport_ids;
+ viewport_ids.inner_viewport_container = kInnerViewportClipLayerId;
+ viewport_ids.inner_viewport_scroll = kInnerViewportScrollLayerId;
+ host_impl_->active_tree()->SetViewportLayersFromIds(viewport_ids);
LayerImpl* child_layer = child.get();
root->test_properties()->AddChild(std::move(child));
@@ -6890,9 +6910,11 @@ TEST_F(LayerTreeHostImplTest, ScrollChainingWithReplacedOuterViewport) {
clip->test_properties()->AddChild(std::move(scroll));
content_layer->test_properties()->AddChild(std::move(clip));
- layer_tree_impl->SetViewportLayersFromIds(
- Layer::INVALID_ID, layer_tree_impl->PageScaleLayer()->id(),
- inner_scroll_layer->id(), scroll_layer->id());
+ LayerTreeImpl::ViewportLayerIds viewport_ids;
+ viewport_ids.page_scale = layer_tree_impl->PageScaleLayer()->id();
+ viewport_ids.inner_viewport_scroll = inner_scroll_layer->id();
+ viewport_ids.outer_viewport_scroll = scroll_layer->id();
+ layer_tree_impl->SetViewportLayersFromIds(viewport_ids);
layer_tree_impl->BuildPropertyTreesForTesting();
}
@@ -7025,9 +7047,14 @@ TEST_F(LayerTreeHostImplTest, RootScrollerScrollNonDescendant) {
clip2->test_properties()->AddChild(std::move(scroll2));
content_layer->test_properties()->AddChild(std::move(clip2));
- layer_tree_impl->SetViewportLayersFromIds(
- Layer::INVALID_ID, layer_tree_impl->PageScaleLayer()->id(),
- inner_scroll_layer->id(), outer_scroll_layer->id());
+ LayerImpl* inner_container =
+ host_impl_->active_tree()->InnerViewportContainerLayer();
+ LayerTreeImpl::ViewportLayerIds viewport_ids;
+ viewport_ids.page_scale = layer_tree_impl->PageScaleLayer()->id();
+ viewport_ids.inner_viewport_container = inner_container->id();
+ viewport_ids.inner_viewport_scroll = inner_scroll_layer->id();
+ viewport_ids.outer_viewport_scroll = outer_scroll_layer->id();
+ layer_tree_impl->SetViewportLayersFromIds(viewport_ids);
layer_tree_impl->BuildPropertyTreesForTesting();
ASSERT_EQ(outer_scroll_layer, layer_tree_impl->OuterViewportScrollLayer());
@@ -7219,12 +7246,16 @@ class BlendStateCheckLayer : public LayerImpl {
gfx::Size(1, 1), false, false);
test_blending_draw_quad->visible_rect = quad_visible_rect_;
EXPECT_EQ(blend_, test_blending_draw_quad->ShouldDrawWithBlending());
- EXPECT_EQ(has_render_surface_, !!GetRenderSurface());
+ EXPECT_EQ(has_render_surface_,
+ GetRenderSurface(this) != GetRenderSurface(comparison_layer_));
}
- void SetExpectation(bool blend, bool has_render_surface) {
+ void SetExpectation(bool blend,
+ bool has_render_surface,
+ LayerImpl* comparison_layer) {
blend_ = blend;
has_render_surface_ = has_render_surface;
+ comparison_layer_ = comparison_layer;
quads_appended_ = false;
}
@@ -7243,6 +7274,7 @@ class BlendStateCheckLayer : public LayerImpl {
: LayerImpl(tree_impl, id),
blend_(false),
has_render_surface_(false),
+ comparison_layer_(nullptr),
quads_appended_(false),
quad_rect_(5, 5, 5, 5),
quad_visible_rect_(5, 5, 5, 5),
@@ -7258,6 +7290,7 @@ class BlendStateCheckLayer : public LayerImpl {
bool blend_;
bool has_render_surface_;
+ LayerImpl* comparison_layer_;
bool quads_appended_;
gfx::Rect quad_rect_;
gfx::Rect opaque_content_rect_;
@@ -7286,7 +7319,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
// Opaque layer, drawn without blending.
layer1->SetContentsOpaque(true);
- layer1->SetExpectation(false, false);
+ layer1->SetExpectation(false, false, root);
layer1->SetUpdateRect(gfx::Rect(layer1->bounds()));
host_impl_->active_tree()->BuildPropertyTreesForTesting();
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
@@ -7296,7 +7329,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
// Layer with translucent content and painting, so drawn with blending.
layer1->SetContentsOpaque(false);
- layer1->SetExpectation(true, false);
+ layer1->SetExpectation(true, false, root);
layer1->SetUpdateRect(gfx::Rect(layer1->bounds()));
host_impl_->active_tree()->BuildPropertyTreesForTesting();
host_impl_->active_tree()->set_needs_update_draw_properties();
@@ -7309,7 +7342,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
layer1->SetContentsOpaque(true);
layer1->test_properties()->opacity = 0.5f;
layer1->NoteLayerPropertyChanged();
- layer1->SetExpectation(true, false);
+ layer1->SetExpectation(true, false, root);
layer1->SetUpdateRect(gfx::Rect(layer1->bounds()));
host_impl_->active_tree()->BuildPropertyTreesForTesting();
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
@@ -7321,7 +7354,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
layer1->SetContentsOpaque(true);
layer1->test_properties()->opacity = 0.5f;
layer1->NoteLayerPropertyChanged();
- layer1->SetExpectation(true, false);
+ layer1->SetExpectation(true, false, root);
layer1->SetUpdateRect(gfx::Rect(layer1->bounds()));
host_impl_->active_tree()->BuildPropertyTreesForTesting();
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
@@ -7339,12 +7372,12 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
layer1->SetContentsOpaque(true);
layer1->test_properties()->opacity = 1.f;
layer1->NoteLayerPropertyChanged();
- layer1->SetExpectation(false, false);
+ layer1->SetExpectation(false, false, root);
layer1->SetUpdateRect(gfx::Rect(layer1->bounds()));
layer2->SetContentsOpaque(true);
layer2->test_properties()->opacity = 1.f;
layer2->NoteLayerPropertyChanged();
- layer2->SetExpectation(false, false);
+ layer2->SetExpectation(false, false, root);
layer2->SetUpdateRect(gfx::Rect(layer1->bounds()));
host_impl_->active_tree()->BuildPropertyTreesForTesting();
host_impl_->active_tree()->set_needs_update_draw_properties();
@@ -7357,9 +7390,9 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
// Parent layer with translucent content, drawn with blending.
// Child layer with opaque content, drawn without blending.
layer1->SetContentsOpaque(false);
- layer1->SetExpectation(true, false);
+ layer1->SetExpectation(true, false, root);
layer1->SetUpdateRect(gfx::Rect(layer1->bounds()));
- layer2->SetExpectation(false, false);
+ layer2->SetExpectation(false, false, root);
layer2->SetUpdateRect(gfx::Rect(layer1->bounds()));
host_impl_->active_tree()->BuildPropertyTreesForTesting();
host_impl_->active_tree()->set_needs_update_draw_properties();
@@ -7373,9 +7406,9 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
// blending.
// Child layer with opaque content, drawn without blending.
layer1->SetContentsOpaque(true);
- layer1->SetExpectation(false, false);
+ layer1->SetExpectation(false, false, root);
layer1->SetUpdateRect(gfx::Rect(layer1->bounds()));
- layer2->SetExpectation(false, false);
+ layer2->SetExpectation(false, false, root);
layer2->SetUpdateRect(gfx::Rect(layer1->bounds()));
host_impl_->active_tree()->BuildPropertyTreesForTesting();
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
@@ -7393,9 +7426,9 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
layer1->test_properties()->opacity = 0.5f;
layer1->NoteLayerPropertyChanged();
layer1->test_properties()->force_render_surface = true;
- layer1->SetExpectation(false, true);
+ layer1->SetExpectation(false, true, root);
layer1->SetUpdateRect(gfx::Rect(layer1->bounds()));
- layer2->SetExpectation(false, false);
+ layer2->SetExpectation(false, false, layer1);
layer2->SetUpdateRect(gfx::Rect(layer1->bounds()));
host_impl_->active_tree()->BuildPropertyTreesForTesting();
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
@@ -7410,12 +7443,12 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
layer1->SetContentsOpaque(true);
layer1->test_properties()->opacity = 1.f;
layer1->NoteLayerPropertyChanged();
- layer1->SetExpectation(false, false);
+ layer1->SetExpectation(false, false, root);
layer1->SetUpdateRect(gfx::Rect(layer1->bounds()));
layer2->SetContentsOpaque(true);
layer2->test_properties()->opacity = 0.5f;
layer2->NoteLayerPropertyChanged();
- layer2->SetExpectation(true, false);
+ layer2->SetExpectation(true, false, layer1);
layer2->SetUpdateRect(gfx::Rect(layer1->bounds()));
host_impl_->active_tree()->BuildPropertyTreesForTesting();
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
@@ -7428,12 +7461,12 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
layer1->SetContentsOpaque(true);
layer1->test_properties()->opacity = 1.f;
layer1->NoteLayerPropertyChanged();
- layer1->SetExpectation(false, false);
+ layer1->SetExpectation(false, false, root);
layer1->SetUpdateRect(gfx::Rect(layer1->bounds()));
layer2->SetContentsOpaque(false);
layer2->test_properties()->opacity = 1.f;
layer2->NoteLayerPropertyChanged();
- layer2->SetExpectation(true, false);
+ layer2->SetExpectation(true, false, root);
layer2->SetUpdateRect(gfx::Rect(layer1->bounds()));
host_impl_->active_tree()->BuildPropertyTreesForTesting();
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
@@ -7447,12 +7480,12 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
layer1->SetContentsOpaque(true);
layer1->test_properties()->opacity = 1.f;
layer1->NoteLayerPropertyChanged();
- layer1->SetExpectation(false, false);
+ layer1->SetExpectation(false, false, root);
layer1->SetUpdateRect(gfx::Rect(layer1->bounds()));
layer2->SetContentsOpaque(true);
layer2->test_properties()->opacity = 1.f;
layer2->NoteLayerPropertyChanged();
- layer2->SetExpectation(false, false);
+ layer2->SetExpectation(false, false, root);
layer2->SetUpdateRect(gfx::Rect(layer1->bounds()));
host_impl_->active_tree()->BuildPropertyTreesForTesting();
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
@@ -7466,7 +7499,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
layer1->SetQuadRect(gfx::Rect(5, 5, 5, 5));
layer1->SetQuadVisibleRect(gfx::Rect(5, 5, 5, 5));
layer1->SetOpaqueContentRect(gfx::Rect(5, 5, 2, 5));
- layer1->SetExpectation(true, false);
+ layer1->SetExpectation(true, false, root);
layer1->SetUpdateRect(gfx::Rect(layer1->bounds()));
host_impl_->active_tree()->BuildPropertyTreesForTesting();
host_impl_->active_tree()->set_needs_update_draw_properties();
@@ -7480,7 +7513,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
layer1->SetQuadRect(gfx::Rect(5, 5, 5, 5));
layer1->SetQuadVisibleRect(gfx::Rect(5, 5, 5, 2));
layer1->SetOpaqueContentRect(gfx::Rect(5, 5, 2, 5));
- layer1->SetExpectation(true, false);
+ layer1->SetExpectation(true, false, root);
layer1->SetUpdateRect(gfx::Rect(layer1->bounds()));
host_impl_->active_tree()->BuildPropertyTreesForTesting();
host_impl_->active_tree()->set_needs_update_draw_properties();
@@ -7494,7 +7527,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
layer1->SetQuadRect(gfx::Rect(5, 5, 5, 5));
layer1->SetQuadVisibleRect(gfx::Rect(7, 5, 3, 5));
layer1->SetOpaqueContentRect(gfx::Rect(5, 5, 2, 5));
- layer1->SetExpectation(true, false);
+ layer1->SetExpectation(true, false, root);
layer1->SetUpdateRect(gfx::Rect(layer1->bounds()));
host_impl_->active_tree()->BuildPropertyTreesForTesting();
host_impl_->active_tree()->set_needs_update_draw_properties();
@@ -7509,7 +7542,7 @@ TEST_F(LayerTreeHostImplTest, BlendingOffWhenDrawingOpaqueLayers) {
layer1->SetQuadRect(gfx::Rect(5, 5, 5, 5));
layer1->SetQuadVisibleRect(gfx::Rect(5, 5, 2, 5));
layer1->SetOpaqueContentRect(gfx::Rect(5, 5, 2, 5));
- layer1->SetExpectation(false, false);
+ layer1->SetExpectation(false, false, root);
layer1->SetUpdateRect(gfx::Rect(layer1->bounds()));
host_impl_->active_tree()->BuildPropertyTreesForTesting();
host_impl_->active_tree()->set_needs_update_draw_properties();
@@ -7599,7 +7632,8 @@ class LayerTreeHostImplViewportCoveredTest : public LayerTreeHostImplTest {
->root_layer_for_testing()
->test_properties()
->children[0]);
- child_->SetExpectation(false, false);
+ child_->SetExpectation(false, false,
+ host_impl_->active_tree()->root_layer_for_testing());
child_->SetContentsOpaque(true);
}
@@ -7982,7 +8016,7 @@ TEST_F(LayerTreeHostImplTest, RootLayerDoesntCreateExtraSurface) {
TestFrameData frame;
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
- EXPECT_EQ(1u, frame.render_surface_layer_list->size());
+ EXPECT_EQ(1u, frame.render_surface_list->size());
EXPECT_EQ(1u, frame.render_passes.size());
host_impl_->DidDrawAllLayers(frame);
}
@@ -8293,7 +8327,7 @@ TEST_F(LayerTreeHostImplTestDrawAndTestDamage, FrameIncludesDamageRect) {
host_impl_->active_tree()->BuildPropertyTreesForTesting();
// Draw a frame. In the first frame, the entire viewport should be damaged.
- gfx::Rect full_frame_damage(host_impl_->DrawViewportSize());
+ gfx::Rect full_frame_damage(host_impl_->DeviceViewport().size());
DrawFrameAndTestDamage(full_frame_damage);
// The second frame has damage that doesn't touch the child layer. Its quads
@@ -8339,7 +8373,7 @@ TEST_F(LayerTreeHostImplTest, FarAwayQuadsDontNeedAA) {
LayerImpl* scrolling_layer = scoped_scrolling_layer.get();
root->test_properties()->AddChild(std::move(scoped_scrolling_layer));
- gfx::Size content_layer_bounds(100000, 100);
+ gfx::Size content_layer_bounds(100001, 100);
scoped_refptr<FakeRasterSource> raster_source(
FakeRasterSource::CreateFilled(content_layer_bounds));
@@ -8367,7 +8401,7 @@ TEST_F(LayerTreeHostImplTest, FarAwayQuadsDontNeedAA) {
bool update_lcd_text = false;
host_impl_->active_tree()->UpdateDrawProperties(update_lcd_text);
- ASSERT_EQ(1u, host_impl_->active_tree()->RenderSurfaceLayerList().size());
+ ASSERT_EQ(1u, host_impl_->active_tree()->GetRenderSurfaceList().size());
TestFrameData frame;
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
@@ -8757,11 +8791,12 @@ TEST_F(LayerTreeHostImplTest, ShutdownReleasesContext) {
TestContextProvider::Create();
FrameSinkClient test_client_(context_provider);
+ constexpr bool synchronous_composite = true;
+ constexpr bool disable_display_vsync = false;
auto compositor_frame_sink = base::MakeUnique<TestCompositorFrameSink>(
context_provider, TestContextProvider::CreateWorker(), nullptr, nullptr,
RendererSettings(), base::ThreadTaskRunnerHandle::Get().get(),
- true /* synchronous_composite */,
- false /* force_disable_reclaim_resources */);
+ synchronous_composite, disable_display_vsync);
compositor_frame_sink->SetClient(&test_client_);
CreateHostImpl(DefaultSettings(), std::move(compositor_frame_sink));
@@ -8798,14 +8833,17 @@ TEST_F(LayerTreeHostImplTest, TouchFlingShouldNotBubble) {
// bubble).
gfx::Size surface_size(10, 10);
gfx::Size content_size(20, 20);
+ const int kPageScaleLayerId = 4;
+ const int kInnerViewportClipLayerId = 3;
+ const int kInnerViewportScrollLayerId = 1;
std::unique_ptr<LayerImpl> root_ptr =
- LayerImpl::Create(host_impl_->active_tree(), 4);
+ LayerImpl::Create(host_impl_->active_tree(), kPageScaleLayerId);
std::unique_ptr<LayerImpl> root_clip =
- LayerImpl::Create(host_impl_->active_tree(), 3);
+ LayerImpl::Create(host_impl_->active_tree(), kInnerViewportClipLayerId);
root_clip->test_properties()->force_render_surface = true;
- std::unique_ptr<LayerImpl> root_scroll =
- CreateScrollableLayer(1, content_size, root_clip.get());
+ std::unique_ptr<LayerImpl> root_scroll = CreateScrollableLayer(
+ kInnerViewportScrollLayerId, content_size, root_clip.get());
root_scroll->test_properties()->is_container_for_fixed_position_layers = true;
std::unique_ptr<LayerImpl> child =
CreateScrollableLayer(2, content_size, root_clip.get());
@@ -8817,8 +8855,11 @@ TEST_F(LayerTreeHostImplTest, TouchFlingShouldNotBubble) {
host_impl_->SetViewportSize(surface_size);
host_impl_->active_tree()->SetRootLayerForTesting(std::move(root_ptr));
- host_impl_->active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 4, 1,
- Layer::INVALID_ID);
+ LayerTreeImpl::ViewportLayerIds viewport_ids;
+ viewport_ids.page_scale = kPageScaleLayerId;
+ viewport_ids.inner_viewport_container = kInnerViewportClipLayerId;
+ viewport_ids.inner_viewport_scroll = kInnerViewportScrollLayerId;
+ host_impl_->active_tree()->SetViewportLayersFromIds(viewport_ids);
host_impl_->active_tree()->BuildPropertyTreesForTesting();
host_impl_->active_tree()->DidBecomeActive();
DrawFrame();
@@ -9122,7 +9163,7 @@ TEST_F(LayerTreeHostImplTest, LatencyInfoPassedToCompositorFrameMetadata) {
new LatencyInfoSwapPromise(latency_info));
host_impl_->active_tree()->QueuePinnedSwapPromise(std::move(swap_promise));
- gfx::Rect full_frame_damage(host_impl_->DrawViewportSize());
+ gfx::Rect full_frame_damage(host_impl_->DeviceViewport().size());
TestFrameData frame;
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
EXPECT_TRUE(host_impl_->DrawLayers(&frame));
@@ -9166,7 +9207,7 @@ TEST_F(LayerTreeHostImplTest, SelectionBoundsPassedToCompositorFrameMetadata) {
// Trigger a draw-swap sequence.
host_impl_->SetNeedsRedraw();
- gfx::Rect full_frame_damage(host_impl_->DrawViewportSize());
+ gfx::Rect full_frame_damage(host_impl_->DeviceViewport().size());
TestFrameData frame;
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
EXPECT_TRUE(host_impl_->DrawLayers(&frame));
@@ -9825,6 +9866,7 @@ TEST_F(LayerTreeHostImplBrowserControlsTest,
LayerImpl* inner_scroll = host_impl_->InnerViewportScrollLayer();
LayerTreeImpl* layer_tree_impl = host_impl_->active_tree();
LayerImpl* scroll_layer = nullptr;
+ LayerImpl* clip_layer = nullptr;
// Initialization: Add a child scrolling layer to the outer scroll layer and
// set its scroll layer as the outer viewport. This simulates setting a
@@ -9841,12 +9883,18 @@ TEST_F(LayerTreeHostImplBrowserControlsTest,
scroll->SetDrawsContent(true);
scroll_layer = scroll.get();
+ clip_layer = clip.get();
clip->test_properties()->AddChild(std::move(scroll));
outer_scroll->test_properties()->AddChild(std::move(clip));
- layer_tree_impl->SetViewportLayersFromIds(
- Layer::INVALID_ID, layer_tree_impl->PageScaleLayer()->id(),
- inner_scroll->id(), scroll_layer->id());
+ LayerTreeImpl::ViewportLayerIds viewport_ids;
+ viewport_ids.page_scale = layer_tree_impl->PageScaleLayer()->id();
+ viewport_ids.inner_viewport_container =
+ layer_tree_impl->InnerViewportContainerLayer()->id();
+ viewport_ids.outer_viewport_container = clip_layer->id();
+ viewport_ids.inner_viewport_scroll = inner_scroll->id();
+ viewport_ids.outer_viewport_scroll = scroll_layer->id();
+ layer_tree_impl->SetViewportLayersFromIds(viewport_ids);
layer_tree_impl->BuildPropertyTreesForTesting();
DrawFrame();
}
@@ -9935,9 +9983,13 @@ class LayerTreeHostImplVirtualViewportTest : public LayerTreeHostImplTest {
inner_clip->test_properties()->force_render_surface = true;
layer_tree_impl->SetRootLayerForTesting(std::move(inner_clip));
- layer_tree_impl->SetViewportLayersFromIds(
- Layer::INVALID_ID, kPageScaleLayerId, kInnerViewportScrollLayerId,
- kOuterViewportScrollLayerId);
+ LayerTreeImpl::ViewportLayerIds viewport_ids;
+ viewport_ids.page_scale = kPageScaleLayerId;
+ viewport_ids.inner_viewport_container = kInnerViewportClipLayerId;
+ viewport_ids.outer_viewport_container = kOuterViewportClipLayerId;
+ viewport_ids.inner_viewport_scroll = kInnerViewportScrollLayerId;
+ viewport_ids.outer_viewport_scroll = kOuterViewportScrollLayerId;
+ layer_tree_impl->SetViewportLayersFromIds(viewport_ids);
host_impl_->active_tree()->BuildPropertyTreesForTesting();
host_impl_->active_tree()->DidBecomeActive();
@@ -10746,7 +10798,7 @@ TEST_F(LayerTreeHostImplTest, ScrollAnimated) {
host_impl_->Animate();
host_impl_->UpdateAnimationState(true);
- EXPECT_EQ(gfx::ScrollOffset(), scrolling_layer->CurrentScrollOffset());
+ EXPECT_NE(gfx::ScrollOffset(), scrolling_layer->CurrentScrollOffset());
host_impl_->DidFinishImplFrame();
begin_frame_args.frame_time =
@@ -10887,13 +10939,15 @@ TEST_F(LayerTreeHostImplTest, ScrollAnimatedWithDelay) {
begin_frame_args.sequence_number++;
host_impl_->WillBeginImplFrame(begin_frame_args);
host_impl_->UpdateAnimationState(true);
- EXPECT_EQ(gfx::ScrollOffset(), scrolling_layer->CurrentScrollOffset());
+ EXPECT_NE(gfx::ScrollOffset(), scrolling_layer->CurrentScrollOffset());
host_impl_->DidFinishImplFrame();
- // Second tick after 50ms, animation should be half way done since
- // the duration due to delay is 100ms.
- begin_frame_args.frame_time =
- start_time + base::TimeDelta::FromMilliseconds(50);
+ // Second tick after 50ms, animation should be half way done since the
+ // duration due to delay is 100ms. Subtract off the frame interval since we
+ // progress a full frame on the first tick.
+ base::TimeTicks half_way_time = start_time - begin_frame_args.interval +
+ base::TimeDelta::FromMilliseconds(50);
+ begin_frame_args.frame_time = half_way_time;
begin_frame_args.sequence_number++;
host_impl_->WillBeginImplFrame(begin_frame_args);
host_impl_->UpdateAnimationState(true);
@@ -10950,7 +11004,7 @@ TEST_F(LayerTreeHostImplTimelinesTest, ScrollAnimatedAborted) {
EXPECT_TRUE(GetImplAnimationHost()->HasAnyAnimationTargetingProperty(
scrolling_layer->element_id(), TargetProperty::SCROLL_OFFSET));
- EXPECT_EQ(gfx::ScrollOffset(), scrolling_layer->CurrentScrollOffset());
+ EXPECT_NE(gfx::ScrollOffset(), scrolling_layer->CurrentScrollOffset());
host_impl_->DidFinishImplFrame();
begin_frame_args.frame_time =
@@ -11019,7 +11073,7 @@ TEST_F(LayerTreeHostImplTimelinesTest, ScrollAnimated) {
host_impl_->Animate();
host_impl_->UpdateAnimationState(true);
- EXPECT_EQ(gfx::ScrollOffset(), scrolling_layer->CurrentScrollOffset());
+ EXPECT_NE(gfx::ScrollOffset(), scrolling_layer->CurrentScrollOffset());
host_impl_->DidFinishImplFrame();
begin_frame_args.frame_time =
@@ -11255,7 +11309,7 @@ TEST_F(LayerTreeHostImplTimelinesTest, ScrollAnimatedNotUserScrollable) {
host_impl_->Animate();
host_impl_->UpdateAnimationState(true);
- EXPECT_EQ(gfx::ScrollOffset(), scrolling_layer->CurrentScrollOffset());
+ EXPECT_NE(gfx::ScrollOffset(), scrolling_layer->CurrentScrollOffset());
host_impl_->DidFinishImplFrame();
begin_frame_args.frame_time =
@@ -11706,13 +11760,22 @@ TEST_F(LayerTreeHostImplTest, GpuRasterizationStatusTrigger) {
// Tests that SetContentIsSuitableForGpuRasterization behaves as expected.
TEST_F(LayerTreeHostImplTest, GpuRasterizationStatusSuitability) {
+ std::unique_ptr<TestWebGraphicsContext3D> context_with_msaa =
+ TestWebGraphicsContext3D::Create();
+ context_with_msaa->SetMaxSamples(4);
+ context_with_msaa->set_gpu_rasterization(true);
+ LayerTreeSettings msaaSettings = DefaultSettings();
+ msaaSettings.gpu_rasterization_msaa_sample_count = 4;
+ EXPECT_TRUE(CreateHostImpl(msaaSettings, FakeCompositorFrameSink::Create3d(
+ std::move(context_with_msaa))));
+
// Set initial state, before varying GPU rasterization suitability.
host_impl_->SetHasGpuRasterizationTrigger(true);
host_impl_->SetContentIsSuitableForGpuRasterization(false);
host_impl_->CommitComplete();
- EXPECT_EQ(GpuRasterizationStatus::OFF_CONTENT,
+ EXPECT_EQ(GpuRasterizationStatus::MSAA_CONTENT,
host_impl_->gpu_rasterization_status());
- EXPECT_FALSE(host_impl_->use_gpu_rasterization());
+ EXPECT_TRUE(host_impl_->use_msaa());
// Toggle suitability on.
host_impl_->SetContentIsSuitableForGpuRasterization(true);
@@ -11724,10 +11787,10 @@ TEST_F(LayerTreeHostImplTest, GpuRasterizationStatusSuitability) {
// And off.
host_impl_->SetContentIsSuitableForGpuRasterization(false);
host_impl_->CommitComplete();
- EXPECT_EQ(GpuRasterizationStatus::OFF_CONTENT,
+ EXPECT_EQ(GpuRasterizationStatus::MSAA_CONTENT,
host_impl_->gpu_rasterization_status());
- EXPECT_FALSE(host_impl_->use_gpu_rasterization());
- EXPECT_FALSE(host_impl_->use_msaa());
+ EXPECT_TRUE(host_impl_->use_gpu_rasterization());
+ EXPECT_TRUE(host_impl_->use_msaa());
}
// Tests that SetDeviceScaleFactor correctly impacts GPU rasterization.
@@ -11746,9 +11809,8 @@ TEST_F(LayerTreeHostImplTest, GpuRasterizationStatusDeviceScaleFactor) {
host_impl_->SetHasGpuRasterizationTrigger(true);
host_impl_->SetContentIsSuitableForGpuRasterization(false);
host_impl_->CommitComplete();
- EXPECT_EQ(GpuRasterizationStatus::OFF_CONTENT,
- host_impl_->gpu_rasterization_status());
- EXPECT_FALSE(host_impl_->use_gpu_rasterization());
+ EXPECT_EQ(GpuRasterizationStatus::ON, host_impl_->gpu_rasterization_status());
+ EXPECT_TRUE(host_impl_->use_gpu_rasterization());
// Set device scale factor to 2, which lowers the required MSAA samples from
// 8 to 4.
@@ -11762,9 +11824,8 @@ TEST_F(LayerTreeHostImplTest, GpuRasterizationStatusDeviceScaleFactor) {
// Set device scale factor back to 1.
host_impl_->active_tree()->SetDeviceScaleFactor(1.0f);
host_impl_->CommitComplete();
- EXPECT_EQ(GpuRasterizationStatus::OFF_CONTENT,
- host_impl_->gpu_rasterization_status());
- EXPECT_FALSE(host_impl_->use_gpu_rasterization());
+ EXPECT_EQ(GpuRasterizationStatus::ON, host_impl_->gpu_rasterization_status());
+ EXPECT_TRUE(host_impl_->use_gpu_rasterization());
EXPECT_FALSE(host_impl_->use_msaa());
}
@@ -11850,40 +11911,14 @@ TEST_F(MsaaIsSlowLayerTreeHostImplTest, GpuRasterizationStatusMsaaIsSlow) {
EXPECT_TRUE(host_impl_->use_gpu_rasterization());
// Ensure that with the msaa_is_slow cap we don't raster unsuitable content
- // with msaa.
+ // with msaa (we'll still use GPU raster, though).
CreateHostImplWithMsaaIsSlow(true);
host_impl_->SetHasGpuRasterizationTrigger(true);
host_impl_->SetContentIsSuitableForGpuRasterization(false);
host_impl_->CommitComplete();
- EXPECT_EQ(GpuRasterizationStatus::OFF_CONTENT,
- host_impl_->gpu_rasterization_status());
- EXPECT_FALSE(host_impl_->use_gpu_rasterization());
-}
-
-// A mock output surface which lets us detect calls to ForceReclaimResources.
-class MockReclaimResourcesCompositorFrameSink : public FakeCompositorFrameSink {
- public:
- MockReclaimResourcesCompositorFrameSink()
- : FakeCompositorFrameSink(TestContextProvider::Create(),
- TestContextProvider::CreateWorker()) {}
-
- MOCK_METHOD0(ForceReclaimResources, void());
-};
-
-// Display::Draw (and the planned Display Scheduler) currently rely on resources
-// being reclaimed to block drawing between BeginCommit / Swap. This test
-// ensures that BeginCommit triggers ForceReclaimResources. See
-// crbug.com/489515.
-TEST_F(LayerTreeHostImplTest, BeginCommitReclaimsResources) {
- auto compositor_frame_sink =
- base::MakeUnique<MockReclaimResourcesCompositorFrameSink>();
- // Hold an unowned pointer to the output surface to use for mock expectations.
- MockReclaimResourcesCompositorFrameSink* mock_compositor_frame_sink =
- compositor_frame_sink.get();
-
- CreateHostImpl(DefaultSettings(), std::move(compositor_frame_sink));
- EXPECT_CALL(*mock_compositor_frame_sink, ForceReclaimResources()).Times(1);
- host_impl_->BeginCommit();
+ EXPECT_EQ(GpuRasterizationStatus::ON, host_impl_->gpu_rasterization_status());
+ EXPECT_TRUE(host_impl_->use_gpu_rasterization());
+ EXPECT_FALSE(host_impl_->use_msaa());
}
TEST_F(LayerTreeHostImplTest, UpdatePageScaleFactorOnActiveTree) {
@@ -12093,12 +12128,14 @@ void LayerTreeHostImplTest::SetupMouseMoveAtTestScrollbarStates(
// scrollbar_1 on root scroll.
std::unique_ptr<SolidColorScrollbarLayerImpl> scrollbar_1 =
SolidColorScrollbarLayerImpl::Create(host_impl_->active_tree(),
- scrollbar_1_id, VERTICAL, 5, 5, true,
- true);
- scrollbar_1->SetScrollLayerId(root_scroll->id());
+ scrollbar_1_id, VERTICAL, 15, 0,
+ true, true);
+ scrollbar_1->SetScrollElementId(root_scroll->element_id());
scrollbar_1->SetDrawsContent(true);
scrollbar_1->SetBounds(scrollbar_size_1);
scrollbar_1->SetTouchEventHandlerRegion(gfx::Rect(scrollbar_size_1));
+ scrollbar_1->SetCurrentPos(0);
+ scrollbar_1->SetPosition(gfx::PointF(0, 0));
host_impl_->active_tree()
->InnerViewportContainerLayer()
->test_properties()
@@ -12111,46 +12148,81 @@ void LayerTreeHostImplTest::SetupMouseMoveAtTestScrollbarStates(
host_impl_->active_tree()->UpdateDrawProperties(false);
ScrollbarAnimationController* scrollbar_1_animation_controller =
- host_impl_->ScrollbarAnimationControllerForId(root_scroll->id());
+ host_impl_->ScrollbarAnimationControllerForElementId(
+ root_scroll->element_id());
EXPECT_TRUE(scrollbar_1_animation_controller);
- const float kMouseDistanceToTriggerAnimation =
+ const float kMouseMoveDistanceToTriggerFadeIn =
+ ScrollbarAnimationController::kMouseMoveDistanceToTriggerFadeIn;
+
+ const float kMouseMoveDistanceToTriggerExpand =
SingleScrollbarAnimationControllerThinning::
- kDefaultMouseMoveDistanceToTriggerAnimation;
+ kMouseMoveDistanceToTriggerExpand;
// Mouse moves close to the scrollbar, goes over the scrollbar, and
// moves back to where it was.
host_impl_->MouseMoveAt(
- gfx::Point(15 + kMouseDistanceToTriggerAnimation, 150));
+ gfx::Point(15 + kMouseMoveDistanceToTriggerFadeIn, 0));
EXPECT_FALSE(
scrollbar_1_animation_controller->MouseIsNearScrollbar(VERTICAL));
EXPECT_FALSE(
- scrollbar_1_animation_controller->MouseIsOverScrollbar(VERTICAL));
+ scrollbar_1_animation_controller->MouseIsNearScrollbarThumb(VERTICAL));
+ EXPECT_FALSE(
+ scrollbar_1_animation_controller->MouseIsOverScrollbarThumb(VERTICAL));
+
+ host_impl_->MouseMoveAt(
+ gfx::Point(15 + kMouseMoveDistanceToTriggerExpand, 0));
+ EXPECT_TRUE(scrollbar_1_animation_controller->MouseIsNearScrollbar(VERTICAL));
+ EXPECT_FALSE(
+ scrollbar_1_animation_controller->MouseIsNearScrollbarThumb(VERTICAL));
+ EXPECT_FALSE(
+ scrollbar_1_animation_controller->MouseIsOverScrollbarThumb(VERTICAL));
+
host_impl_->MouseMoveAt(
- gfx::Point(14 + kMouseDistanceToTriggerAnimation, 150));
+ gfx::Point(14 + kMouseMoveDistanceToTriggerExpand, 0));
EXPECT_TRUE(scrollbar_1_animation_controller->MouseIsNearScrollbar(VERTICAL));
+ EXPECT_TRUE(
+ scrollbar_1_animation_controller->MouseIsNearScrollbarThumb(VERTICAL));
EXPECT_FALSE(
- scrollbar_1_animation_controller->MouseIsOverScrollbar(VERTICAL));
- host_impl_->MouseMoveAt(gfx::Point(10, 150));
+ scrollbar_1_animation_controller->MouseIsOverScrollbarThumb(VERTICAL));
+
+ host_impl_->MouseMoveAt(gfx::Point(10, 0));
EXPECT_TRUE(scrollbar_1_animation_controller->MouseIsNearScrollbar(VERTICAL));
- EXPECT_TRUE(scrollbar_1_animation_controller->MouseIsOverScrollbar(VERTICAL));
+ EXPECT_TRUE(
+ scrollbar_1_animation_controller->MouseIsNearScrollbarThumb(VERTICAL));
+ EXPECT_TRUE(
+ scrollbar_1_animation_controller->MouseIsOverScrollbarThumb(VERTICAL));
+
host_impl_->MouseMoveAt(
- gfx::Point(14 + kMouseDistanceToTriggerAnimation, 150));
+ gfx::Point(14 + kMouseMoveDistanceToTriggerExpand, 0));
EXPECT_TRUE(scrollbar_1_animation_controller->MouseIsNearScrollbar(VERTICAL));
+ EXPECT_TRUE(
+ scrollbar_1_animation_controller->MouseIsNearScrollbarThumb(VERTICAL));
EXPECT_FALSE(
- scrollbar_1_animation_controller->MouseIsOverScrollbar(VERTICAL));
+ scrollbar_1_animation_controller->MouseIsOverScrollbarThumb(VERTICAL));
+
host_impl_->MouseMoveAt(
- gfx::Point(15 + kMouseDistanceToTriggerAnimation, 150));
+ gfx::Point(15 + kMouseMoveDistanceToTriggerExpand, 0));
+ EXPECT_TRUE(scrollbar_1_animation_controller->MouseIsNearScrollbar(VERTICAL));
+ EXPECT_FALSE(
+ scrollbar_1_animation_controller->MouseIsNearScrollbarThumb(VERTICAL));
+ EXPECT_FALSE(
+ scrollbar_1_animation_controller->MouseIsOverScrollbarThumb(VERTICAL));
+
+ host_impl_->MouseMoveAt(
+ gfx::Point(15 + kMouseMoveDistanceToTriggerFadeIn, 0));
EXPECT_FALSE(
scrollbar_1_animation_controller->MouseIsNearScrollbar(VERTICAL));
EXPECT_FALSE(
- scrollbar_1_animation_controller->MouseIsOverScrollbar(VERTICAL));
+ scrollbar_1_animation_controller->MouseIsNearScrollbarThumb(VERTICAL));
+ EXPECT_FALSE(
+ scrollbar_1_animation_controller->MouseIsOverScrollbarThumb(VERTICAL));
// scrollbar_2 on child.
std::unique_ptr<SolidColorScrollbarLayerImpl> scrollbar_2 =
SolidColorScrollbarLayerImpl::Create(host_impl_->active_tree(),
- scrollbar_2_id, VERTICAL, 5, 5, true,
- true);
+ scrollbar_2_id, VERTICAL, 15, 0,
+ true, true);
std::unique_ptr<LayerImpl> child_clip =
LayerImpl::Create(host_impl_->active_tree(), child_clip_id);
std::unique_ptr<LayerImpl> child =
@@ -12160,15 +12232,18 @@ void LayerTreeHostImplTest::SetupMouseMoveAtTestScrollbarStates(
child->SetDrawsContent(true);
child->SetScrollClipLayer(child_clip_id);
child->SetElementId(LayerIdToElementIdForTesting(child->id()));
+ ElementId child_element_id = child->element_id();
if (main_thread_scrolling) {
child->set_main_thread_scrolling_reasons(
MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects);
}
- scrollbar_2->SetScrollLayerId(child_scroll_id);
+ scrollbar_2->SetScrollElementId(child_element_id);
scrollbar_2->SetDrawsContent(true);
scrollbar_2->SetBounds(scrollbar_size_2);
+ scrollbar_2->SetCurrentPos(0);
+ scrollbar_2->SetPosition(gfx::PointF(0, 0));
child->test_properties()->AddChild(std::move(scrollbar_2));
child_clip->test_properties()->AddChild(std::move(child));
@@ -12178,50 +12253,70 @@ void LayerTreeHostImplTest::SetupMouseMoveAtTestScrollbarStates(
host_impl_->active_tree()->DidBecomeActive();
ScrollbarAnimationController* scrollbar_2_animation_controller =
- host_impl_->ScrollbarAnimationControllerForId(child_scroll_id);
+ host_impl_->ScrollbarAnimationControllerForElementId(child_element_id);
EXPECT_TRUE(scrollbar_2_animation_controller);
// Mouse goes over scrollbar_2, moves close to scrollbar_2, moves close to
// scrollbar_1, goes over scrollbar_1.
- host_impl_->MouseMoveAt(gfx::Point(60, 150));
+ host_impl_->MouseMoveAt(gfx::Point(60, 60));
EXPECT_FALSE(
scrollbar_1_animation_controller->MouseIsNearScrollbar(VERTICAL));
EXPECT_FALSE(
- scrollbar_1_animation_controller->MouseIsOverScrollbar(VERTICAL));
+ scrollbar_1_animation_controller->MouseIsNearScrollbarThumb(VERTICAL));
+ EXPECT_FALSE(
+ scrollbar_1_animation_controller->MouseIsOverScrollbarThumb(VERTICAL));
EXPECT_TRUE(scrollbar_2_animation_controller->MouseIsNearScrollbar(VERTICAL));
- EXPECT_TRUE(scrollbar_2_animation_controller->MouseIsOverScrollbar(VERTICAL));
+ EXPECT_TRUE(
+ scrollbar_2_animation_controller->MouseIsNearScrollbarThumb(VERTICAL));
+ EXPECT_TRUE(
+ scrollbar_2_animation_controller->MouseIsOverScrollbarThumb(VERTICAL));
+
host_impl_->MouseMoveAt(
- gfx::Point(64 + kMouseDistanceToTriggerAnimation, 150));
+ gfx::Point(64 + kMouseMoveDistanceToTriggerExpand, 50));
EXPECT_FALSE(
scrollbar_1_animation_controller->MouseIsNearScrollbar(VERTICAL));
EXPECT_FALSE(
- scrollbar_1_animation_controller->MouseIsOverScrollbar(VERTICAL));
+ scrollbar_1_animation_controller->MouseIsNearScrollbarThumb(VERTICAL));
+ EXPECT_FALSE(
+ scrollbar_1_animation_controller->MouseIsOverScrollbarThumb(VERTICAL));
EXPECT_TRUE(scrollbar_2_animation_controller->MouseIsNearScrollbar(VERTICAL));
+ EXPECT_TRUE(
+ scrollbar_2_animation_controller->MouseIsNearScrollbarThumb(VERTICAL));
EXPECT_FALSE(
- scrollbar_2_animation_controller->MouseIsOverScrollbar(VERTICAL));
+ scrollbar_2_animation_controller->MouseIsOverScrollbarThumb(VERTICAL));
host_impl_->MouseMoveAt(
- gfx::Point(14 + kMouseDistanceToTriggerAnimation, 150));
+ gfx::Point(14 + kMouseMoveDistanceToTriggerExpand, 0));
EXPECT_TRUE(scrollbar_1_animation_controller->MouseIsNearScrollbar(VERTICAL));
+ EXPECT_TRUE(
+ scrollbar_1_animation_controller->MouseIsNearScrollbarThumb(VERTICAL));
EXPECT_FALSE(
- scrollbar_1_animation_controller->MouseIsOverScrollbar(VERTICAL));
+ scrollbar_1_animation_controller->MouseIsOverScrollbarThumb(VERTICAL));
EXPECT_FALSE(
scrollbar_2_animation_controller->MouseIsNearScrollbar(VERTICAL));
EXPECT_FALSE(
- scrollbar_2_animation_controller->MouseIsOverScrollbar(VERTICAL));
- host_impl_->MouseMoveAt(gfx::Point(10, 150));
+ scrollbar_2_animation_controller->MouseIsNearScrollbarThumb(VERTICAL));
+ EXPECT_FALSE(
+ scrollbar_2_animation_controller->MouseIsOverScrollbarThumb(VERTICAL));
+ host_impl_->MouseMoveAt(gfx::Point(10, 0));
EXPECT_TRUE(scrollbar_1_animation_controller->MouseIsNearScrollbar(VERTICAL));
- EXPECT_TRUE(scrollbar_1_animation_controller->MouseIsOverScrollbar(VERTICAL));
+ EXPECT_TRUE(
+ scrollbar_1_animation_controller->MouseIsNearScrollbarThumb(VERTICAL));
+ EXPECT_TRUE(
+ scrollbar_1_animation_controller->MouseIsOverScrollbarThumb(VERTICAL));
EXPECT_FALSE(
scrollbar_2_animation_controller->MouseIsNearScrollbar(VERTICAL));
EXPECT_FALSE(
- scrollbar_2_animation_controller->MouseIsOverScrollbar(VERTICAL));
+ scrollbar_2_animation_controller->MouseIsNearScrollbarThumb(VERTICAL));
+ EXPECT_FALSE(
+ scrollbar_2_animation_controller->MouseIsOverScrollbarThumb(VERTICAL));
// Capture scrollbar_1, then move mouse to scrollbar_2's layer, should post an
// event to fade out scrollbar_1.
+ scrollbar_1_animation_controller->DidScrollUpdate();
animation_task_ = base::Closure();
host_impl_->MouseDown();
- host_impl_->MouseMoveAt(gfx::Point(100, 150));
+ host_impl_->MouseMoveAt(gfx::Point(60, 50));
host_impl_->MouseUp();
EXPECT_FALSE(animation_task_.Equals(base::Closure()));
@@ -12239,17 +12334,17 @@ void LayerTreeHostImplTest::SetupMouseMoveAtTestScrollbarStates(
// scrollbar_2_animation_controller, then mouse up should not cause crash.
host_impl_->MouseMoveAt(gfx::Point(40, 150));
host_impl_->MouseDown();
- host_impl_->UnregisterScrollbarAnimationController(root_scroll->id());
+ host_impl_->UnregisterScrollbarAnimationController(root_scroll->element_id());
host_impl_->MouseUp();
}
TEST_F(LayerTreeHostImplTest,
- LayerTreeHostImplTestScrollbarStatesInMainThreadScorlling) {
+ LayerTreeHostImplTestScrollbarStatesInMainThreadScrolling) {
SetupMouseMoveAtTestScrollbarStates(true);
}
TEST_F(LayerTreeHostImplTest,
- LayerTreeHostImplTestScrollbarStatesInNotMainThreadScorlling) {
+ LayerTreeHostImplTestScrollbarStatesInNotMainThreadScrolling) {
SetupMouseMoveAtTestScrollbarStates(false);
}
@@ -12263,9 +12358,8 @@ TEST_F(LayerTreeHostImplTest, CheckerImagingTileInvalidation) {
std::unique_ptr<FakeRecordingSource> recording_source =
FakeRecordingSource::CreateFilledRecordingSource(layer_size);
- recording_source->SetGenerateDiscardableImagesMetadata(true);
- sk_sp<SkImage> checkerable_image =
- CreateDiscardableImage(gfx::Size(500, 500));
+ PaintImage checkerable_image = PaintImage(
+ PaintImage::GetNextId(), CreateDiscardableImage(gfx::Size(500, 500)));
recording_source->add_draw_image(checkerable_image, gfx::Point(0, 0));
SkColor non_solid_color = SkColorSetARGB(128, 45, 56, 67);
@@ -12325,9 +12419,22 @@ TEST_F(LayerTreeHostImplTest, CheckerImagingTileInvalidation) {
EXPECT_FALSE(tile->HasRasterTask());
}
Region expected_invalidation(
- raster_source->GetRectForImage(checkerable_image->uniqueID()));
+ raster_source->GetRectForImage(checkerable_image.stable_id()));
EXPECT_EQ(expected_invalidation, *(root->GetPendingInvalidation()));
}
+TEST_F(LayerTreeHostImplTest, RasterColorSpaceNoColorCorrection) {
+ LayerTreeSettings settings = DefaultSettings();
+ CreateHostImpl(settings, CreateCompositorFrameSink());
+ EXPECT_FALSE(host_impl_->GetRasterColorSpace().IsValid());
+}
+
+TEST_F(LayerTreeHostImplTest, RasterColorSpace) {
+ LayerTreeSettings settings = DefaultSettings();
+ settings.enable_color_correct_rasterization = true;
+ CreateHostImpl(settings, CreateCompositorFrameSink());
+ EXPECT_EQ(host_impl_->GetRasterColorSpace(), gfx::ColorSpace::CreateSRGB());
+}
+
} // namespace
} // namespace cc
diff --git a/chromium/cc/trees/layer_tree_host_perftest.cc b/chromium/cc/trees/layer_tree_host_perftest.cc
index ff17af70317..7649a527fa2 100644
--- a/chromium/cc/trees/layer_tree_host_perftest.cc
+++ b/chromium/cc/trees/layer_tree_host_perftest.cc
@@ -23,6 +23,7 @@
#include "cc/test/layer_tree_json_parser.h"
#include "cc/test/layer_tree_test.h"
#include "cc/test/paths.h"
+#include "cc/test/test_compositor_frame_sink.h"
#include "cc/trees/layer_tree_impl.h"
#include "testing/perf/perf_test.h"
@@ -45,12 +46,18 @@ class LayerTreeHostPerfTest : public LayerTreeTest {
measure_commit_cost_(false) {
}
- void InitializeSettings(LayerTreeSettings* settings) override {
- // LayerTreeTests give the Display's BeginFrameSource directly to the
- // LayerTreeHost like we do in the Browser process via
- // TestDelegatingOutputSurface, so setting disable_display_vsync here
- // unthrottles both the DisplayScheduler and the Scheduler.
- settings->renderer_settings.disable_display_vsync = true;
+ std::unique_ptr<TestCompositorFrameSink> CreateCompositorFrameSink(
+ scoped_refptr<ContextProvider> compositor_context_provider,
+ scoped_refptr<ContextProvider> worker_context_provider) override {
+ constexpr bool disable_display_vsync = true;
+ bool synchronous_composite =
+ !HasImplThread() &&
+ !layer_tree_host()->GetSettings().single_thread_proxy_scheduler;
+ return base::MakeUnique<TestCompositorFrameSink>(
+ compositor_context_provider, std::move(worker_context_provider),
+ shared_bitmap_manager(), gpu_memory_buffer_manager(),
+ layer_tree_host()->GetSettings().renderer_settings,
+ ImplThreadTaskRunner(), synchronous_composite, disable_display_vsync);
}
void BeginTest() override {
@@ -149,13 +156,25 @@ class LayerTreeHostPerfTestJsonReader : public LayerTreeHostPerfTest {
};
// Simulates a tab switcher scene with two stacks of 10 tabs each.
-TEST_F(LayerTreeHostPerfTestJsonReader, TenTenSingleThread) {
+// Timed out on Android: http://crbug.com/723821
+#if defined(OS_ANDROID)
+#define MAYBE_TenTenSingleThread DISABLED_TenTenSingleThread
+#else
+#define MAYBE_TenTenSingleThread TenTenSingleThread
+#endif
+TEST_F(LayerTreeHostPerfTestJsonReader, MAYBE_TenTenSingleThread) {
SetTestName("10_10_single_thread");
ReadTestFile("10_10_layer_tree");
RunTest(CompositorMode::SINGLE_THREADED);
}
-TEST_F(LayerTreeHostPerfTestJsonReader, TenTenThreaded) {
+// Timed out on Android: http://crbug.com/723821
+#if defined(OS_ANDROID)
+#define MAYBE_TenTenThreaded DISABLED_TenTenThreaded
+#else
+#define MAYBE_TenTenThreaded TenTenThreaded
+#endif
+TEST_F(LayerTreeHostPerfTestJsonReader, MAYBE_TenTenThreaded) {
SetTestName("10_10_threaded_impl_side");
ReadTestFile("10_10_layer_tree");
RunTest(CompositorMode::THREADED);
@@ -211,7 +230,8 @@ TEST_F(LayerTreeHostPerfTestLeafInvalidates, TenTenSingleThread) {
RunTest(CompositorMode::SINGLE_THREADED);
}
-TEST_F(LayerTreeHostPerfTestLeafInvalidates, TenTenThreaded) {
+// Timed out on Android: http://crbug.com/723821
+TEST_F(LayerTreeHostPerfTestLeafInvalidates, MAYBE_TenTenThreaded) {
SetTestName("10_10_threaded_impl_side_leaf_invalidates");
ReadTestFile("10_10_layer_tree");
RunTest(CompositorMode::THREADED);
@@ -242,13 +262,26 @@ class ScrollingLayerTreePerfTest : public LayerTreeHostPerfTestJsonReader {
scoped_refptr<Layer> scrollable_;
};
-TEST_F(ScrollingLayerTreePerfTest, LongScrollablePageSingleThread) {
+// Timed out on Android: http://crbug.com/723821
+#if defined(OS_ANDROID)
+#define MAYBE_LongScrollablePageSingleThread \
+ DISABLED_LongScrollablePageSingleThread
+#else
+#define MAYBE_LongScrollablePageSingleThread LongScrollablePageSingleThread
+#endif
+TEST_F(ScrollingLayerTreePerfTest, MAYBE_LongScrollablePageSingleThread) {
SetTestName("long_scrollable_page");
ReadTestFile("long_scrollable_page");
RunTest(CompositorMode::SINGLE_THREADED);
}
-TEST_F(ScrollingLayerTreePerfTest, LongScrollablePageThreaded) {
+// Timed out on Android: http://crbug.com/723821
+#if defined(OS_ANDROID)
+#define MAYBE_LongScrollablePageThreaded DISABLED_LongScrollablePageThreaded
+#else
+#define MAYBE_LongScrollablePageThreaded LongScrollablePageThreaded
+#endif
+TEST_F(ScrollingLayerTreePerfTest, MAYBE_LongScrollablePageThreaded) {
SetTestName("long_scrollable_page_threaded_impl_side");
ReadTestFile("long_scrollable_page");
RunTest(CompositorMode::THREADED);
@@ -343,7 +376,13 @@ TEST_F(BrowserCompositorInvalidateLayerTreePerfTest, DenseBrowserUIThreaded) {
}
// Simulates a page with several large, transformed and animated layers.
-TEST_F(LayerTreeHostPerfTestJsonReader, HeavyPageThreaded) {
+// Timed out on Android: http://crbug.com/723821
+#if defined(OS_ANDROID)
+#define MAYBE_HeavyPageThreaded DISABLED_HeavyPageThreaded
+#else
+#define MAYBE_HeavyPageThreaded HeavyPageThreaded
+#endif
+TEST_F(LayerTreeHostPerfTestJsonReader, MAYBE_HeavyPageThreaded) {
begin_frame_driven_drawing_ = true;
measure_commit_cost_ = true;
SetTestName("heavy_page");
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_blending.cc b/chromium/cc/trees/layer_tree_host_pixeltest_blending.cc
index 05f94594ae4..656d2922e02 100644
--- a/chromium/cc/trees/layer_tree_host_pixeltest_blending.cc
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_blending.cc
@@ -6,6 +6,7 @@
#include "cc/layers/picture_image_layer.h"
#include "cc/layers/solid_color_layer.h"
+#include "cc/paint/paint_image.h"
#include "cc/test/layer_tree_pixel_resource_test.h"
#include "cc/test/pixel_comparator.h"
#include "third_party/skia/include/core/SkImage.h"
@@ -145,7 +146,8 @@ class LayerTreeHostBlendingPixelTest : public LayerTreeHostPixelResourceTest {
scoped_refptr<PictureImageLayer> layer = PictureImageLayer::Create();
layer->SetIsDrawable(true);
layer->SetBounds(gfx::Size(width, height));
- layer->SetImage(backing_store->makeImageSnapshot());
+ layer->SetImage(PaintImage(PaintImage::GetNextId(),
+ backing_store->makeImageSnapshot()));
return layer;
}
@@ -167,7 +169,8 @@ class LayerTreeHostBlendingPixelTest : public LayerTreeHostPixelResourceTest {
bounds.width() - kMaskOffset * 2,
bounds.height() - kMaskOffset * 2),
paint);
- mask->SetImage(surface->makeImageSnapshot());
+ mask->SetImage(
+ PaintImage(PaintImage::GetNextId(), surface->makeImageSnapshot()));
layer->SetMaskLayer(mask.get());
}
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc b/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc
index eed99f6a625..1d1d70b2cdd 100644
--- a/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_masks.cc
@@ -11,7 +11,9 @@
#include "cc/layers/solid_color_layer.h"
#include "cc/paint/drawing_display_item.h"
#include "cc/paint/paint_flags.h"
+#include "cc/paint/paint_image.h"
#include "cc/paint/paint_recorder.h"
+#include "cc/test/fake_picture_layer.h"
#include "cc/test/layer_tree_pixel_resource_test.h"
#include "cc/test/pixel_comparator.h"
#include "cc/test/solid_color_content_layer_client.h"
@@ -40,7 +42,7 @@ class MaskContentLayerClient : public ContentLayerClient {
PaintingControlSetting picture_control) override {
PaintRecorder recorder;
PaintCanvas* canvas =
- recorder.beginRecording(gfx::RectToSkRect(gfx::Rect(bounds_)));
+ recorder.beginRecording(gfx::RectToSkRect(PaintableRegion()));
PaintFlags flags;
flags.setStyle(PaintFlags::kStroke_Style);
@@ -60,7 +62,8 @@ class MaskContentLayerClient : public ContentLayerClient {
auto display_list = make_scoped_refptr(new DisplayItemList);
display_list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
- PaintableRegion(), recorder.finishRecordingAsPicture());
+ PaintableRegion(), recorder.finishRecordingAsPicture(),
+ gfx::RectToSkRect(PaintableRegion()));
display_list->Finalize();
return display_list;
@@ -71,8 +74,8 @@ class MaskContentLayerClient : public ContentLayerClient {
};
TEST_P(LayerTreeHostMasksPixelTest, MaskOfLayer) {
- scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
- gfx::Rect(100, 100), SK_ColorWHITE);
+ scoped_refptr<SolidColorLayer> background =
+ CreateSolidColorLayer(gfx::Rect(100, 100), SK_ColorWHITE);
scoped_refptr<SolidColorLayer> green = CreateSolidColorLayerWithBorder(
gfx::Rect(25, 25, 50, 50), kCSSGreen, 1, SK_ColorBLACK);
@@ -83,7 +86,7 @@ TEST_P(LayerTreeHostMasksPixelTest, MaskOfLayer) {
scoped_refptr<PictureLayer> mask = PictureLayer::Create(&client);
mask->SetBounds(mask_bounds);
mask->SetIsDrawable(true);
- mask->SetLayerMaskType(Layer::LayerMaskType::MULTI_TEXTURE_MASK);
+ mask->SetLayerMaskType(mask_type_);
green->SetMaskLayer(mask.get());
RunPixelResourceTest(background,
@@ -91,14 +94,14 @@ TEST_P(LayerTreeHostMasksPixelTest, MaskOfLayer) {
}
TEST_P(LayerTreeHostMasksPixelTest, ImageMaskOfLayer) {
- scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
- gfx::Rect(100, 100), SK_ColorWHITE);
+ scoped_refptr<SolidColorLayer> background =
+ CreateSolidColorLayer(gfx::Rect(100, 100), SK_ColorWHITE);
gfx::Size mask_bounds(50, 50);
scoped_refptr<PictureImageLayer> mask = PictureImageLayer::Create();
mask->SetIsDrawable(true);
- mask->SetLayerMaskType(Layer::LayerMaskType::MULTI_TEXTURE_MASK);
+ mask->SetLayerMaskType(mask_type_);
mask->SetBounds(mask_bounds);
sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(200, 200);
@@ -108,8 +111,9 @@ TEST_P(LayerTreeHostMasksPixelTest, ImageMaskOfLayer) {
scoped_refptr<DisplayItemList> mask_display_list =
client.PaintContentsToDisplayList(
ContentLayerClient::PAINTING_BEHAVIOR_NORMAL);
- mask_display_list->Raster(canvas, nullptr);
- mask->SetImage(surface->makeImageSnapshot());
+ mask_display_list->Raster(canvas);
+ mask->SetImage(
+ PaintImage(PaintImage::GetNextId(), surface->makeImageSnapshot()));
scoped_refptr<SolidColorLayer> green = CreateSolidColorLayerWithBorder(
gfx::Rect(25, 25, 50, 50), kCSSGreen, 1, SK_ColorBLACK);
@@ -121,8 +125,8 @@ TEST_P(LayerTreeHostMasksPixelTest, ImageMaskOfLayer) {
}
TEST_P(LayerTreeHostMasksPixelTest, MaskOfClippedLayer) {
- scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
- gfx::Rect(100, 100), SK_ColorWHITE);
+ scoped_refptr<SolidColorLayer> background =
+ CreateSolidColorLayer(gfx::Rect(100, 100), SK_ColorWHITE);
// Clip to the top half of the green layer.
scoped_refptr<Layer> clip = Layer::Create();
@@ -140,7 +144,7 @@ TEST_P(LayerTreeHostMasksPixelTest, MaskOfClippedLayer) {
scoped_refptr<PictureLayer> mask = PictureLayer::Create(&client);
mask->SetBounds(mask_bounds);
mask->SetIsDrawable(true);
- mask->SetLayerMaskType(Layer::LayerMaskType::MULTI_TEXTURE_MASK);
+ mask->SetLayerMaskType(mask_type_);
green->SetMaskLayer(mask.get());
RunPixelResourceTest(
@@ -148,6 +152,63 @@ TEST_P(LayerTreeHostMasksPixelTest, MaskOfClippedLayer) {
base::FilePath(FILE_PATH_LITERAL("mask_of_clipped_layer.png")));
}
+TEST_P(LayerTreeHostMasksPixelTest, MaskOfLargerLayer) {
+ scoped_refptr<SolidColorLayer> background =
+ CreateSolidColorLayer(gfx::Rect(100, 100), SK_ColorWHITE);
+
+ scoped_refptr<SolidColorLayer> green = CreateSolidColorLayerWithBorder(
+ gfx::Rect(0, 0, 100, 100), kCSSGreen, 1, SK_ColorBLACK);
+ background->AddChild(green);
+
+ gfx::Size mask_bounds(50, 50);
+ MaskContentLayerClient client(mask_bounds);
+ scoped_refptr<PictureLayer> mask = PictureLayer::Create(&client);
+ mask->SetBounds(mask_bounds);
+ mask->SetIsDrawable(true);
+ mask->SetLayerMaskType(mask_type_);
+ green->SetMaskLayer(mask.get());
+
+ if (raster_buffer_provider_type_ == RASTER_BUFFER_PROVIDER_TYPE_BITMAP) {
+ // Bitmap produces a sharper (but equivalent sized) mask.
+ float percentage_pixels_large_error = 40.0f;
+ float percentage_pixels_small_error = 0.0f;
+ float average_error_allowed_in_bad_pixels = 65.0f;
+ int large_error_allowed = 120;
+ int small_error_allowed = 0;
+ pixel_comparator_.reset(new FuzzyPixelComparator(
+ true, // discard_alpha
+ percentage_pixels_large_error, percentage_pixels_small_error,
+ average_error_allowed_in_bad_pixels, large_error_allowed,
+ small_error_allowed));
+ }
+
+ RunPixelResourceTest(
+ background,
+ base::FilePath(FILE_PATH_LITERAL("mask_of_larger_layer.png")));
+}
+
+TEST_P(LayerTreeHostMasksPixelTest, MaskOfLayerNonExactTextureSize) {
+ scoped_refptr<SolidColorLayer> background =
+ CreateSolidColorLayer(gfx::Rect(100, 100), SK_ColorWHITE);
+
+ scoped_refptr<SolidColorLayer> green = CreateSolidColorLayerWithBorder(
+ gfx::Rect(0, 0, 100, 100), kCSSGreen, 1, SK_ColorBLACK);
+ background->AddChild(green);
+
+ gfx::Size mask_bounds(100, 100);
+ MaskContentLayerClient client(mask_bounds);
+ scoped_refptr<FakePictureLayer> mask = FakePictureLayer::Create(&client);
+ mask->SetBounds(mask_bounds);
+ mask->SetIsDrawable(true);
+ mask->SetLayerMaskType(mask_type_);
+ mask->set_fixed_tile_size(gfx::Size(173, 135));
+ green->SetMaskLayer(mask.get());
+
+ RunPixelResourceTest(background,
+ base::FilePath(FILE_PATH_LITERAL(
+ "mask_with_non_exact_texture_size.png")));
+}
+
class CheckerContentLayerClient : public ContentLayerClient {
public:
CheckerContentLayerClient(const gfx::Size& bounds,
@@ -162,7 +223,7 @@ class CheckerContentLayerClient : public ContentLayerClient {
PaintingControlSetting picture_control) override {
PaintRecorder recorder;
PaintCanvas* canvas =
- recorder.beginRecording(gfx::RectToSkRect(gfx::Rect(bounds_)));
+ recorder.beginRecording(gfx::RectToSkRect(PaintableRegion()));
PaintFlags flags;
flags.setStyle(PaintFlags::kStroke_Style);
@@ -181,7 +242,8 @@ class CheckerContentLayerClient : public ContentLayerClient {
auto display_list = make_scoped_refptr(new DisplayItemList);
display_list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
- PaintableRegion(), recorder.finishRecordingAsPicture());
+ PaintableRegion(), recorder.finishRecordingAsPicture(),
+ gfx::RectToSkRect(PaintableRegion()));
display_list->Finalize();
return display_list;
@@ -205,7 +267,7 @@ class CircleContentLayerClient : public ContentLayerClient {
PaintingControlSetting picture_control) override {
PaintRecorder recorder;
PaintCanvas* canvas =
- recorder.beginRecording(gfx::RectToSkRect(gfx::Rect(bounds_)));
+ recorder.beginRecording(gfx::RectToSkRect(PaintableRegion()));
PaintFlags flags;
flags.setStyle(PaintFlags::kFill_Style);
@@ -216,7 +278,8 @@ class CircleContentLayerClient : public ContentLayerClient {
auto display_list = make_scoped_refptr(new DisplayItemList);
display_list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
- PaintableRegion(), recorder.finishRecordingAsPicture());
+ PaintableRegion(), recorder.finishRecordingAsPicture(),
+ gfx::RectToSkRect(PaintableRegion()));
display_list->Finalize();
return display_list;
@@ -229,16 +292,20 @@ class CircleContentLayerClient : public ContentLayerClient {
using LayerTreeHostMasksForBackgroundFiltersPixelTest =
ParameterizedPixelResourceTest;
-INSTANTIATE_TEST_CASE_P(PixelResourceTest,
- LayerTreeHostMasksForBackgroundFiltersPixelTest,
- ::testing::Values(SOFTWARE,
- GL_GPU_RASTER_2D_DRAW,
- GL_ONE_COPY_2D_STAGING_2D_DRAW,
- GL_ONE_COPY_RECT_STAGING_2D_DRAW,
- GL_ONE_COPY_EXTERNAL_STAGING_2D_DRAW,
- GL_ZERO_COPY_2D_DRAW,
- GL_ZERO_COPY_RECT_DRAW,
- GL_ZERO_COPY_EXTERNAL_DRAW));
+INSTANTIATE_TEST_CASE_P(
+ PixelResourceTest,
+ LayerTreeHostMasksForBackgroundFiltersPixelTest,
+ ::testing::Combine(
+ ::testing::Values(SOFTWARE,
+ GL_GPU_RASTER_2D_DRAW,
+ GL_ONE_COPY_2D_STAGING_2D_DRAW,
+ GL_ONE_COPY_RECT_STAGING_2D_DRAW,
+ GL_ONE_COPY_EXTERNAL_STAGING_2D_DRAW,
+ GL_ZERO_COPY_2D_DRAW,
+ GL_ZERO_COPY_RECT_DRAW,
+ GL_ZERO_COPY_EXTERNAL_DRAW),
+ ::testing::Values(Layer::LayerMaskType::SINGLE_TEXTURE_MASK,
+ Layer::LayerMaskType::MULTI_TEXTURE_MASK)));
TEST_P(LayerTreeHostMasksForBackgroundFiltersPixelTest,
MaskOfLayerWithBackgroundFilter) {
@@ -265,7 +332,7 @@ TEST_P(LayerTreeHostMasksForBackgroundFiltersPixelTest,
scoped_refptr<PictureLayer> mask = PictureLayer::Create(&mask_client);
mask->SetBounds(mask_bounds);
mask->SetIsDrawable(true);
- mask->SetLayerMaskType(Layer::LayerMaskType::MULTI_TEXTURE_MASK);
+ mask->SetLayerMaskType(mask_type_);
blur->SetMaskLayer(mask.get());
float percentage_pixels_large_error = 2.5f; // 2.5%, ~250px / (100*100)
@@ -316,7 +383,7 @@ TEST_P(LayerTreeHostMasksForBackgroundFiltersPixelTest,
scoped_refptr<PictureLayer> mask = PictureLayer::Create(&mask_client);
mask->SetBounds(mask_bounds);
mask->SetIsDrawable(true);
- mask->SetLayerMaskType(Layer::LayerMaskType::MULTI_TEXTURE_MASK);
+ mask->SetLayerMaskType(mask_type_);
picture_horizontal->SetMaskLayer(mask.get());
float percentage_pixels_large_error = 0.04f; // 0.04%, ~6px / (128*128)
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc b/chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc
index 9e6c405beb3..93d29ad071b 100644
--- a/chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_scrollbars.cc
@@ -88,7 +88,7 @@ TEST_F(LayerTreeHostScrollbarsPixelTest, NoScale) {
auto scrollbar = base::MakeUnique<PaintedScrollbar>();
scoped_refptr<PaintedScrollbarLayer> layer =
- PaintedScrollbarLayer::Create(std::move(scrollbar), Layer::INVALID_ID);
+ PaintedScrollbarLayer::Create(std::move(scrollbar));
layer->SetIsDrawable(true);
layer->SetBounds(gfx::Size(200, 200));
background->AddChild(layer);
@@ -107,7 +107,7 @@ TEST_F(LayerTreeHostScrollbarsPixelTest, DeviceScaleFactor) {
auto scrollbar = base::MakeUnique<PaintedScrollbar>();
scoped_refptr<PaintedScrollbarLayer> layer =
- PaintedScrollbarLayer::Create(std::move(scrollbar), Layer::INVALID_ID);
+ PaintedScrollbarLayer::Create(std::move(scrollbar));
layer->SetIsDrawable(true);
layer->SetBounds(gfx::Size(100, 100));
background->AddChild(layer);
@@ -122,7 +122,7 @@ TEST_F(LayerTreeHostScrollbarsPixelTest, TransformScale) {
auto scrollbar = base::MakeUnique<PaintedScrollbar>();
scoped_refptr<PaintedScrollbarLayer> layer =
- PaintedScrollbarLayer::Create(std::move(scrollbar), Layer::INVALID_ID);
+ PaintedScrollbarLayer::Create(std::move(scrollbar));
layer->SetIsDrawable(true);
layer->SetBounds(gfx::Size(100, 100));
background->AddChild(layer);
@@ -144,7 +144,7 @@ TEST_F(LayerTreeHostScrollbarsPixelTest, HugeTransformScale) {
auto scrollbar = base::MakeUnique<PaintedScrollbar>();
scrollbar->set_paint_scale(1);
scoped_refptr<PaintedScrollbarLayer> layer =
- PaintedScrollbarLayer::Create(std::move(scrollbar), Layer::INVALID_ID);
+ PaintedScrollbarLayer::Create(std::move(scrollbar));
layer->SetIsDrawable(true);
layer->SetBounds(gfx::Size(10, 400));
background->AddChild(layer);
@@ -239,8 +239,7 @@ TEST_F(LayerTreeHostOverlayScrollbarsPixelTest, NinePatchScrollbarScaledUp) {
auto scrollbar = base::MakeUnique<PaintedOverlayScrollbar>();
scoped_refptr<PaintedOverlayScrollbarLayer> layer =
- PaintedOverlayScrollbarLayer::Create(std::move(scrollbar),
- Layer::INVALID_ID);
+ PaintedOverlayScrollbarLayer::Create(std::move(scrollbar));
scrollbar_layer_id_ = layer->id();
thickness_scale_ = 5.f;
@@ -264,8 +263,7 @@ TEST_F(LayerTreeHostOverlayScrollbarsPixelTest, NinePatchScrollbarScaledDown) {
auto scrollbar = base::MakeUnique<PaintedOverlayScrollbar>();
scoped_refptr<PaintedOverlayScrollbarLayer> layer =
- PaintedOverlayScrollbarLayer::Create(std::move(scrollbar),
- Layer::INVALID_ID);
+ PaintedOverlayScrollbarLayer::Create(std::move(scrollbar));
scrollbar_layer_id_ = layer->id();
thickness_scale_ = 0.4f;
diff --git a/chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc b/chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc
index d6145d577c8..e2fc6d64670 100644
--- a/chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc
+++ b/chromium/cc/trees/layer_tree_host_pixeltest_tiles.cc
@@ -113,7 +113,7 @@ class BlueYellowClient : public ContentLayerClient {
PaintRecorder recorder;
PaintCanvas* canvas =
- recorder.beginRecording(gfx::RectToSkRect(gfx::Rect(size_)));
+ recorder.beginRecording(gfx::RectToSkRect(PaintableRegion()));
gfx::Rect top(0, 0, size_.width(), size_.height() / 2);
gfx::Rect bottom(0, size_.height() / 2, size_.width(), size_.height() / 2);
@@ -129,7 +129,8 @@ class BlueYellowClient : public ContentLayerClient {
canvas->drawRect(gfx::RectToSkRect(yellow_rect), flags);
display_list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
- PaintableRegion(), recorder.finishRecordingAsPicture());
+ PaintableRegion(), recorder.finishRecordingAsPicture(),
+ gfx::RectToSkRect(PaintableRegion()));
display_list->Finalize();
return display_list;
}
@@ -157,11 +158,17 @@ class LayerTreeHostTilesTestPartialInvalidation
void DidCommitAndDrawFrame() override {
switch (layer_tree_host()->SourceFrameNumber()) {
case 1:
- // We have done one frame, so the layer's content has been rastered.
- // Now we change the picture behind it to record something completely
- // different, but we give a smaller invalidation rect. The layer should
- // only re-raster the stuff in the rect. If it doesn't do partial raster
- // it would re-raster the whole thing instead.
+ // We have done one frame, but the resource may not be available for
+ // partial raster yet. Force a second frame.
+ picture_layer_->SetNeedsDisplayRect(gfx::Rect(50, 50, 100, 100));
+ break;
+ case 2:
+ // We have done two frames, so the layer's content has been rastered
+ // twice and the first frame's resource is available for partial
+ // raster. Now we change the picture behind it to record something
+ // completely different, but we give a smaller invalidation rect. The
+ // layer should only re-raster the stuff in the rect. If it doesn't do
+ // partial raster it would re-raster the whole thing instead.
client_.set_blue_top(false);
Finish();
picture_layer_->SetNeedsDisplayRect(gfx::Rect(50, 50, 100, 100));
@@ -203,30 +210,15 @@ TEST_F(LayerTreeHostTilesTestPartialInvalidation,
base::FilePath(FILE_PATH_LITERAL("blue_yellow_flipped.png")));
}
-// crbug.com/707711
-#if defined(OS_LINUX)
-#define MAYBE_PartialRaster_MultiThread_OneCopy \
- DISABLED_PartialRaster_MultiThread_OneCopy
-#else
-#define MAYBE_PartialRaster_MultiThread_OneCopy \
- PartialRaster_MultiThread_OneCopy
-#endif
TEST_F(LayerTreeHostTilesTestPartialInvalidation,
- MAYBE_PartialRaster_MultiThread_OneCopy) {
+ PartialRaster_MultiThread_OneCopy) {
RunRasterPixelTest(
true, PARTIAL_ONE_COPY, picture_layer_,
base::FilePath(FILE_PATH_LITERAL("blue_yellow_partial_flipped.png")));
}
-// crbug.com/707711
-#if defined(OS_LINUX)
-#define MAYBE_FullRaster_MultiThread_OneCopy \
- DISABLED_FullRaster_MultiThread_OneCopy
-#else
-#define MAYBE_FullRaster_MultiThread_OneCopy FullRaster_MultiThread_OneCopy
-#endif
TEST_F(LayerTreeHostTilesTestPartialInvalidation,
- MAYBE_FullRaster_MultiThread_OneCopy) {
+ FullRaster_MultiThread_OneCopy) {
RunRasterPixelTest(
true, FULL_ONE_COPY, picture_layer_,
base::FilePath(FILE_PATH_LITERAL("blue_yellow_flipped.png")));
diff --git a/chromium/cc/trees/layer_tree_host_unittest.cc b/chromium/cc/trees/layer_tree_host_unittest.cc
index 2e7457a49aa..9a657f521e4 100644
--- a/chromium/cc/trees/layer_tree_host_unittest.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest.cc
@@ -46,6 +46,7 @@
#include "cc/test/fake_scoped_ui_resource.h"
#include "cc/test/fake_video_frame_provider.h"
#include "cc/test/geometry_test_utils.h"
+#include "cc/test/layer_test_common.h"
#include "cc/test/layer_tree_test.h"
#include "cc/test/push_properties_counting_layer.h"
#include "cc/test/push_properties_counting_layer_impl.h"
@@ -1043,29 +1044,29 @@ class LayerTreeHostTestSurfaceDamage : public LayerTreeHostTest {
LayerImpl* child_impl = impl->active_tree()->LayerById(child_->id());
switch (impl->active_tree()->source_frame_number()) {
case 0:
- EXPECT_TRUE(root_impl->GetRenderSurface()->AncestorPropertyChanged());
- EXPECT_TRUE(child_impl->GetRenderSurface()->AncestorPropertyChanged());
+ EXPECT_TRUE(GetRenderSurface(root_impl)->AncestorPropertyChanged());
+ EXPECT_TRUE(GetRenderSurface(child_impl)->AncestorPropertyChanged());
PostSetNeedsCommitToMainThread();
break;
case 1:
- EXPECT_FALSE(root_impl->GetRenderSurface()->AncestorPropertyChanged());
- EXPECT_FALSE(child_impl->GetRenderSurface()->AncestorPropertyChanged());
+ EXPECT_FALSE(GetRenderSurface(root_impl)->AncestorPropertyChanged());
+ EXPECT_FALSE(GetRenderSurface(child_impl)->AncestorPropertyChanged());
PostSetNeedsCommitToMainThread();
break;
case 2:
- EXPECT_TRUE(root_impl->GetRenderSurface()->AncestorPropertyChanged());
- EXPECT_TRUE(child_impl->GetRenderSurface()->AncestorPropertyChanged());
+ EXPECT_TRUE(GetRenderSurface(root_impl)->AncestorPropertyChanged());
+ EXPECT_TRUE(GetRenderSurface(child_impl)->AncestorPropertyChanged());
PostSetNeedsCommitToMainThread();
break;
case 3:
- EXPECT_FALSE(root_impl->GetRenderSurface()->AncestorPropertyChanged());
- EXPECT_TRUE(child_impl->GetRenderSurface()->AncestorPropertyChanged());
+ EXPECT_FALSE(GetRenderSurface(root_impl)->AncestorPropertyChanged());
+ EXPECT_TRUE(GetRenderSurface(child_impl)->AncestorPropertyChanged());
EndTest();
PostSetNeedsCommitToMainThread();
break;
case 4:
- EXPECT_FALSE(root_impl->GetRenderSurface()->AncestorPropertyChanged());
- EXPECT_FALSE(child_impl->GetRenderSurface()->AncestorPropertyChanged());
+ EXPECT_FALSE(GetRenderSurface(root_impl)->AncestorPropertyChanged());
+ EXPECT_FALSE(GetRenderSurface(child_impl)->AncestorPropertyChanged());
EndTest();
break;
}
@@ -1179,6 +1180,227 @@ class LayerTreeHostTestPropertyTreesChangedSync : public LayerTreeHostTest {
SINGLE_THREAD_TEST_F(LayerTreeHostTestPropertyTreesChangedSync);
+// Simple base class for tests that just need to mutate the layer tree
+// host and observe results without any impl thread, multi-layer, or
+// multi-frame antics.
+class LayerTreeHostTestLayerListsTest : public LayerTreeHostTest {
+ public:
+ explicit LayerTreeHostTestLayerListsTest(bool use_layer_lists)
+ : use_layer_lists_(use_layer_lists) {}
+
+ protected:
+ void InitializeSettings(LayerTreeSettings* settings) override {
+ settings->use_layer_lists = use_layer_lists_;
+ }
+
+ void SetupTree() override {
+ root_ = Layer::Create();
+ layer_tree_host()->SetRootLayer(root_);
+ LayerTreeHostTest::SetupTree();
+ }
+
+ void AfterTest() override {}
+
+ scoped_refptr<Layer> root_;
+
+ private:
+ bool use_layer_lists_;
+};
+
+class LayerTreeHostTestAnimationOpacityMutatedNotUsingLayerLists
+ : public LayerTreeHostTestLayerListsTest {
+ public:
+ LayerTreeHostTestAnimationOpacityMutatedNotUsingLayerLists()
+ : LayerTreeHostTestLayerListsTest(false) {}
+
+ protected:
+ void BeginTest() override {
+ EXPECT_EQ(1.0f, root_->opacity());
+ layer_tree_host()->SetElementOpacityMutated(root_->element_id(),
+ ElementListType::ACTIVE, 0.3f);
+ // When not using layer lists, opacity is stored on the layer.
+ EXPECT_EQ(0.3f, root_->opacity());
+ EndTest();
+ }
+};
+
+SINGLE_THREAD_TEST_F(
+ LayerTreeHostTestAnimationOpacityMutatedNotUsingLayerLists);
+
+class LayerTreeHostTestAnimationOpacityMutatedUsingLayerLists
+ : public LayerTreeHostTestLayerListsTest {
+ public:
+ LayerTreeHostTestAnimationOpacityMutatedUsingLayerLists()
+ : LayerTreeHostTestLayerListsTest(true) {}
+
+ protected:
+ void BeginTest() override {
+ // Insert a dummy effect node to observe its mutation. This would
+ // normally have been created by PaintArtifactCompositor.
+ int effect_node_id =
+ layer_tree_host()->property_trees()->effect_tree.Insert(
+ EffectNode(), EffectTree::kInvalidNodeId);
+ layer_tree_host()
+ ->property_trees()
+ ->element_id_to_effect_node_index[root_->element_id()] = effect_node_id;
+
+ EXPECT_EQ(1.0f, root_->opacity());
+ EXPECT_EQ(1.0f,
+ layer_tree_host()
+ ->property_trees()
+ ->effect_tree.FindNodeFromElementId(root_->element_id())
+ ->opacity);
+
+ layer_tree_host()->SetElementOpacityMutated(root_->element_id(),
+ ElementListType::ACTIVE, 0.3f);
+
+ // When using layer lists, we don't have to store the opacity on the layer.
+ EXPECT_EQ(1.0f, root_->opacity());
+ // The opacity should have been set directly on the effect node instead.
+ EXPECT_EQ(0.3f,
+ layer_tree_host()
+ ->property_trees()
+ ->effect_tree.FindNodeFromElementId(root_->element_id())
+ ->opacity);
+ EndTest();
+ }
+};
+
+SINGLE_THREAD_TEST_F(LayerTreeHostTestAnimationOpacityMutatedUsingLayerLists);
+
+class LayerTreeHostTestAnimationTransformMutatedNotUsingLayerLists
+ : public LayerTreeHostTestLayerListsTest {
+ public:
+ LayerTreeHostTestAnimationTransformMutatedNotUsingLayerLists()
+ : LayerTreeHostTestLayerListsTest(false) {}
+
+ protected:
+ void BeginTest() override {
+ EXPECT_EQ(gfx::Transform(), root_->transform());
+ gfx::Transform expected_transform;
+ expected_transform.Translate(42, 42);
+ layer_tree_host()->SetElementTransformMutated(
+ root_->element_id(), ElementListType::ACTIVE, expected_transform);
+ // When not using layer lists, transform is stored on the layer.
+ EXPECT_EQ(expected_transform, root_->transform());
+ EndTest();
+ }
+};
+
+SINGLE_THREAD_TEST_F(
+ LayerTreeHostTestAnimationTransformMutatedNotUsingLayerLists);
+
+class LayerTreeHostTestAnimationTransformMutatedUsingLayerLists
+ : public LayerTreeHostTestLayerListsTest {
+ public:
+ LayerTreeHostTestAnimationTransformMutatedUsingLayerLists()
+ : LayerTreeHostTestLayerListsTest(true) {}
+
+ protected:
+ void BeginTest() override {
+ // Insert a dummy transform node to observe its mutation. This would
+ // normally have been created by PaintArtifactCompositor.
+ int transform_node_id =
+ layer_tree_host()->property_trees()->transform_tree.Insert(
+ TransformNode(), TransformTree::kInvalidNodeId);
+ layer_tree_host()
+ ->property_trees()
+ ->element_id_to_transform_node_index[root_->element_id()] =
+ transform_node_id;
+
+ EXPECT_EQ(gfx::Transform(), root_->transform());
+ EXPECT_EQ(gfx::Transform(),
+ layer_tree_host()
+ ->property_trees()
+ ->transform_tree.FindNodeFromElementId(root_->element_id())
+ ->local);
+
+ gfx::Transform expected_transform;
+ expected_transform.Translate(42, 42);
+ layer_tree_host()->SetElementTransformMutated(
+ root_->element_id(), ElementListType::ACTIVE, expected_transform);
+
+ // When using layer lists, we don't have to store the transform on the
+ // layer.
+ EXPECT_EQ(gfx::Transform(), root_->transform());
+ // The transform should have been set directly on the transform node
+ // instead.
+ EXPECT_EQ(expected_transform,
+ layer_tree_host()
+ ->property_trees()
+ ->transform_tree.FindNodeFromElementId(root_->element_id())
+ ->local);
+ EndTest();
+ }
+};
+
+SINGLE_THREAD_TEST_F(LayerTreeHostTestAnimationTransformMutatedUsingLayerLists);
+
+class LayerTreeHostTestAnimationFilterMutatedNotUsingLayerLists
+ : public LayerTreeHostTestLayerListsTest {
+ public:
+ LayerTreeHostTestAnimationFilterMutatedNotUsingLayerLists()
+ : LayerTreeHostTestLayerListsTest(false) {}
+
+ protected:
+ void BeginTest() override {
+ FilterOperations filters;
+ EXPECT_EQ(FilterOperations(), root_->filters());
+ filters.Append(FilterOperation::CreateOpacityFilter(0.5f));
+ layer_tree_host()->SetElementFilterMutated(
+ root_->element_id(), ElementListType::ACTIVE, filters);
+ // When not using layer lists, filters are just stored directly on the
+ // layer.
+ EXPECT_EQ(filters, root_->filters());
+ EndTest();
+ }
+};
+
+SINGLE_THREAD_TEST_F(LayerTreeHostTestAnimationFilterMutatedNotUsingLayerLists);
+
+class LayerTreeHostTestAnimationFilterMutatedUsingLayerLists
+ : public LayerTreeHostTestLayerListsTest {
+ public:
+ LayerTreeHostTestAnimationFilterMutatedUsingLayerLists()
+ : LayerTreeHostTestLayerListsTest(true) {}
+
+ protected:
+ void BeginTest() override {
+ // Insert a dummy effect node to observe its mutation. This would
+ // normally have been created by PaintArtifactCompositor.
+ int effect_node_id =
+ layer_tree_host()->property_trees()->effect_tree.Insert(
+ EffectNode(), EffectTree::kInvalidNodeId);
+ layer_tree_host()
+ ->property_trees()
+ ->element_id_to_effect_node_index[root_->element_id()] = effect_node_id;
+
+ EXPECT_EQ(FilterOperations(), root_->filters());
+ EXPECT_EQ(FilterOperations(),
+ layer_tree_host()
+ ->property_trees()
+ ->effect_tree.FindNodeFromElementId(root_->element_id())
+ ->filters);
+
+ FilterOperations filters;
+ filters.Append(FilterOperation::CreateOpacityFilter(0.5f));
+ layer_tree_host()->SetElementFilterMutated(
+ root_->element_id(), ElementListType::ACTIVE, filters);
+
+ // When using layer lists, we don't have to store the filters on the layer.
+ EXPECT_EQ(FilterOperations(), root_->filters());
+ // The filter should have been set directly on the effect node instead.
+ EXPECT_EQ(filters,
+ layer_tree_host()
+ ->property_trees()
+ ->effect_tree.FindNodeFromElementId(root_->element_id())
+ ->filters);
+ EndTest();
+ }
+};
+
+SINGLE_THREAD_TEST_F(LayerTreeHostTestAnimationFilterMutatedUsingLayerLists);
+
class LayerTreeHostTestEffectTreeSync : public LayerTreeHostTest {
protected:
void SetupTree() override {
@@ -1376,8 +1598,8 @@ class LayerTreeHostTestTransformTreeDamageIsUpdated : public LayerTreeHostTest {
root_->SetBounds(gfx::Size(50, 50));
- // Make sure child is registerd for animation.
- child_->SetElementId(ElementId(2, 0));
+ // Make sure child is registered for animation.
+ child_->SetElementId(ElementId(2));
// Make sure child and grand_child have transform nodes.
gfx::Transform rotation;
@@ -1442,6 +1664,21 @@ class LayerTreeHostTestTransformTreeDamageIsUpdated : public LayerTreeHostTest {
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestTransformTreeDamageIsUpdated);
+class UpdateCountingLayer : public Layer {
+ public:
+ bool Update() override {
+ update_count_++;
+ return false;
+ }
+
+ int update_count() const { return update_count_; }
+
+ private:
+ ~UpdateCountingLayer() override = default;
+
+ int update_count_ = 0;
+};
+
// Test that when mask layers switches layers, this gets pushed onto impl.
// Also test that mask layer is in the layer update list even if its owning
// layer isn't.
@@ -1450,11 +1687,11 @@ class LayerTreeHostTestSwitchMaskLayer : public LayerTreeHostTest {
void SetupTree() override {
scoped_refptr<Layer> root = Layer::Create();
root->SetBounds(gfx::Size(10, 10));
- scoped_refptr<Layer> child = Layer::Create();
- mask_layer = Layer::Create();
- mask_layer->SetBounds(gfx::Size(10, 10));
- child->SetMaskLayer(mask_layer.get());
- root->AddChild(std::move(child));
+ child_layer_ = make_scoped_refptr(new UpdateCountingLayer);
+ mask_layer_ = make_scoped_refptr(new UpdateCountingLayer);
+ mask_layer_->SetBounds(gfx::Size(10, 10));
+ child_layer_->SetMaskLayer(mask_layer_.get());
+ root->AddChild(child_layer_);
layer_tree_host()->SetRootLayer(root);
LayerTreeHostTest::SetupTree();
}
@@ -1470,19 +1707,11 @@ class LayerTreeHostTestSwitchMaskLayer : public LayerTreeHostTest {
// Root and mask layer should have the same source frame number as they
// will be in the layer update list but the child is not as it has empty
// bounds.
- EXPECT_EQ(mask_layer->paint_properties().source_frame_number,
- layer_tree_host()
- ->root_layer()
- ->paint_properties()
- .source_frame_number);
- EXPECT_NE(mask_layer->paint_properties().source_frame_number,
- layer_tree_host()
- ->root_layer()
- ->child_at(0)
- ->paint_properties()
- .source_frame_number);
+ EXPECT_EQ(mask_layer_->update_count(), 1);
+ EXPECT_EQ(child_layer_->update_count(), 0);
+
layer_tree_host()->root_layer()->RemoveAllChildren();
- layer_tree_host()->root_layer()->SetMaskLayer(mask_layer.get());
+ layer_tree_host()->root_layer()->SetMaskLayer(mask_layer_.get());
break;
}
}
@@ -1491,16 +1720,14 @@ class LayerTreeHostTestSwitchMaskLayer : public LayerTreeHostTest {
switch (index_) {
case 0:
index_++;
- EXPECT_FALSE(impl->sync_tree()
- ->root_layer_for_testing()
- ->GetRenderSurface()
- ->MaskLayer());
+ EXPECT_FALSE(
+ GetRenderSurface(impl->sync_tree()->root_layer_for_testing())
+ ->MaskLayer());
break;
case 1:
- EXPECT_TRUE(impl->sync_tree()
- ->root_layer_for_testing()
- ->GetRenderSurface()
- ->MaskLayer());
+ EXPECT_TRUE(
+ GetRenderSurface(impl->sync_tree()->root_layer_for_testing())
+ ->MaskLayer());
EndTest();
break;
}
@@ -1508,7 +1735,8 @@ class LayerTreeHostTestSwitchMaskLayer : public LayerTreeHostTest {
void AfterTest() override {}
- scoped_refptr<Layer> mask_layer;
+ scoped_refptr<UpdateCountingLayer> mask_layer_;
+ scoped_refptr<UpdateCountingLayer> child_layer_;
int index_;
};
@@ -1750,7 +1978,7 @@ class LayerTreeHostTestNoExtraCommitFromScrollbarInvalidate
bool paint_scrollbar = true;
bool has_thumb = false;
scrollbar_ = FakePaintedScrollbarLayer::Create(paint_scrollbar, has_thumb,
- root_layer_->id());
+ root_layer_->element_id());
scrollbar_->SetPosition(gfx::PointF(0.f, 10.f));
scrollbar_->SetBounds(gfx::Size(10, 10));
@@ -2298,7 +2526,7 @@ class LayerTreeHostTestCommit : public LayerTreeHostTest {
}
void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override {
- EXPECT_EQ(gfx::Size(20, 20), impl->DrawViewportSize());
+ EXPECT_EQ(gfx::Rect(20, 20), impl->DeviceViewport());
EXPECT_EQ(SK_ColorGRAY, impl->active_tree()->background_color());
EXPECT_EQ(EventListenerProperties::kPassive,
impl->active_tree()->event_listener_properties(
@@ -2473,15 +2701,16 @@ class LayerTreeHostTestStartPageScaleAnimation : public LayerTreeHostTest {
break;
case 1:
EXPECT_EQ(1.f, impl->active_tree()->current_page_scale_factor());
+ // Once the animation starts, an ImplFrame will be requested. However,
+ // main frames may be happening in the mean-time due to high-latency
+ // mode. If one happens before the next impl frame, then the source
+ // frame number may increment twice instead of just once.
break;
case 2:
+ case 3:
EXPECT_EQ(1.25f, impl->active_tree()->current_page_scale_factor());
EndTest();
break;
- case 3:
- break;
- default:
- NOTREACHED();
}
}
@@ -2570,7 +2799,7 @@ class LayerTreeHostTestDeviceScaleFactorScalesViewportAndLayers
EXPECT_NEAR(impl->active_tree()->device_scale_factor(), 1.5f, 0.00001f);
// Device viewport is scaled.
- EXPECT_EQ(gfx::Size(60, 60), impl->DrawViewportSize());
+ EXPECT_EQ(gfx::Rect(60, 60), impl->DeviceViewport());
FakePictureLayerImpl* root = static_cast<FakePictureLayerImpl*>(
impl->active_tree()->root_layer_for_testing());
@@ -2586,18 +2815,16 @@ class LayerTreeHostTestDeviceScaleFactorScalesViewportAndLayers
impl->PrepareToDraw(&frame_data);
impl->DidDrawAllLayers(frame_data);
- const LayerImplList& render_surface_layer_list =
- *frame_data.render_surface_layer_list;
+ const RenderSurfaceList& render_surface_list =
+ *frame_data.render_surface_list;
// Both layers should be drawing into the root render surface.
- ASSERT_EQ(1u, render_surface_layer_list.size());
- ASSERT_EQ(root->GetRenderSurface(),
- render_surface_layer_list[0]->GetRenderSurface());
- ASSERT_EQ(2u, root->GetRenderSurface()->layer_list().size());
+ ASSERT_EQ(1u, render_surface_list.size());
+ ASSERT_EQ(GetRenderSurface(root), render_surface_list[0]);
+ ASSERT_EQ(2, GetRenderSurface(root)->num_contributors());
// The root render surface is the size of the viewport.
- EXPECT_EQ(gfx::Rect(0, 0, 60, 60),
- root->GetRenderSurface()->content_rect());
+ EXPECT_EQ(gfx::Rect(0, 0, 60, 60), GetRenderSurface(root)->content_rect());
// The max tiling scale of the child should be scaled.
EXPECT_FLOAT_EQ(1.5f, child->MaximumTilingContentsScale());
@@ -3085,7 +3312,6 @@ class OnDrawCompositorFrameSink : public TestCompositorFrameSink {
const RendererSettings& renderer_settings,
base::SingleThreadTaskRunner* task_runner,
bool synchronous_composite,
- bool force_disable_reclaim_resources,
base::Closure invalidate_callback)
: TestCompositorFrameSink(std::move(compositor_context_provider),
std::move(worker_context_provider),
@@ -3094,7 +3320,7 @@ class OnDrawCompositorFrameSink : public TestCompositorFrameSink {
renderer_settings,
task_runner,
synchronous_composite,
- force_disable_reclaim_resources),
+ false /* disable_display_vsync */),
invalidate_callback_(std::move(invalidate_callback)) {}
// TestCompositorFrameSink overrides.
@@ -3130,7 +3356,6 @@ class LayerTreeHostTestAbortedCommitDoesntStallSynchronousCompositor
shared_bitmap_manager(), gpu_memory_buffer_manager(),
layer_tree_host()->GetSettings().renderer_settings,
ImplThreadTaskRunner(), false /* synchronous_composite */,
- false /* force_disable_reclaim_resources */,
std::move(on_draw_callback));
compositor_frame_sink_ = frame_sink.get();
return std::move(frame_sink);
@@ -3737,7 +3962,7 @@ class LayerTreeHostTestPropertyChangesDuringUpdateArePushed
bool paint_scrollbar = true;
bool has_thumb = false;
scrollbar_layer_ = FakePaintedScrollbarLayer::Create(
- paint_scrollbar, has_thumb, root_->id());
+ paint_scrollbar, has_thumb, root_->element_id());
root_->AddChild(scrollbar_layer_);
@@ -4496,9 +4721,12 @@ class LayerTreeHostTestElasticOverscroll : public LayerTreeHostTest {
inner_viewport_scroll_layer->AddChild(content_layer);
layer_tree_host()->SetRootLayer(root_layer_);
- layer_tree_host()->RegisterViewportLayers(
- overscroll_elasticity_layer, page_scale_layer,
- inner_viewport_scroll_layer, nullptr);
+ LayerTreeHost::ViewportLayers viewport_layers;
+ viewport_layers.overscroll_elasticity = overscroll_elasticity_layer;
+ viewport_layers.page_scale = page_scale_layer;
+ viewport_layers.inner_viewport_container = inner_viewport_container_layer;
+ viewport_layers.inner_viewport_scroll = inner_viewport_scroll_layer;
+ layer_tree_host()->RegisterViewportLayers(viewport_layers);
LayerTreeHostTest::SetupTree();
client_.set_bounds(content_layer->bounds());
}
@@ -5300,15 +5528,15 @@ class LayerTreeHostTestGpuRasterizationEnabled
// Ensure the suitability bit sticks.
EXPECT_FALSE(layer_->IsSuitableForGpuRasterization());
- EXPECT_FALSE(host_impl->pending_tree()->use_gpu_rasterization());
- EXPECT_FALSE(host_impl->use_gpu_rasterization());
+ EXPECT_TRUE(host_impl->pending_tree()->use_gpu_rasterization());
+ EXPECT_TRUE(host_impl->use_gpu_rasterization());
}
void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
EXPECT_FALSE(layer_->IsSuitableForGpuRasterization());
- EXPECT_FALSE(host_impl->active_tree()->use_gpu_rasterization());
- EXPECT_FALSE(host_impl->use_gpu_rasterization());
+ EXPECT_TRUE(host_impl->active_tree()->use_gpu_rasterization());
+ EXPECT_TRUE(host_impl->use_gpu_rasterization());
EndTest();
}
@@ -5324,6 +5552,23 @@ MULTI_THREAD_TEST_F(LayerTreeHostTestGpuRasterizationEnabled);
class LayerTreeHostTestGpuRasterizationReenabled
: public LayerTreeHostWithGpuRasterizationTest {
protected:
+ void InitializeSettings(LayerTreeSettings* settings) override {
+ settings->gpu_rasterization_msaa_sample_count = 4;
+ }
+
+ std::unique_ptr<TestCompositorFrameSink> CreateCompositorFrameSink(
+ scoped_refptr<ContextProvider> compositor_context_provider,
+ scoped_refptr<ContextProvider> worker_context_provider) override {
+ std::unique_ptr<TestWebGraphicsContext3D> context =
+ TestWebGraphicsContext3D::Create();
+ context->SetMaxSamples(4);
+ context->set_gpu_rasterization(true);
+ compositor_context_provider =
+ TestContextProvider::Create(std::move(context));
+ return LayerTreeTest::CreateCompositorFrameSink(compositor_context_provider,
+ worker_context_provider);
+ }
+
void SetupTree() override {
LayerTreeHostTest::SetupTree();
@@ -5362,10 +5607,10 @@ class LayerTreeHostTestGpuRasterizationReenabled
void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
SCOPED_TRACE(base::StringPrintf("commit %d", num_commits_));
- if (expected_gpu_enabled_) {
- EXPECT_TRUE(host_impl->use_gpu_rasterization());
+ if (expected_use_msaa_) {
+ EXPECT_TRUE(host_impl->use_msaa());
} else {
- EXPECT_FALSE(host_impl->use_gpu_rasterization());
+ EXPECT_FALSE(host_impl->use_msaa());
}
++num_commits_;
@@ -5380,7 +5625,7 @@ class LayerTreeHostTestGpuRasterizationReenabled
layer_->set_force_unsuitable_for_gpu_rasterization(false);
break;
case 90:
- expected_gpu_enabled_ = true;
+ expected_use_msaa_ = false;
break;
}
PostSetNeedsCommitToMainThread();
@@ -5394,7 +5639,7 @@ class LayerTreeHostTestGpuRasterizationReenabled
FakePictureLayer* layer_;
FakeRecordingSource* recording_source_;
int num_commits_ = 0;
- bool expected_gpu_enabled_ = false;
+ bool expected_use_msaa_ = true;
};
MULTI_THREAD_TEST_F(LayerTreeHostTestGpuRasterizationReenabled);
@@ -5666,7 +5911,7 @@ class LayerTreeHostTestRenderSurfaceEffectTreeIndex : public LayerTreeHostTest {
LayerImpl* grand_child_impl =
host_impl->sync_tree()->LayerById(grand_child_->id());
EXPECT_EQ(grand_child_impl->effect_tree_index(),
- grand_child_impl->GetRenderSurface()->EffectTreeIndex());
+ GetRenderSurface(grand_child_impl)->EffectTreeIndex());
}
}
@@ -5680,12 +5925,12 @@ class LayerTreeHostTestRenderSurfaceEffectTreeIndex : public LayerTreeHostTest {
case 1:
case 2:
EXPECT_EQ(grand_child_impl->effect_tree_index(),
- grand_child_impl->GetRenderSurface()->EffectTreeIndex());
+ GetRenderSurface(grand_child_impl)->EffectTreeIndex());
PostSetNeedsCommitToMainThread();
break;
case 3:
EXPECT_EQ(grand_child_impl->effect_tree_index(),
- grand_child_impl->GetRenderSurface()->EffectTreeIndex());
+ GetRenderSurface(grand_child_impl)->EffectTreeIndex());
EndTest();
}
}
@@ -5727,17 +5972,15 @@ class LayerTreeHostTestSynchronousCompositeSwapPromise
std::unique_ptr<TestCompositorFrameSink> CreateCompositorFrameSink(
scoped_refptr<ContextProvider> compositor_context_provider,
scoped_refptr<ContextProvider> worker_context_provider) override {
+ constexpr bool disable_display_vsync = false;
bool synchronous_composite =
!HasImplThread() &&
!layer_tree_host()->GetSettings().single_thread_proxy_scheduler;
- // Relaiming resources is parameterized for this test.
- bool force_disable_reclaim_resources = !reclaim_resources_;
return base::MakeUnique<TestCompositorFrameSink>(
compositor_context_provider, std::move(worker_context_provider),
shared_bitmap_manager(), gpu_memory_buffer_manager(),
layer_tree_host()->GetSettings().renderer_settings,
- ImplThreadTaskRunner(), synchronous_composite,
- force_disable_reclaim_resources);
+ ImplThreadTaskRunner(), synchronous_composite, disable_display_vsync);
}
void BeginTest() override {
@@ -5784,19 +6027,13 @@ class LayerTreeHostTestSynchronousCompositeSwapPromise
EXPECT_TRUE(swap_promise_result_[0].dtor_called);
}
- // Second swap promise fails to swap if not reclaiming resources from the
- // Display.
+ // Second swap promise fails to swap.
{
base::AutoLock lock(swap_promise_result_[1].lock);
EXPECT_TRUE(swap_promise_result_[1].did_activate_called);
- if (!reclaim_resources_) {
- EXPECT_FALSE(swap_promise_result_[1].did_swap_called);
- EXPECT_TRUE(swap_promise_result_[1].did_not_swap_called);
- EXPECT_EQ(SwapPromise::SWAP_FAILS, swap_promise_result_[1].reason);
- } else {
- EXPECT_TRUE(swap_promise_result_[1].did_swap_called);
- EXPECT_FALSE(swap_promise_result_[1].did_not_swap_called);
- }
+ EXPECT_FALSE(swap_promise_result_[1].did_swap_called);
+ EXPECT_TRUE(swap_promise_result_[1].did_not_swap_called);
+ EXPECT_EQ(SwapPromise::SWAP_FAILS, swap_promise_result_[1].reason);
EXPECT_TRUE(swap_promise_result_[1].dtor_called);
}
@@ -5811,20 +6048,12 @@ class LayerTreeHostTestSynchronousCompositeSwapPromise
}
}
- bool reclaim_resources_;
int commit_count_ = 0;
TestSwapPromiseResult swap_promise_result_[3];
};
-TEST_F(LayerTreeHostTestSynchronousCompositeSwapPromise, NoReclaim) {
- reclaim_resources_ = false;
- RunTest(CompositorMode::SINGLE_THREADED);
-}
-
-TEST_F(LayerTreeHostTestSynchronousCompositeSwapPromise, Reclaim) {
- reclaim_resources_ = true;
- RunTest(CompositorMode::SINGLE_THREADED);
-}
+// Synchronous composite is a single-threaded only feature.
+SINGLE_THREAD_TEST_F(LayerTreeHostTestSynchronousCompositeSwapPromise);
// Make sure page scale and top control deltas are applied to the client even
// when the LayerTreeHost doesn't have a root layer.
@@ -5901,8 +6130,11 @@ class LayerTreeHostTestCrispUpAfterPinchEnds : public LayerTreeHostTest {
// pinch.
pinch->AddChild(layer);
- layer_tree_host()->RegisterViewportLayers(NULL, page_scale_layer, pinch,
- nullptr);
+ LayerTreeHost::ViewportLayers viewport_layers;
+ viewport_layers.page_scale = page_scale_layer;
+ viewport_layers.inner_viewport_container = root_clip;
+ viewport_layers.inner_viewport_scroll = pinch;
+ layer_tree_host()->RegisterViewportLayers(viewport_layers);
layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 1.f, 4.f);
layer_tree_host()->SetRootLayer(root_clip);
LayerTreeHostTest::SetupTree();
@@ -6205,8 +6437,11 @@ class LayerTreeHostTestContinuousDrawWhenCreatingVisibleTiles
// pinch.
pinch->AddChild(layer);
- layer_tree_host()->RegisterViewportLayers(NULL, page_scale_layer, pinch,
- nullptr);
+ LayerTreeHost::ViewportLayers viewport_layers;
+ viewport_layers.page_scale = page_scale_layer;
+ viewport_layers.inner_viewport_container = root_clip;
+ viewport_layers.inner_viewport_scroll = pinch;
+ layer_tree_host()->RegisterViewportLayers(viewport_layers);
layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 1.f, 4.f);
layer_tree_host()->SetRootLayer(root_clip);
LayerTreeHostTest::SetupTree();
@@ -6508,7 +6743,7 @@ class LayerTreeHostTestUpdateCopyRequests : public LayerTreeHostTest {
void WillCommit() override {
switch (layer_tree_host()->SourceFrameNumber()) {
case 1:
- EXPECT_GT(root->num_copy_requests_in_target_subtree(), 0);
+ EXPECT_TRUE(root->has_copy_requests_in_target_subtree());
break;
}
}
@@ -6531,7 +6766,7 @@ class LayerTreeHostTestUpdateCopyRequests : public LayerTreeHostTest {
child->SetTransform(transform);
break;
case 3:
- EXPECT_EQ(root->num_copy_requests_in_target_subtree(), 0);
+ EXPECT_FALSE(root->has_copy_requests_in_target_subtree());
EndTest();
break;
}
@@ -6641,8 +6876,27 @@ class LayerTreeTestMaskLayerForSurfaceWithContentRectNotAtOrigin
FakeContentLayerClient client_;
};
+class LayerTreeTestSingleTextureMaskLayerForSurfaceWithContentRectNotAtOrigin
+ : public LayerTreeTestMaskLayerForSurfaceWithContentRectNotAtOrigin {
+ public:
+ void InitializeSettings(LayerTreeSettings* settings) override {
+ settings->enable_mask_tiling = false;
+ }
+};
+
SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeTestMaskLayerForSurfaceWithContentRectNotAtOrigin);
+ LayerTreeTestSingleTextureMaskLayerForSurfaceWithContentRectNotAtOrigin);
+
+class LayerTreeTestMultiTextureMaskLayerForSurfaceWithContentRectNotAtOrigin
+ : public LayerTreeTestMaskLayerForSurfaceWithContentRectNotAtOrigin {
+ public:
+ void InitializeSettings(LayerTreeSettings* settings) override {
+ settings->enable_mask_tiling = true;
+ }
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(
+ LayerTreeTestMultiTextureMaskLayerForSurfaceWithContentRectNotAtOrigin);
class LayerTreeTestMaskLayerForSurfaceWithClippedLayer : public LayerTreeTest {
protected:
@@ -6754,15 +7008,30 @@ class LayerTreeTestMaskLayerForSurfaceWithClippedLayer : public LayerTreeTest {
FakeContentLayerClient client_;
};
+class LayerTreeTestSingleTextureMaskLayerForSurfaceWithClippedLayer
+ : public LayerTreeTestMaskLayerForSurfaceWithClippedLayer {
+ public:
+ void InitializeSettings(LayerTreeSettings* settings) override {
+ settings->enable_mask_tiling = false;
+ }
+};
+
SINGLE_AND_MULTI_THREAD_TEST_F(
- LayerTreeTestMaskLayerForSurfaceWithClippedLayer);
+ LayerTreeTestSingleTextureMaskLayerForSurfaceWithClippedLayer);
-class LayerTreeTestMaskLayerWithScaling : public LayerTreeTest {
- protected:
+class LayerTreeTestMultiTextureMaskLayerForSurfaceWithClippedLayer
+ : public LayerTreeTestMaskLayerForSurfaceWithClippedLayer {
+ public:
void InitializeSettings(LayerTreeSettings* settings) override {
- settings->layer_transforms_should_scale_layer_contents = true;
+ settings->enable_mask_tiling = true;
}
+};
+SINGLE_AND_MULTI_THREAD_TEST_F(
+ LayerTreeTestMultiTextureMaskLayerForSurfaceWithClippedLayer);
+
+class LayerTreeTestMaskLayerWithScaling : public LayerTreeTest {
+ protected:
void SetupTree() override {
// Root
// |
@@ -6878,7 +7147,27 @@ class LayerTreeTestMaskLayerWithScaling : public LayerTreeTest {
FakeContentLayerClient client_;
};
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeTestMaskLayerWithScaling);
+class LayerTreeTestSingleTextureMaskLayerWithScaling
+ : public LayerTreeTestMaskLayerWithScaling {
+ public:
+ void InitializeSettings(LayerTreeSettings* settings) override {
+ settings->enable_mask_tiling = false;
+ settings->layer_transforms_should_scale_layer_contents = true;
+ }
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeTestSingleTextureMaskLayerWithScaling);
+
+class LayerTreeTestMultiTextureMaskLayerWithScaling
+ : public LayerTreeTestMaskLayerWithScaling {
+ public:
+ void InitializeSettings(LayerTreeSettings* settings) override {
+ settings->enable_mask_tiling = true;
+ settings->layer_transforms_should_scale_layer_contents = true;
+ }
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeTestMultiTextureMaskLayerWithScaling);
class LayerTreeTestMaskLayerWithDifferentBounds : public LayerTreeTest {
protected:
@@ -6983,7 +7272,103 @@ class LayerTreeTestMaskLayerWithDifferentBounds : public LayerTreeTest {
FakeContentLayerClient client_;
};
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeTestMaskLayerWithDifferentBounds);
+class LayerTreeTestSingleTextureMaskLayerWithDifferentBounds
+ : public LayerTreeTestMaskLayerWithDifferentBounds {
+ public:
+ void InitializeSettings(LayerTreeSettings* settings) override {
+ settings->enable_mask_tiling = false;
+ }
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(
+ LayerTreeTestSingleTextureMaskLayerWithDifferentBounds);
+
+class LayerTreeTestMultiTextureMaskLayerWithDifferentBounds
+ : public LayerTreeTestMaskLayerWithDifferentBounds {
+ public:
+ void InitializeSettings(LayerTreeSettings* settings) override {
+ settings->enable_mask_tiling = true;
+ }
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(
+ LayerTreeTestMultiTextureMaskLayerWithDifferentBounds);
+
+class LayerTreeTestMaskWithNonExactTextureSize : public LayerTreeTest {
+ protected:
+ void SetupTree() override {
+ // The masked layer has bounds 100x100, but is allocated a 120x150 texture.
+
+ scoped_refptr<Layer> root = Layer::Create();
+
+ scoped_refptr<FakePictureLayer> content_layer =
+ FakePictureLayer::Create(&client_);
+ root->AddChild(content_layer);
+
+ std::unique_ptr<RecordingSource> recording_source =
+ FakeRecordingSource::CreateFilledRecordingSource(gfx::Size(100, 100));
+ PaintFlags paint1, paint2;
+ static_cast<FakeRecordingSource*>(recording_source.get())
+ ->add_draw_rect_with_flags(gfx::Rect(0, 0, 100, 90), paint1);
+ static_cast<FakeRecordingSource*>(recording_source.get())
+ ->add_draw_rect_with_flags(gfx::Rect(0, 90, 100, 10), paint2);
+ client_.set_fill_with_nonsolid_color(true);
+ static_cast<FakeRecordingSource*>(recording_source.get())->Rerecord();
+
+ scoped_refptr<FakePictureLayer> mask_layer =
+ FakePictureLayer::CreateWithRecordingSource(
+ &client_, std::move(recording_source));
+ content_layer->SetMaskLayer(mask_layer.get());
+
+ gfx::Size root_size(100, 100);
+ root->SetBounds(root_size);
+
+ gfx::Size layer_size(100, 100);
+ content_layer->SetBounds(layer_size);
+
+ gfx::Size mask_size(100, 100);
+ gfx::Size mask_texture_size(120, 150);
+ mask_layer->SetBounds(mask_size);
+ mask_layer->SetLayerMaskType(Layer::LayerMaskType::SINGLE_TEXTURE_MASK);
+ mask_layer->set_fixed_tile_size(mask_texture_size);
+
+ layer_tree_host()->SetRootLayer(root);
+ LayerTreeTest::SetupTree();
+ client_.set_bounds(root->bounds());
+ }
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame_data,
+ DrawResult draw_result) override {
+ EXPECT_EQ(2u, frame_data->render_passes.size());
+ RenderPass* root_pass = frame_data->render_passes.back().get();
+ EXPECT_EQ(2u, root_pass->quad_list.size());
+
+ // There's a solid color quad under everything.
+ EXPECT_EQ(DrawQuad::SOLID_COLOR, root_pass->quad_list.back()->material);
+
+ // The surface is 100x100
+ EXPECT_EQ(DrawQuad::RENDER_PASS, root_pass->quad_list.front()->material);
+ const RenderPassDrawQuad* render_pass_quad =
+ RenderPassDrawQuad::MaterialCast(root_pass->quad_list.front());
+ EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
+ render_pass_quad->rect.ToString());
+ // The mask layer is 100x100, but is backed by a 120x150 image.
+ EXPECT_EQ(gfx::RectF(0.0f, 0.0f, 100.f / 120.0f, 100.f / 150.0f).ToString(),
+ render_pass_quad->mask_uv_rect.ToString());
+ EndTest();
+ return draw_result;
+ }
+
+ void AfterTest() override {}
+
+ int mask_layer_id_;
+ FakeContentLayerClient client_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeTestMaskWithNonExactTextureSize);
class LayerTreeTestPageScaleFlags : public LayerTreeTest {
protected:
@@ -7015,12 +7400,9 @@ class LayerTreeTestPageScaleFlags : public LayerTreeTest {
layer_tree_host()->SetRootLayer(root);
LayerTreeTest::SetupTree();
- scoped_refptr<Layer> overscroll_elasticity_layer = nullptr;
- scoped_refptr<Layer> inner_viewport_scroll_layer = nullptr;
- scoped_refptr<Layer> outer_viewport_scroll_layer = nullptr;
- layer_tree_host()->RegisterViewportLayers(
- overscroll_elasticity_layer, page_scale, inner_viewport_scroll_layer,
- outer_viewport_scroll_layer);
+ LayerTreeHost::ViewportLayers viewport_layers;
+ viewport_layers.page_scale = page_scale;
+ layer_tree_host()->RegisterViewportLayers(viewport_layers);
affected_by_page_scale_.push_back(page_scale->id());
affected_by_page_scale_.push_back(page_scale_child1->id());
@@ -7104,6 +7486,10 @@ SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestPaintedDeviceScaleFactor);
// Makes sure that LocalSurfaceId is propagated to the CompositorFrameSink.
class LayerTreeHostTestLocalSurfaceId : public LayerTreeHostTest {
protected:
+ void InitializeSettings(LayerTreeSettings* settings) override {
+ settings->enable_surface_synchronization = true;
+ }
+
void BeginTest() override {
expected_local_surface_id_ = allocator_.GenerateId();
PostSetLocalSurfaceIdToMainThread(expected_local_surface_id_);
@@ -7162,7 +7548,6 @@ class GpuRasterizationSucceedsWithLargeImage : public LayerTreeHostTest {
recording->add_draw_image(CreateDiscardableImage(large_image_size_),
gfx::Point(0, 0));
- recording->SetGenerateDiscardableImagesMetadata(true);
recording->Rerecord();
scoped_refptr<FakePictureLayer> root =
@@ -7502,5 +7887,86 @@ class LayerTreeHostTestHudLayerWithLayerLists : public LayerTreeHostTest {
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestHudLayerWithLayerLists);
+// Verifies that LayerTreeHostClient does not receive frame acks from a released
+// CompositorFrameSink.
+class LayerTreeHostTestDiscardAckAfterRelease : public LayerTreeHostTest {
+ protected:
+ void SetupTree() override {
+ scoped_refptr<Layer> root = Layer::Create();
+ root->SetBounds(gfx::Size(10, 10));
+ layer_tree_host()->SetRootLayer(std::move(root));
+ LayerTreeHostTest::SetupTree();
+ }
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ void WillReceiveCompositorFrameAckOnThread(
+ LayerTreeHostImpl* host_impl) override {
+ // This method is called before ack is posted to main thread. This ensures
+ // that WillReceiveCompositorFrameAck which we PostTask below will be called
+ // before DidReceiveCompositorFrameAck.
+ MainThreadTaskRunner()->PostTask(
+ FROM_HERE, base::Bind(&LayerTreeHostTestDiscardAckAfterRelease::
+ WillReceiveCompositorFrameAck,
+ base::Unretained(this)));
+ }
+
+ void WillReceiveCompositorFrameAck() {
+ switch (layer_tree_host()->SourceFrameNumber()) {
+ case 1:
+ // For the first commit, don't release the CompositorFrameSink. We must
+ // receive the ack later on.
+ break;
+ case 2:
+ // Release the CompositorFrameSink for the second commit. We'll later
+ // check that the ack is discarded.
+ layer_tree_host()->SetVisible(false);
+ layer_tree_host()->ReleaseCompositorFrameSink();
+ break;
+ default:
+ NOTREACHED();
+ }
+ }
+
+ void DidReceiveCompositorFrameAckOnThread(
+ LayerTreeHostImpl* host_impl) override {
+ // Since this method is called after ack is posted to main thread, we can be
+ // sure that if the ack is not discarded, it will be definitely received
+ // before we are in CheckFrameAck.
+ MainThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::Bind(&LayerTreeHostTestDiscardAckAfterRelease::CheckFrameAck,
+ base::Unretained(this)));
+ }
+
+ void DidReceiveCompositorFrameAck() override { received_ack_ = true; }
+
+ void CheckFrameAck() {
+ switch (layer_tree_host()->SourceFrameNumber()) {
+ case 1:
+ // CompositorFrameSink was not released. We must receive the ack.
+ EXPECT_TRUE(received_ack_);
+ // Cause damage so that we draw and swap.
+ layer_tree_host()->root_layer()->SetBackgroundColor(SK_ColorGREEN);
+ break;
+ case 2:
+ // CompositorFrameSink was released. The ack must be discarded.
+ EXPECT_FALSE(received_ack_);
+ EndTest();
+ break;
+ default:
+ NOTREACHED();
+ }
+ received_ack_ = false;
+ }
+
+ void AfterTest() override {}
+
+ private:
+ bool received_ack_ = false;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestDiscardAckAfterRelease);
+
} // 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 f25dc93e40f..b9fa010f632 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_animation.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_animation.cc
@@ -5,6 +5,7 @@
#include "cc/trees/layer_tree_host.h"
#include <stdint.h>
+#include <climits>
#include "cc/animation/animation_curve.h"
#include "cc/animation/animation_host.h"
@@ -489,7 +490,7 @@ class LayerTreeHostAnimationTestLayerAddedWithAnimation
AttachPlayersToTimeline();
scoped_refptr<Layer> layer = Layer::Create();
- layer->SetElementId(ElementId(42, 0));
+ layer->SetElementId(ElementId(42));
player_->AttachElement(layer->element_id());
player_->set_animation_delegate(this);
@@ -810,7 +811,7 @@ class LayerTreeHostAnimationTestScrollOffsetAnimationTakeover
if (host_impl->sync_tree()->source_frame_number() == 0) {
GetImplAnimationHost(host_impl)->ImplOnlyScrollAnimationCreate(
scroll_layer_->element_id(), gfx::ScrollOffset(650.f, 750.f),
- gfx::ScrollOffset(10, 20), base::TimeDelta());
+ gfx::ScrollOffset(10, 20), base::TimeDelta(), base::TimeDelta());
}
}
@@ -905,7 +906,7 @@ class LayerTreeHostAnimationTestScrollOffsetAnimationAdjusted
if (host_impl->sync_tree()->source_frame_number() == 0) {
GetImplAnimationHost(host_impl)->ImplOnlyScrollAnimationCreate(
scroll_layer_->element_id(), gfx::ScrollOffset(650.f, 750.f),
- gfx::ScrollOffset(10, 20), base::TimeDelta());
+ gfx::ScrollOffset(10, 20), base::TimeDelta(), base::TimeDelta());
}
}
@@ -1403,7 +1404,11 @@ class LayerTreeHostAnimationTestRemoveAnimation
player_child_->AttachElement(layer_->element_id());
}
- void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+ void BeginTest() override {
+ animation_stopped_ = false;
+ last_frame_number_ = INT_MAX;
+ PostSetNeedsCommitToMainThread();
+ }
void DidCommit() override {
switch (layer_tree_host()->SourceFrameNumber()) {
@@ -1433,6 +1438,7 @@ class LayerTreeHostAnimationTestRemoveAnimation
}
void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
+ GetImplTimelineAndPlayerByID(*host_impl);
LayerImpl* child = host_impl->active_tree()->LayerById(layer_->id());
switch (host_impl->active_tree()->source_frame_number()) {
case 0:
@@ -1443,18 +1449,37 @@ class LayerTreeHostAnimationTestRemoveAnimation
EXPECT_TRUE(child->screen_space_transform_is_animating());
break;
case 2: {
- // The animation is removed, the transform that was set afterward is
+ // The animation is stopped, the transform that was set afterward is
// applied.
gfx::Transform expected_transform;
expected_transform.Translate(10.f, 10.f);
EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform,
child->DrawTransform());
EXPECT_FALSE(child->screen_space_transform_is_animating());
- EndTest();
+ animation_stopped_ = true;
+ PostSetNeedsCommitToMainThread();
break;
}
- default:
- NOTREACHED();
+ }
+ }
+
+ void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
+ if (host_impl->sync_tree()->source_frame_number() >= last_frame_number_) {
+ // Check that eventually the animation is removed.
+ EXPECT_FALSE(player_child_impl_->has_any_animation());
+ EndTest();
+ }
+ }
+
+ void UpdateAnimationState(LayerTreeHostImpl* host_impl,
+ bool has_unfinished_animation) override {
+ // Non impl only animations are removed during commit. After the animation
+ // is fully stopped on compositor thread, make sure another commit happens.
+ if (animation_stopped_ && !has_unfinished_animation) {
+ last_frame_number_ =
+ std::min(last_frame_number_,
+ host_impl->active_tree()->source_frame_number() + 1);
+ PostSetNeedsCommitToMainThread();
}
}
@@ -1463,6 +1488,9 @@ class LayerTreeHostAnimationTestRemoveAnimation
private:
scoped_refptr<Layer> layer_;
FakeContentLayerClient client_;
+
+ int last_frame_number_;
+ bool animation_stopped_;
};
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestRemoveAnimation);
@@ -1620,6 +1648,84 @@ class LayerTreeHostAnimationTestAnimationFinishesDuringCommit
// compositor thread.
MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestAnimationFinishesDuringCommit);
+class LayerTreeHostAnimationTestImplSideInvalidation
+ : public LayerTreeHostAnimationTest {
+ public:
+ void SetupTree() override {
+ LayerTreeHostAnimationTest::SetupTree();
+ layer_ = FakePictureLayer::Create(&client_);
+ layer_->SetBounds(gfx::Size(4, 4));
+ client_.set_bounds(layer_->bounds());
+ layer_tree_host()->root_layer()->AddChild(layer_);
+
+ AttachPlayersToTimeline();
+
+ player_->AttachElement(layer_tree_host()->root_layer()->element_id());
+ player_child_->AttachElement(layer_->element_id());
+ }
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ void DidCommit() override {
+ if (layer_tree_host()->SourceFrameNumber() == 1)
+ AddAnimatedTransformToPlayer(player_child_.get(), 0.04, 5, 5);
+ }
+
+ void WillCommit() override {
+ if (layer_tree_host()->SourceFrameNumber() == 2) {
+ // Block until the animation finishes on the compositor thread. Since
+ // animations have already been ticked on the main thread, when the commit
+ // happens the state on the main thread will be consistent with having a
+ // running animation but the state on the compositor thread will be
+ // consistent with having only a finished animation.
+ completion_.Wait();
+ }
+ }
+
+ void DidInvalidateContentOnImplSide(LayerTreeHostImpl* host_impl) override {
+ DCHECK(did_request_impl_side_invalidation_);
+ completion_.Signal();
+ }
+
+ void UpdateAnimationState(LayerTreeHostImpl* host_impl,
+ bool has_unfinished_animation) override {
+ if (host_impl->active_tree()->source_frame_number() == 1 &&
+ !has_unfinished_animation && !did_request_impl_side_invalidation_) {
+ // The animation on the active tree has finished, now request an impl-side
+ // invalidation and make sure it finishes before the main thread is
+ // released.
+ did_request_impl_side_invalidation_ = true;
+ host_impl->RequestImplSideInvalidation();
+ }
+ }
+
+ void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
+ switch (host_impl->sync_tree()->source_frame_number()) {
+ case 1:
+ PostSetNeedsCommitToMainThread();
+ break;
+ case 2:
+ gfx::Transform expected_transform;
+ expected_transform.Translate(5.f, 5.f);
+ LayerImpl* layer_impl = host_impl->sync_tree()->LayerById(layer_->id());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform,
+ layer_impl->DrawTransform());
+ EndTest();
+ break;
+ }
+ }
+
+ void AfterTest() override {}
+
+ private:
+ scoped_refptr<Layer> layer_;
+ FakeContentLayerClient client_;
+ CompletionEvent completion_;
+ bool did_request_impl_side_invalidation_ = false;
+};
+
+MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestImplSideInvalidation);
+
class LayerTreeHostAnimationTestNotifyAnimationFinished
: public LayerTreeHostAnimationTest {
public:
diff --git a/chromium/cc/trees/layer_tree_host_unittest_checkerimaging.cc b/chromium/cc/trees/layer_tree_host_unittest_checkerimaging.cc
index 37b3e1b006f..0828b107c44 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_checkerimaging.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_checkerimaging.cc
@@ -21,7 +21,6 @@ class LayerTreeHostCheckerImagingTest : public LayerTreeTest {
void AfterTest() override {}
void InitializeSettings(LayerTreeSettings* settings) override {
- settings->image_decode_tasks_enabled = true;
settings->enable_checker_imaging = true;
}
diff --git a/chromium/cc/trees/layer_tree_host_unittest_context.cc b/chromium/cc/trees/layer_tree_host_unittest_context.cc
index 3c7351f3ff4..d1337cb9904 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_context.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_context.cc
@@ -973,7 +973,7 @@ class LayerTreeHostContextTestDontUseLostResources
scoped_refptr<PaintedScrollbarLayer> scrollbar =
PaintedScrollbarLayer::Create(
- std::unique_ptr<Scrollbar>(new FakeScrollbar), layer->id());
+ std::unique_ptr<Scrollbar>(new FakeScrollbar), layer->element_id());
scrollbar->SetBounds(gfx::Size(10, 10));
scrollbar->SetIsDrawable(true);
root->AddChild(scrollbar);
@@ -1088,8 +1088,8 @@ class ScrollbarLayerLostContext : public LayerTreeHostContextTest {
void BeginTest() override {
scoped_refptr<Layer> scroll_layer = Layer::Create();
- scrollbar_layer_ =
- FakePaintedScrollbarLayer::Create(false, true, scroll_layer->id());
+ scrollbar_layer_ = FakePaintedScrollbarLayer::Create(
+ false, true, scroll_layer->element_id());
scrollbar_layer_->SetBounds(gfx::Size(10, 100));
layer_tree_host()->root_layer()->AddChild(scrollbar_layer_);
layer_tree_host()->root_layer()->AddChild(scroll_layer);
diff --git a/chromium/cc/trees/layer_tree_host_unittest_damage.cc b/chromium/cc/trees/layer_tree_host_unittest_damage.cc
index 73d71a2d6dd..578324f785e 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_damage.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_damage.cc
@@ -12,6 +12,7 @@
#include "cc/test/fake_content_layer_client.h"
#include "cc/test/fake_painted_scrollbar_layer.h"
#include "cc/test/fake_picture_layer.h"
+#include "cc/test/layer_test_common.h"
#include "cc/test/layer_tree_test.h"
#include "cc/trees/damage_tracker.h"
#include "cc/trees/layer_tree_impl.h"
@@ -55,7 +56,7 @@ class LayerTreeHostDamageTestSetNeedsRedraw
EXPECT_EQ(DRAW_SUCCESS, draw_result);
RenderSurfaceImpl* root_surface =
- impl->active_tree()->root_layer_for_testing()->GetRenderSurface();
+ GetRenderSurface(impl->active_tree()->root_layer_for_testing());
gfx::Rect root_damage;
EXPECT_TRUE(
root_surface->damage_tracker()->GetDamageRectIfValid(&root_damage));
@@ -118,7 +119,7 @@ class LayerTreeHostDamageTestSetViewportSize
EXPECT_EQ(DRAW_SUCCESS, draw_result);
RenderSurfaceImpl* root_surface =
- impl->active_tree()->root_layer_for_testing()->GetRenderSurface();
+ GetRenderSurface(impl->active_tree()->root_layer_for_testing());
gfx::Rect root_damage;
EXPECT_TRUE(
root_surface->damage_tracker()->GetDamageRectIfValid(&root_damage));
@@ -260,7 +261,7 @@ class LayerTreeHostDamageTestForcedFullDamage : public LayerTreeHostDamageTest {
EXPECT_EQ(DRAW_SUCCESS, draw_result);
RenderSurfaceImpl* root_surface =
- host_impl->active_tree()->root_layer_for_testing()->GetRenderSurface();
+ GetRenderSurface(host_impl->active_tree()->root_layer_for_testing());
gfx::Rect root_damage;
EXPECT_TRUE(
root_surface->damage_tracker()->GetDamageRectIfValid(&root_damage));
@@ -340,6 +341,8 @@ class LayerTreeHostScrollbarDamageTest : public LayerTreeHostDamageTest {
scoped_refptr<Layer> scroll_clip_layer = Layer::Create();
content_layer_ = FakePictureLayer::Create(&client_);
+ content_layer_->SetElementId(
+ LayerIdToElementIdForTesting(content_layer_->id()));
content_layer_->SetScrollClipLayerId(scroll_clip_layer->id());
content_layer_->SetScrollOffset(gfx::ScrollOffset(10, 20));
content_layer_->SetBounds(gfx::Size(100, 200));
@@ -350,8 +353,8 @@ class LayerTreeHostScrollbarDamageTest : public LayerTreeHostDamageTest {
scroll_clip_layer->AddChild(content_layer_);
root_layer->AddChild(scroll_clip_layer);
- scoped_refptr<Layer> scrollbar_layer =
- FakePaintedScrollbarLayer::Create(false, true, content_layer_->id());
+ scoped_refptr<Layer> scrollbar_layer = FakePaintedScrollbarLayer::Create(
+ false, true, content_layer_->element_id());
scrollbar_layer->SetPosition(gfx::PointF(300.f, 300.f));
scrollbar_layer->SetBounds(gfx::Size(10, 100));
root_layer->AddChild(scrollbar_layer);
@@ -385,7 +388,7 @@ class LayerTreeHostDamageTestScrollbarDoesDamage
DrawResult draw_result) override {
EXPECT_EQ(DRAW_SUCCESS, draw_result);
RenderSurfaceImpl* root_surface =
- host_impl->active_tree()->root_layer_for_testing()->GetRenderSurface();
+ GetRenderSurface(host_impl->active_tree()->root_layer_for_testing());
gfx::Rect root_damage;
EXPECT_TRUE(
root_surface->damage_tracker()->GetDamageRectIfValid(&root_damage));
@@ -471,7 +474,7 @@ class LayerTreeHostDamageTestScrollbarCommitDoesNoDamage
DrawResult draw_result) override {
EXPECT_EQ(DRAW_SUCCESS, draw_result);
RenderSurfaceImpl* root_surface =
- host_impl->active_tree()->root_layer_for_testing()->GetRenderSurface();
+ GetRenderSurface(host_impl->active_tree()->root_layer_for_testing());
gfx::Rect root_damage;
EXPECT_TRUE(
root_surface->damage_tracker()->GetDamageRectIfValid(&root_damage));
diff --git a/chromium/cc/trees/layer_tree_host_unittest_occlusion.cc b/chromium/cc/trees/layer_tree_host_unittest_occlusion.cc
index 3202bb93f1a..d979e0b46ea 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_occlusion.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_occlusion.cc
@@ -7,6 +7,7 @@
#include "cc/layers/layer.h"
#include "cc/layers/picture_layer.h"
#include "cc/test/fake_content_layer_client.h"
+#include "cc/test/layer_test_common.h"
#include "cc/test/layer_tree_test.h"
#include "cc/trees/layer_tree_impl.h"
@@ -52,8 +53,8 @@ class LayerTreeHostOcclusionTestDrawPropertiesOnLayer
LayerImpl* child = impl->active_tree()->LayerById(child_->id());
// Verify the draw properties are valid.
- EXPECT_TRUE(root->is_drawn_render_surface_layer_list_member());
- EXPECT_TRUE(child->is_drawn_render_surface_layer_list_member());
+ EXPECT_TRUE(root->contributes_to_drawn_render_surface());
+ EXPECT_TRUE(child->contributes_to_drawn_render_surface());
EXPECT_OCCLUSION_EQ(
Occlusion(child->DrawTransform(), SimpleEnclosedRegion(),
@@ -106,13 +107,13 @@ class LayerTreeHostOcclusionTestDrawPropertiesOnSurface
void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
LayerImpl* root = impl->active_tree()->root_layer_for_testing();
LayerImpl* child = impl->active_tree()->LayerById(child_->id());
- RenderSurfaceImpl* surface = child->GetRenderSurface();
+ RenderSurfaceImpl* surface = GetRenderSurface(child);
// Verify the draw properties are valid.
- EXPECT_TRUE(root->is_drawn_render_surface_layer_list_member());
- EXPECT_TRUE(child->is_drawn_render_surface_layer_list_member());
- EXPECT_TRUE(child->GetRenderSurface());
- EXPECT_EQ(child->GetRenderSurface(), child->render_target());
+ EXPECT_TRUE(root->contributes_to_drawn_render_surface());
+ EXPECT_TRUE(child->contributes_to_drawn_render_surface());
+ EXPECT_TRUE(GetRenderSurface(child));
+ EXPECT_EQ(GetRenderSurface(child), child->render_target());
EXPECT_OCCLUSION_EQ(
Occlusion(surface->draw_transform(), SimpleEnclosedRegion(),
@@ -173,14 +174,14 @@ class LayerTreeHostOcclusionTestDrawPropertiesOnMask
void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
LayerImpl* root = impl->active_tree()->root_layer_for_testing();
LayerImpl* child = impl->active_tree()->LayerById(child_->id());
- RenderSurfaceImpl* surface = child->GetRenderSurface();
+ RenderSurfaceImpl* surface = GetRenderSurface(child);
LayerImpl* mask = surface->MaskLayer();
// Verify the draw properties are valid.
- EXPECT_TRUE(root->is_drawn_render_surface_layer_list_member());
- EXPECT_TRUE(child->is_drawn_render_surface_layer_list_member());
- EXPECT_TRUE(child->GetRenderSurface());
- EXPECT_EQ(child->GetRenderSurface(), child->render_target());
+ EXPECT_TRUE(root->contributes_to_drawn_render_surface());
+ EXPECT_TRUE(child->contributes_to_drawn_render_surface());
+ EXPECT_TRUE(GetRenderSurface(child));
+ EXPECT_EQ(GetRenderSurface(child), child->render_target());
gfx::Transform transform = surface->draw_transform();
transform.PreconcatTransform(child->DrawTransform());
@@ -245,7 +246,7 @@ class LayerTreeHostOcclusionTestDrawPropertiesOnScaledMask
void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
LayerImpl* child = impl->active_tree()->LayerById(child_->id());
- LayerImpl* mask = child->GetRenderSurface()->MaskLayer();
+ LayerImpl* mask = GetRenderSurface(child)->MaskLayer();
gfx::Transform scale;
scale.Scale(2, 2);
diff --git a/chromium/cc/trees/layer_tree_host_unittest_picture.cc b/chromium/cc/trees/layer_tree_host_unittest_picture.cc
index 55eabcb1eb7..e4fefef207c 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_picture.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_picture.cc
@@ -423,8 +423,11 @@ class LayerTreeHostPictureTestRSLLMembershipWithScale
picture_->SetBounds(gfx::Size(100, 100));
pinch_->AddChild(picture_);
- layer_tree_host()->RegisterViewportLayers(NULL, page_scale_layer, pinch_,
- nullptr);
+ LayerTreeHost::ViewportLayers viewport_layers;
+ viewport_layers.page_scale = page_scale_layer;
+ viewport_layers.inner_viewport_container = root_clip;
+ viewport_layers.inner_viewport_scroll = pinch_;
+ layer_tree_host()->RegisterViewportLayers(viewport_layers);
layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 1.f, 4.f);
layer_tree_host()->SetRootLayer(root_clip);
LayerTreeHostPictureTest::SetupTree();
diff --git a/chromium/cc/trees/layer_tree_host_unittest_scroll.cc b/chromium/cc/trees/layer_tree_host_unittest_scroll.cc
index b547fefcc45..e9a1e5d6b2e 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_scroll.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_scroll.cc
@@ -1417,7 +1417,8 @@ class LayerTreeHostScrollTestLayerStructureChange
virtual void DidScroll(Layer* layer) {
if (scroll_destroy_whole_tree_) {
- layer_tree_host()->RegisterViewportLayers(NULL, NULL, NULL, NULL);
+ layer_tree_host()->RegisterViewportLayers(
+ LayerTreeHost::ViewportLayers());
layer_tree_host()->SetRootLayer(NULL);
EndTest();
return;
@@ -2132,6 +2133,25 @@ class LayerTreeHostScrollTestImplSideInvalidation
SignalCompletionIfPossible();
}
+ void WillNotifyReadyToActivateOnThread(
+ LayerTreeHostImpl* host_impl) override {
+ // Ensure that the scroll-offsets on the TransformTree are consistent with
+ // the synced scroll offsets, for the pending tree.
+ if (!host_impl->pending_tree())
+ return;
+
+ LayerImpl* scroll_layer =
+ host_impl->pending_tree()->OuterViewportScrollLayer();
+ gfx::ScrollOffset scroll_offset = scroll_layer->CurrentScrollOffset();
+ int transform_index = scroll_layer->transform_tree_index();
+ gfx::ScrollOffset transform_tree_scroll_offset =
+ host_impl->pending_tree()
+ ->property_trees()
+ ->transform_tree.Node(transform_index)
+ ->scroll_offset;
+ EXPECT_EQ(scroll_offset, transform_tree_scroll_offset);
+ }
+
void SignalCompletionIfPossible() {
if (!invalidated_on_impl_thread_ || !impl_side_invalidation_event_)
return;
diff --git a/chromium/cc/trees/layer_tree_host_unittest_video.cc b/chromium/cc/trees/layer_tree_host_unittest_video.cc
index ae48abaa7b3..1c659af77e1 100644
--- a/chromium/cc/trees/layer_tree_host_unittest_video.cc
+++ b/chromium/cc/trees/layer_tree_host_unittest_video.cc
@@ -8,6 +8,7 @@
#include "cc/layers/video_layer.h"
#include "cc/layers/video_layer_impl.h"
#include "cc/test/fake_video_frame_provider.h"
+#include "cc/test/layer_test_common.h"
#include "cc/test/layer_tree_test.h"
#include "cc/trees/damage_tracker.h"
#include "cc/trees/layer_tree_impl.h"
@@ -48,7 +49,7 @@ class LayerTreeHostVideoTestSetNeedsDisplay
LayerTreeHostImpl::FrameData* frame,
DrawResult draw_result) override {
LayerImpl* root_layer = host_impl->active_tree()->root_layer_for_testing();
- RenderSurfaceImpl* root_surface = root_layer->GetRenderSurface();
+ RenderSurfaceImpl* root_surface = GetRenderSurface(root_layer);
gfx::Rect damage_rect;
EXPECT_TRUE(
root_surface->damage_tracker()->GetDamageRectIfValid(&damage_rect));
diff --git a/chromium/cc/trees/layer_tree_impl.cc b/chromium/cc/trees/layer_tree_impl.cc
index 12ebf3fa413..2c57e5a1f0e 100644
--- a/chromium/cc/trees/layer_tree_impl.cc
+++ b/chromium/cc/trees/layer_tree_impl.cc
@@ -51,6 +51,21 @@
namespace cc {
+void LayerTreeLifecycle::AdvanceTo(LifecycleState next_state) {
+ switch (next_state) {
+ case (kNotSyncing):
+ DCHECK_EQ(state_, kLastSyncState);
+ break;
+ case (kBeginningSync):
+ case (kSyncedPropertyTrees):
+ case (kSyncedLayerProperties):
+ // Only allow tree synchronization states to be transitioned in order.
+ DCHECK_EQ(state_ + 1, next_state);
+ break;
+ }
+ state_ = next_state;
+}
+
LayerTreeImpl::LayerTreeImpl(
LayerTreeHostImpl* layer_tree_host_impl,
scoped_refptr<SyncedProperty<ScaleGroup>> page_scale_factor,
@@ -64,10 +79,6 @@ LayerTreeImpl::LayerTreeImpl(
background_color_(0),
has_transparent_background_(false),
last_scrolled_scroll_node_index_(ScrollTree::kInvalidNodeId),
- overscroll_elasticity_layer_id_(Layer::INVALID_ID),
- page_scale_layer_id_(Layer::INVALID_ID),
- inner_viewport_scroll_layer_id_(Layer::INVALID_ID),
- outer_viewport_scroll_layer_id_(Layer::INVALID_ID),
page_scale_factor_(page_scale_factor),
min_page_scale_factor_(0),
max_page_scale_factor_(0),
@@ -139,21 +150,26 @@ void LayerTreeImpl::RecreateTileResources() {
}
bool LayerTreeImpl::IsViewportLayerId(int id) const {
- if (id == inner_viewport_scroll_layer_id_ ||
- id == outer_viewport_scroll_layer_id_)
- return true;
- if (InnerViewportContainerLayer() &&
- id == InnerViewportContainerLayer()->id())
- return true;
- if (OuterViewportContainerLayer() &&
- id == OuterViewportContainerLayer()->id())
- return true;
-
+#if DCHECK_IS_ON()
+ // Ensure the LayerImpl viewport layer types correspond to the LayerTreeImpl's
+ // viewport layers.
+ if (id == viewport_layer_ids_.inner_viewport_container)
+ DCHECK(LayerById(id)->viewport_layer_type() == INNER_VIEWPORT_CONTAINER);
+ if (id == viewport_layer_ids_.outer_viewport_container)
+ DCHECK(LayerById(id)->viewport_layer_type() == OUTER_VIEWPORT_CONTAINER);
+ if (id == viewport_layer_ids_.inner_viewport_scroll)
+ DCHECK(LayerById(id)->viewport_layer_type() == INNER_VIEWPORT_SCROLL);
+ if (id == viewport_layer_ids_.outer_viewport_scroll)
+ DCHECK(LayerById(id)->viewport_layer_type() == OUTER_VIEWPORT_SCROLL);
+#endif
+ if (auto* layer = LayerById(id))
+ return layer->viewport_layer_type() != NOT_VIEWPORT_LAYER;
return false;
}
void LayerTreeImpl::DidUpdateScrollOffset(int layer_id) {
DidUpdateScrollState(layer_id);
+ DCHECK(lifecycle().AllowsPropertyTreeAccess());
TransformTree& transform_tree = property_trees()->transform_tree;
ScrollTree& scroll_tree = property_trees()->scroll_tree;
int transform_id = TransformTree::kInvalidNodeId;
@@ -191,6 +207,12 @@ void LayerTreeImpl::DidUpdateScrollState(int layer_id) {
if (!IsActiveTree())
return;
+ DCHECK(lifecycle().AllowsPropertyTreeAccess());
+
+ // The scroll_clip_layer Layer properties should be up-to-date.
+ // TODO(pdr): This DCHECK fails on existing tests but should be enabled.
+ // DCHECK(lifecycle().AllowsLayerPropertyAccess());
+
if (layer_id == Layer::INVALID_ID)
return;
@@ -202,8 +224,8 @@ void LayerTreeImpl::DidUpdateScrollState(int layer_id) {
// For scrollbar purposes, a change to any of the four viewport layers
// should affect the scrollbars tied to the outermost layers, which express
// the sum of the entire viewport.
- scroll_layer_id = outer_viewport_scroll_layer_id_;
- clip_layer_id = InnerViewportContainerLayer()->id();
+ scroll_layer_id = viewport_layer_ids_.outer_viewport_scroll;
+ clip_layer_id = viewport_layer_ids_.inner_viewport_container;
} else {
// If the clip layer id was passed in, then look up the scroll layer, or
// vice versa.
@@ -242,55 +264,28 @@ void LayerTreeImpl::UpdateScrollbars(int scroll_layer_id, int clip_layer_id) {
clip_size.Scale(1 / current_page_scale_factor());
}
- bool scrollbar_needs_animation = false;
- bool clip_layer_size_did_change = false;
- bool scroll_layer_size_did_change = false;
bool y_offset_did_change = false;
- for (ScrollbarLayerImplBase* scrollbar : ScrollbarsFor(scroll_layer_id)) {
+ for (auto* scrollbar : ScrollbarsFor(scroll_layer->element_id())) {
if (scrollbar->orientation() == HORIZONTAL) {
- scrollbar_needs_animation |= scrollbar->SetCurrentPos(current_offset.x());
- clip_layer_size_did_change |=
- scrollbar->SetClipLayerLength(clip_size.width());
- scroll_layer_size_did_change |=
- scrollbar->SetScrollLayerLength(scroll_size.width());
+ scrollbar->SetCurrentPos(current_offset.x());
+ scrollbar->SetClipLayerLength(clip_size.width());
+ scrollbar->SetScrollLayerLength(scroll_size.width());
} else {
- scrollbar_needs_animation |= y_offset_did_change |=
- scrollbar->SetCurrentPos(current_offset.y());
- clip_layer_size_did_change |=
- scrollbar->SetClipLayerLength(clip_size.height());
- scroll_layer_size_did_change |=
- scrollbar->SetScrollLayerLength(scroll_size.height());
+ y_offset_did_change = scrollbar->SetCurrentPos(current_offset.y());
+ scrollbar->SetClipLayerLength(clip_size.height());
+ scrollbar->SetScrollLayerLength(scroll_size.height());
}
- scrollbar_needs_animation |=
- scrollbar->SetVerticalAdjust(clip_layer->bounds_delta().y());
+ scrollbar->SetVerticalAdjust(clip_layer->ViewportBoundsDelta().y());
}
- scrollbar_needs_animation |=
- (clip_layer_size_did_change || scroll_layer_size_did_change);
-
if (y_offset_did_change && IsViewportLayerId(scroll_layer_id))
TRACE_COUNTER_ID1("cc", "scroll_offset_y", scroll_layer->id(),
current_offset.y());
-
- if (scrollbar_needs_animation) {
- ScrollbarAnimationController* controller =
- layer_tree_host_impl_->ScrollbarAnimationControllerForId(
- scroll_layer_id);
- if (!controller)
- return;
-
- // TODO(chaopeng) clip_layer_size_did_change should call DidResize after
- // crbug.com/701810 got fixed.
- if (scroll_layer_size_did_change) {
- controller->DidResize();
- } else {
- controller->DidScrollUpdate();
- }
- }
}
-RenderSurfaceImpl* LayerTreeImpl::RootRenderSurface() const {
- return layer_list_.empty() ? nullptr : layer_list_[0]->GetRenderSurface();
+const RenderSurfaceImpl* LayerTreeImpl::RootRenderSurface() const {
+ return property_trees_.effect_tree.GetRenderSurface(
+ EffectTree::kContentsRootNodeId);
}
bool LayerTreeImpl::LayerListIsEmpty() const {
@@ -330,7 +325,7 @@ void LayerTreeImpl::BuildLayerListForTesting() {
}
void LayerTreeImpl::InvalidateRegionForImages(
- const ImageIdFlatSet& images_to_invalidate) {
+ const PaintImageIdFlatSet& images_to_invalidate) {
DCHECK(IsSyncTree());
if (images_to_invalidate.empty())
@@ -344,14 +339,6 @@ bool LayerTreeImpl::IsRootLayer(const LayerImpl* layer) const {
return layer_list_.empty() ? false : layer_list_[0] == layer;
}
-LayerImpl* LayerTreeImpl::InnerViewportScrollLayer() const {
- return LayerById(inner_viewport_scroll_layer_id_);
-}
-
-LayerImpl* LayerTreeImpl::OuterViewportScrollLayer() const {
- return LayerById(outer_viewport_scroll_layer_id_);
-}
-
gfx::ScrollOffset LayerTreeImpl::TotalScrollOffset() const {
gfx::ScrollOffset offset;
@@ -379,28 +366,13 @@ gfx::ScrollOffset LayerTreeImpl::TotalMaxScrollOffset() const {
std::unique_ptr<OwnedLayerImplList> LayerTreeImpl::DetachLayers() {
root_layer_for_testing_ = nullptr;
layer_list_.clear();
- render_surface_layer_list_.clear();
+ render_surface_list_.clear();
set_needs_update_draw_properties();
std::unique_ptr<OwnedLayerImplList> ret = std::move(layers_);
layers_.reset(new OwnedLayerImplList);
return ret;
}
-static void UpdateClipTreeForBoundsDeltaOnLayer(LayerImpl* layer,
- ClipTree* clip_tree) {
- if (layer && layer->masks_to_bounds()) {
- ClipNode* clip_node = clip_tree->Node(layer->clip_tree_index());
- if (clip_node) {
- DCHECK_EQ(layer->id(), clip_node->owning_layer_id);
- gfx::SizeF bounds = gfx::SizeF(layer->bounds());
- if (clip_node->clip.size() != bounds) {
- clip_node->clip.set_size(bounds);
- clip_tree->set_needs_update(true);
- }
- }
- }
-}
-
void LayerTreeImpl::SetPropertyTrees(PropertyTrees* property_trees) {
std::vector<std::unique_ptr<RenderSurfaceImpl>> old_render_surfaces;
property_trees_.effect_tree.TakeRenderSurfaces(&old_render_surfaces);
@@ -421,33 +393,17 @@ void LayerTreeImpl::SetPropertyTrees(PropertyTrees* property_trees) {
property_trees_.effect_tree.set_needs_update(true);
}
-void LayerTreeImpl::UpdatePropertyTreesForBoundsDelta() {
- DCHECK(IsActiveTree());
- LayerImpl* inner_container = InnerViewportContainerLayer();
- LayerImpl* outer_container = OuterViewportContainerLayer();
- LayerImpl* inner_scroll = InnerViewportScrollLayer();
-
- UpdateClipTreeForBoundsDeltaOnLayer(inner_container,
- &property_trees_.clip_tree);
- UpdateClipTreeForBoundsDeltaOnLayer(InnerViewportScrollLayer(),
- &property_trees_.clip_tree);
- UpdateClipTreeForBoundsDeltaOnLayer(outer_container,
- &property_trees_.clip_tree);
-
- if (inner_container)
- property_trees_.SetInnerViewportContainerBoundsDelta(
- inner_container->bounds_delta());
- if (outer_container)
- property_trees_.SetOuterViewportContainerBoundsDelta(
- outer_container->bounds_delta());
- if (inner_scroll)
- property_trees_.SetInnerViewportScrollBoundsDelta(
- inner_scroll->bounds_delta());
-}
-
-void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) {
- // The request queue should have been processed and does not require a push.
- DCHECK_EQ(ui_resource_request_queue_.size(), 0u);
+void LayerTreeImpl::PushPropertyTreesTo(LayerTreeImpl* target_tree) {
+ // Property trees may store damage status. We preserve the active tree
+ // damage status by pushing the damage status from active tree property
+ // trees to pending tree property trees or by moving it onto the layers.
+ if (target_tree->property_trees()->changed) {
+ if (property_trees()->sequence_number ==
+ target_tree->property_trees()->sequence_number)
+ target_tree->property_trees()->PushChangeTrackingTo(property_trees());
+ else
+ target_tree->MoveChangeTrackingToLayers();
+ }
// To maintain the current scrolling node we need to use element ids which
// are stable across the property tree update in SetPropertyTrees.
@@ -459,24 +415,19 @@ void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) {
ScrollNode* scrolling_node = nullptr;
if (scrolling_element_id) {
- auto& scroll_node_index_map =
- target_tree->property_trees()->element_id_to_scroll_node_index;
- auto scrolling_node_it = scroll_node_index_map.find(scrolling_element_id);
- if (scrolling_node_it != scroll_node_index_map.end()) {
- int index = scrolling_node_it->second;
- scrolling_node = target_tree->property_trees()->scroll_tree.Node(index);
- }
+ auto& scroll_tree = target_tree->property_trees()->scroll_tree;
+ scrolling_node = scroll_tree.FindNodeFromElementId(scrolling_element_id);
}
target_tree->SetCurrentlyScrollingNode(scrolling_node);
+}
+
+void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) {
+ // The request queue should have been processed and does not require a push.
+ DCHECK_EQ(ui_resource_request_queue_.size(), 0u);
target_tree->property_trees()->scroll_tree.PushScrollUpdatesFromPendingTree(
&property_trees_, target_tree);
- // This needs to be called early so that we don't clamp with incorrect max
- // offsets when UpdateViewportContainerSizes is called from e.g.
- // PushBrowserControls
- target_tree->UpdatePropertyTreesForBoundsDelta();
-
if (next_activation_forces_redraw_) {
target_tree->ForceRedrawNextActivation();
next_activation_forces_redraw_ = false;
@@ -491,6 +442,10 @@ void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) {
target_tree->set_bottom_controls_height(bottom_controls_height_);
target_tree->PushBrowserControls(nullptr);
+ // The page scale factor update can affect scrolling which requires that
+ // these ids are set, so this must be before PushPageScaleFactorAndLimits.
+ target_tree->SetViewportLayersFromIds(viewport_layer_ids_);
+
// Active tree already shares the page_scale_factor object with pending
// tree so only the limits need to be provided.
target_tree->PushPageScaleFactorAndLimits(nullptr, min_page_scale_factor(),
@@ -507,10 +462,6 @@ void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) {
target_tree->pending_page_scale_animation_ =
std::move(pending_page_scale_animation_);
- target_tree->SetViewportLayersFromIds(
- overscroll_elasticity_layer_id_, page_scale_layer_id_,
- inner_viewport_scroll_layer_id_, outer_viewport_scroll_layer_id_);
-
target_tree->RegisterSelection(selection_);
// This should match the property synchronization in
@@ -543,16 +494,17 @@ void LayerTreeImpl::PushPropertiesTo(LayerTreeImpl* target_tree) {
target_tree->has_ever_been_drawn_ = false;
// Note: this needs to happen after SetPropertyTrees.
- target_tree->ShowScrollbars();
+ target_tree->HandleScrollbarShowRequestsFromMain();
}
-void LayerTreeImpl::ShowScrollbars() {
+void LayerTreeImpl::HandleScrollbarShowRequestsFromMain() {
LayerTreeHostCommon::CallFunctionForEveryLayer(this, [this](
LayerImpl* layer) {
if (!layer->needs_show_scrollbars())
return;
ScrollbarAnimationController* controller =
- layer_tree_host_impl_->ScrollbarAnimationControllerForId(layer->id());
+ layer_tree_host_impl_->ScrollbarAnimationControllerForElementId(
+ layer->element_id());
if (controller) {
controller->DidRequestShowFromMainThread();
layer->set_needs_show_scrollbars(false);
@@ -654,24 +606,14 @@ void LayerTreeImpl::RemoveFromElementMap(LayerImpl* layer) {
element_layers_map_.erase(layer->element_id());
}
-void LayerTreeImpl::AddToOpacityAnimationsMap(int id, float opacity) {
- if (LayerImpl* layer = LayerById(id))
- element_id_to_opacity_animations_[layer->element_id()] = opacity;
-}
-
void LayerTreeImpl::SetTransformMutated(ElementId element_id,
const gfx::Transform& transform) {
DCHECK_EQ(1u, property_trees()->element_id_to_transform_node_index.count(
element_id));
element_id_to_transform_animations_[element_id] = transform;
- if (!property_trees()->transform_tree.OnTransformAnimated(element_id,
- transform))
- return;
-
- if (LayerImpl* layer = LayerByElementId(element_id))
- layer->set_was_ever_ready_since_last_transform_animation(false);
-
- set_needs_update_draw_properties();
+ if (property_trees()->transform_tree.OnTransformAnimated(element_id,
+ transform))
+ set_needs_update_draw_properties();
}
void LayerTreeImpl::SetOpacityMutated(ElementId element_id, float opacity) {
@@ -691,18 +633,6 @@ void LayerTreeImpl::SetFilterMutated(ElementId element_id,
set_needs_update_draw_properties();
}
-LayerImpl* LayerTreeImpl::InnerViewportContainerLayer() const {
- return InnerViewportScrollLayer()
- ? InnerViewportScrollLayer()->scroll_clip_layer()
- : NULL;
-}
-
-LayerImpl* LayerTreeImpl::OuterViewportContainerLayer() const {
- return OuterViewportScrollLayer()
- ? OuterViewportScrollLayer()->scroll_clip_layer()
- : NULL;
-}
-
ScrollNode* LayerTreeImpl::CurrentlyScrollingNode() {
DCHECK(IsActiveTree());
return property_trees_.scroll_tree.CurrentlyScrollingNode();
@@ -736,14 +666,12 @@ void LayerTreeImpl::SetCurrentlyScrollingNode(ScrollNode* node) {
if (old_element_id == new_element_id)
return;
- // TODO(pdr): Make the scrollbar animation controller lookup based on
- // element ids instead of layer ids.
ScrollbarAnimationController* old_animation_controller =
- layer_tree_host_impl_->ScrollbarAnimationControllerForId(
- LayerIdByElementId(old_element_id));
+ layer_tree_host_impl_->ScrollbarAnimationControllerForElementId(
+ old_element_id);
ScrollbarAnimationController* new_animation_controller =
- layer_tree_host_impl_->ScrollbarAnimationControllerForId(
- LayerIdByElementId(new_element_id));
+ layer_tree_host_impl_->ScrollbarAnimationControllerForElementId(
+ new_element_id);
if (old_animation_controller)
old_animation_controller->DidScrollEnd();
@@ -766,7 +694,8 @@ float LayerTreeImpl::ClampPageScaleFactorToLimits(
return page_scale_factor;
}
-void LayerTreeImpl::UpdatePropertyTreeScrollingAndAnimationFromMainThread() {
+void LayerTreeImpl::UpdatePropertyTreeScrollingAndAnimationFromMainThread(
+ bool is_impl_side_update) {
// TODO(enne): This should get replaced by pulling out scrolling and
// animations into their own trees. Then scrolls and animations would have
// their own ways of synchronizing across commits. This occurs to push
@@ -775,13 +704,19 @@ void LayerTreeImpl::UpdatePropertyTreeScrollingAndAnimationFromMainThread() {
// frame to a newly-committed property tree.
if (layer_list_.empty())
return;
+
+ // Entries from |element_id_to_*_animations_| should be deleted only after
+ // they have been synchronized with the main thread, which will not be the
+ // case if this is an impl-side invalidation.
+ const bool can_delete_animations = !is_impl_side_update;
auto element_id_to_opacity = element_id_to_opacity_animations_.begin();
while (element_id_to_opacity != element_id_to_opacity_animations_.end()) {
const ElementId id = element_id_to_opacity->first;
if (EffectNode* node =
property_trees_.effect_tree.FindNodeFromElementId(id)) {
- if (!node->is_currently_animating_opacity ||
- node->opacity == element_id_to_opacity->second) {
+ if ((!node->is_currently_animating_opacity ||
+ node->opacity == element_id_to_opacity->second) &&
+ can_delete_animations) {
element_id_to_opacity_animations_.erase(element_id_to_opacity++);
continue;
}
@@ -796,8 +731,9 @@ void LayerTreeImpl::UpdatePropertyTreeScrollingAndAnimationFromMainThread() {
const ElementId id = element_id_to_filter->first;
if (EffectNode* node =
property_trees_.effect_tree.FindNodeFromElementId(id)) {
- if (!node->is_currently_animating_filter ||
- node->filters == element_id_to_filter->second) {
+ if ((!node->is_currently_animating_filter ||
+ node->filters == element_id_to_filter->second) &&
+ can_delete_animations) {
element_id_to_filter_animations_.erase(element_id_to_filter++);
continue;
}
@@ -812,8 +748,9 @@ void LayerTreeImpl::UpdatePropertyTreeScrollingAndAnimationFromMainThread() {
const ElementId id = element_id_to_transform->first;
if (TransformNode* node =
property_trees_.transform_tree.FindNodeFromElementId(id)) {
- if (!node->is_currently_animating ||
- node->local == element_id_to_transform->second) {
+ if ((!node->is_currently_animating ||
+ node->local == element_id_to_transform->second) &&
+ can_delete_animations) {
element_id_to_transform_animations_.erase(element_id_to_transform++);
continue;
}
@@ -831,6 +768,7 @@ void LayerTreeImpl::UpdatePropertyTreeScrollingAndAnimationFromMainThread() {
void LayerTreeImpl::SetPageScaleOnActiveTree(float active_page_scale) {
DCHECK(IsActiveTree());
+ DCHECK(lifecycle().AllowsPropertyTreeAccess());
if (page_scale_factor()->SetCurrent(
ClampPageScaleFactorToLimits(active_page_scale))) {
DidUpdatePageScale();
@@ -881,6 +819,7 @@ void LayerTreeImpl::PushPageScaleFactorAndLimits(const float* page_scale_factor,
if (changed_page_scale)
DidUpdatePageScale();
+ DCHECK(lifecycle().AllowsPropertyTreeAccess());
if (page_scale_factor) {
if (PageScaleLayer()) {
draw_property_utils::UpdatePageScaleFactor(
@@ -970,7 +909,14 @@ void LayerTreeImpl::DidUpdatePageScale() {
ClampPageScaleFactorToLimits(current_page_scale_factor()));
set_needs_update_draw_properties();
- DidUpdateScrollState(inner_viewport_scroll_layer_id_);
+ DidUpdateScrollState(viewport_layer_ids_.inner_viewport_scroll);
+
+ if (IsActiveTree() && layer_tree_host_impl_->ViewportMainScrollLayer()) {
+ if (ScrollbarAnimationController* controller =
+ layer_tree_host_impl_->ScrollbarAnimationControllerForElementId(
+ OuterViewportScrollLayer()->element_id()))
+ controller->DidScrollUpdate();
+ }
}
void LayerTreeImpl::SetDeviceScaleFactor(float device_scale_factor) {
@@ -1031,22 +977,22 @@ void LayerTreeImpl::ApplySentScrollAndScaleDeltasFromAbortedCommit() {
property_trees()->scroll_tree.ApplySentScrollDeltasFromAbortedCommit();
}
-void LayerTreeImpl::SetViewportLayersFromIds(
- int overscroll_elasticity_layer_id,
- int page_scale_layer_id,
- int inner_viewport_scroll_layer_id,
- int outer_viewport_scroll_layer_id) {
- overscroll_elasticity_layer_id_ = overscroll_elasticity_layer_id;
- page_scale_layer_id_ = page_scale_layer_id;
- inner_viewport_scroll_layer_id_ = inner_viewport_scroll_layer_id;
- outer_viewport_scroll_layer_id_ = outer_viewport_scroll_layer_id;
+void LayerTreeImpl::SetViewportLayersFromIds(const ViewportLayerIds& ids) {
+ viewport_layer_ids_ = ids;
+
+ // Set the viewport layer types.
+ if (auto* inner_container = InnerViewportContainerLayer())
+ inner_container->SetViewportLayerType(INNER_VIEWPORT_CONTAINER);
+ if (auto* inner_scroll = InnerViewportScrollLayer())
+ inner_scroll->SetViewportLayerType(INNER_VIEWPORT_SCROLL);
+ if (auto* outer_container = OuterViewportContainerLayer())
+ outer_container->SetViewportLayerType(OUTER_VIEWPORT_CONTAINER);
+ if (auto* outer_scroll = OuterViewportScrollLayer())
+ outer_scroll->SetViewportLayerType(OUTER_VIEWPORT_SCROLL);
}
void LayerTreeImpl::ClearViewportLayers() {
- overscroll_elasticity_layer_id_ = Layer::INVALID_ID;
- page_scale_layer_id_ = Layer::INVALID_ID;
- inner_viewport_scroll_layer_id_ = Layer::INVALID_ID;
- outer_viewport_scroll_layer_id_ = Layer::INVALID_ID;
+ SetViewportLayersFromIds(ViewportLayerIds());
}
// For unit tests, we use the layer's id as its element id.
@@ -1077,7 +1023,7 @@ bool LayerTreeImpl::UpdateDrawProperties(bool update_lcd_text) {
// Clear this after the renderer early out, as it should still be
// possible to hit test even without a renderer.
- render_surface_layer_list_.clear();
+ render_surface_list_.clear();
if (layer_list_.empty())
return false;
@@ -1087,24 +1033,18 @@ bool LayerTreeImpl::UpdateDrawProperties(bool update_lcd_text) {
TRACE_EVENT2(
"cc", "LayerTreeImpl::UpdateDrawProperties::CalculateDrawProperties",
"IsActive", IsActiveTree(), "SourceFrameNumber", source_frame_number_);
- // TODO(crbug.com/692780): Remove this option entirely once this get to
- // stable and proves it works.
- bool can_render_to_separate_surface = true;
-
// We verify visible rect calculations whenever we verify clip tree
// calculations except when this function is explicitly passed a flag asking
// us to skip it.
LayerTreeHostCommon::CalcDrawPropsImplInputs inputs(
- layer_list_[0], DrawViewportSize(),
+ layer_list_[0], DeviceViewport().size(),
layer_tree_host_impl_->DrawTransform(), device_scale_factor(),
current_page_scale_factor(), PageScaleLayer(),
InnerViewportScrollLayer(), OuterViewportScrollLayer(),
elastic_overscroll()->Current(IsActiveTree()),
OverscrollElasticityLayer(), resource_provider()->max_texture_size(),
- can_render_to_separate_surface,
settings().layer_transforms_should_scale_layer_contents,
- settings().use_layer_lists, &render_surface_layer_list_,
- &property_trees_);
+ &render_surface_list_, &property_trees_);
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
if (const char* client_name = GetClientNameForMetrics()) {
UMA_HISTOGRAM_COUNTS(
@@ -1114,7 +1054,7 @@ bool LayerTreeImpl::UpdateDrawProperties(bool update_lcd_text) {
timer.Elapsed().InMicroseconds());
UMA_HISTOGRAM_COUNTS_100(
base::StringPrintf("Compositing.%s.NumRenderSurfaces", client_name),
- base::saturated_cast<int>(render_surface_layer_list_.size()));
+ base::saturated_cast<int>(render_surface_list_.size()));
}
}
@@ -1122,8 +1062,7 @@ bool LayerTreeImpl::UpdateDrawProperties(bool update_lcd_text) {
TRACE_EVENT2("cc", "LayerTreeImpl::UpdateDrawProperties::Occlusion",
"IsActive", IsActiveTree(), "SourceFrameNumber",
source_frame_number_);
- OcclusionTracker occlusion_tracker(
- layer_list_[0]->GetRenderSurface()->content_rect());
+ OcclusionTracker occlusion_tracker(RootRenderSurface()->content_rect());
occlusion_tracker.set_minimum_tracking_size(
settings().minimum_occlusion_tracking_size);
@@ -1205,7 +1144,7 @@ bool LayerTreeImpl::UpdateDrawProperties(bool update_lcd_text) {
size_t layers_updated_count = 0;
bool tile_priorities_updated = false;
for (PictureLayerImpl* layer : picture_layers_) {
- if (!layer->is_drawn_render_surface_layer_list_member())
+ if (!layer->contributes_to_drawn_render_surface())
continue;
++layers_updated_count;
tile_priorities_updated |= layer->UpdateTiles();
@@ -1237,36 +1176,40 @@ void LayerTreeImpl::BuildPropertyTreesForTesting() {
OuterViewportScrollLayer(), OverscrollElasticityLayer(),
elastic_overscroll()->Current(IsActiveTree()),
current_page_scale_factor(), device_scale_factor(),
- gfx::Rect(DrawViewportSize()), layer_tree_host_impl_->DrawTransform(),
- &property_trees_);
+ gfx::Rect(DeviceViewport().size()),
+ layer_tree_host_impl_->DrawTransform(), &property_trees_);
property_trees_.transform_tree.set_source_to_parent_updates_allowed(false);
}
-const LayerImplList& LayerTreeImpl::RenderSurfaceLayerList() const {
+const RenderSurfaceList& LayerTreeImpl::GetRenderSurfaceList() const {
// If this assert triggers, then the list is dirty.
DCHECK(!needs_update_draw_properties_);
- return render_surface_layer_list_;
+ return render_surface_list_;
}
const Region& LayerTreeImpl::UnoccludedScreenSpaceRegion() const {
- // If this assert triggers, then the render_surface_layer_list_ is dirty, so
- // the unoccluded_screen_space_region_ is not valid anymore.
+ // If this assert triggers, then the render_surface_list_ is dirty, so the
+ // unoccluded_screen_space_region_ is not valid anymore.
DCHECK(!needs_update_draw_properties_);
return unoccluded_screen_space_region_;
}
gfx::SizeF LayerTreeImpl::ScrollableSize() const {
- LayerImpl* root_scroll_layer = OuterViewportScrollLayer()
- ? OuterViewportScrollLayer()
- : InnerViewportScrollLayer();
- if (!root_scroll_layer)
+ LayerImpl* root_scroll_layer = nullptr;
+ LayerImpl* root_container_layer = nullptr;
+ if (OuterViewportScrollLayer()) {
+ root_scroll_layer = OuterViewportScrollLayer();
+ root_container_layer = OuterViewportContainerLayer();
+ } else if (InnerViewportScrollLayer()) {
+ root_scroll_layer = InnerViewportScrollLayer();
+ root_container_layer = InnerViewportContainerLayer();
+ }
+
+ if (!root_scroll_layer || !root_container_layer)
return gfx::SizeF();
gfx::SizeF content_size = root_scroll_layer->BoundsForScrolling();
- gfx::SizeF viewport_size =
- root_scroll_layer->scroll_clip_layer()->BoundsForScrolling();
-
- content_size.SetToMax(viewport_size);
+ content_size.SetToMax(root_container_layer->BoundsForScrolling());
return content_size;
}
@@ -1460,36 +1403,31 @@ gfx::Rect LayerTreeImpl::DeviceViewport() const {
return layer_tree_host_impl_->DeviceViewport();
}
-gfx::Size LayerTreeImpl::DrawViewportSize() const {
- return layer_tree_host_impl_->DrawViewportSize();
-}
-
const gfx::Rect LayerTreeImpl::ViewportRectForTilePriority() const {
return layer_tree_host_impl_->ViewportRectForTilePriority();
}
std::unique_ptr<ScrollbarAnimationController>
-LayerTreeImpl::CreateScrollbarAnimationController(int scroll_layer_id) {
+LayerTreeImpl::CreateScrollbarAnimationController(ElementId scroll_element_id,
+ float initial_opacity) {
DCHECK(!settings().scrollbar_fade_delay.is_zero());
DCHECK(!settings().scrollbar_fade_duration.is_zero());
base::TimeDelta fade_delay = settings().scrollbar_fade_delay;
- base::TimeDelta fade_out_resize_delay =
- settings().scrollbar_fade_out_resize_delay;
base::TimeDelta fade_duration = settings().scrollbar_fade_duration;
switch (settings().scrollbar_animator) {
case LayerTreeSettings::ANDROID_OVERLAY: {
return ScrollbarAnimationController::
CreateScrollbarAnimationControllerAndroid(
- scroll_layer_id, layer_tree_host_impl_, fade_delay,
- fade_out_resize_delay, fade_duration);
+ scroll_element_id, layer_tree_host_impl_, fade_delay,
+ fade_duration, initial_opacity);
}
case LayerTreeSettings::AURA_OVERLAY: {
base::TimeDelta thinning_duration =
settings().scrollbar_thinning_duration;
return ScrollbarAnimationController::
CreateScrollbarAnimationControllerAuraOverlay(
- scroll_layer_id, layer_tree_host_impl_, fade_delay,
- fade_out_resize_delay, fade_duration, thinning_duration);
+ scroll_element_id, layer_tree_host_impl_, fade_delay,
+ fade_duration, thinning_duration, initial_opacity);
}
case LayerTreeSettings::NO_ANIMATOR:
NOTREACHED();
@@ -1522,7 +1460,7 @@ void LayerTreeImpl::GetAllPrioritizedTilesForTracing(
std::vector<PrioritizedTile>* prioritized_tiles) const {
for (auto it = layer_list_.rbegin(); it != layer_list_.rend(); ++it) {
LayerImpl* layer_impl = *it;
- if (!layer_impl->is_drawn_render_surface_layer_list_member())
+ if (!layer_impl->contributes_to_drawn_render_surface())
continue;
layer_impl->GetAllPrioritizedTilesForTracing(prioritized_tiles);
}
@@ -1534,7 +1472,7 @@ void LayerTreeImpl::AsValueInto(base::trace_event::TracedValue* state) const {
state->BeginArray("render_surface_layer_list");
for (auto it = layer_list_.rbegin(); it != layer_list_.rend(); ++it) {
- if (!(*it)->is_drawn_render_surface_layer_list_member())
+ if (!(*it)->contributes_to_drawn_render_surface())
continue;
TracedValue::AppendIDRef(*it, state);
}
@@ -1719,41 +1657,65 @@ void LayerTreeImpl::UnregisterPictureLayerImpl(PictureLayerImpl* layer) {
}
void LayerTreeImpl::RegisterScrollbar(ScrollbarLayerImplBase* scrollbar_layer) {
- if (scrollbar_layer->ScrollLayerId() == Layer::INVALID_ID)
+ ElementId scroll_element_id = scrollbar_layer->scroll_element_id();
+ if (!scroll_element_id)
return;
- scrollbar_map_.insert(std::pair<int, int>(scrollbar_layer->ScrollLayerId(),
- scrollbar_layer->id()));
- if (IsActiveTree() && scrollbar_layer->is_overlay_scrollbar())
+ auto& scrollbar_ids = element_id_to_scrollbar_layer_ids_[scroll_element_id];
+ if (scrollbar_layer->orientation() == HORIZONTAL) {
+ DCHECK_EQ(scrollbar_ids.horizontal, Layer::INVALID_ID)
+ << "Existing scrollbar should have been unregistered.";
+ scrollbar_ids.horizontal = scrollbar_layer->id();
+ } else {
+ DCHECK_EQ(scrollbar_ids.vertical, Layer::INVALID_ID)
+ << "Existing scrollbar should have been unregistered.";
+ scrollbar_ids.vertical = scrollbar_layer->id();
+ }
+
+ if (IsActiveTree() && scrollbar_layer->is_overlay_scrollbar() &&
+ scrollbar_layer->GetScrollbarAnimator() !=
+ LayerTreeSettings::NO_ANIMATOR) {
layer_tree_host_impl_->RegisterScrollbarAnimationController(
- scrollbar_layer->ScrollLayerId());
+ scroll_element_id, scrollbar_layer->Opacity());
+ }
- DidUpdateScrollState(scrollbar_layer->ScrollLayerId());
+ // TODO(pdr): Refactor DidUpdateScrollState to use ElementIds instead of
+ // layer ids and remove this use of LayerIdByElementId.
+ DidUpdateScrollState(LayerIdByElementId(scroll_element_id));
}
void LayerTreeImpl::UnregisterScrollbar(
ScrollbarLayerImplBase* scrollbar_layer) {
- int scroll_layer_id = scrollbar_layer->ScrollLayerId();
- if (scroll_layer_id == Layer::INVALID_ID)
+ ElementId scroll_element_id = scrollbar_layer->scroll_element_id();
+ if (!scroll_element_id)
return;
- auto scrollbar_range = scrollbar_map_.equal_range(scroll_layer_id);
- for (auto i = scrollbar_range.first; i != scrollbar_range.second; ++i)
- if (i->second == scrollbar_layer->id()) {
- scrollbar_map_.erase(i);
- break;
+ auto& scrollbar_ids = element_id_to_scrollbar_layer_ids_[scroll_element_id];
+ if (scrollbar_layer->orientation() == HORIZONTAL)
+ scrollbar_ids.horizontal = Layer::INVALID_ID;
+ else
+ scrollbar_ids.vertical = Layer::INVALID_ID;
+
+ if (scrollbar_ids.horizontal == Layer::INVALID_ID &&
+ scrollbar_ids.vertical == Layer::INVALID_ID) {
+ element_id_to_scrollbar_layer_ids_.erase(scroll_element_id);
+ if (IsActiveTree()) {
+ layer_tree_host_impl_->UnregisterScrollbarAnimationController(
+ scroll_element_id);
}
-
- if (IsActiveTree() && scrollbar_map_.count(scroll_layer_id) == 0)
- layer_tree_host_impl_->UnregisterScrollbarAnimationController(
- scroll_layer_id);
+ }
}
-ScrollbarSet LayerTreeImpl::ScrollbarsFor(int scroll_layer_id) const {
+ScrollbarSet LayerTreeImpl::ScrollbarsFor(ElementId scroll_element_id) const {
ScrollbarSet scrollbars;
- auto scrollbar_range = scrollbar_map_.equal_range(scroll_layer_id);
- for (auto i = scrollbar_range.first; i != scrollbar_range.second; ++i)
- scrollbars.insert(LayerById(i->second)->ToScrollbarLayer());
+ auto it = element_id_to_scrollbar_layer_ids_.find(scroll_element_id);
+ if (it != element_id_to_scrollbar_layer_ids_.end()) {
+ const ScrollbarLayerIds& layer_ids = it->second;
+ if (layer_ids.horizontal != Layer::INVALID_ID)
+ scrollbars.insert(LayerById(layer_ids.horizontal)->ToScrollbarLayer());
+ if (layer_ids.vertical != Layer::INVALID_ID)
+ scrollbars.insert(LayerById(layer_ids.vertical)->ToScrollbarLayer());
+ }
return scrollbars;
}
@@ -1765,6 +1727,9 @@ void LayerTreeImpl::RegisterScrollLayer(LayerImpl* layer) {
std::pair<int, int>(layer->scroll_clip_layer_id(), layer->id()));
DidUpdateScrollState(layer->id());
+
+ if (settings().scrollbar_animator == LayerTreeSettings::AURA_OVERLAY)
+ layer->set_needs_show_scrollbars(true);
}
void LayerTreeImpl::UnregisterScrollLayer(LayerImpl* layer) {
@@ -1854,20 +1819,6 @@ static bool PointHitsRegion(const gfx::PointF& screen_space_point,
gfx::ToRoundedPoint(hit_test_point_in_layer_space));
}
-static const gfx::Transform SurfaceScreenSpaceTransform(
- const LayerImpl* layer) {
- const PropertyTrees* property_trees =
- layer->layer_tree_impl()->property_trees();
- RenderSurfaceImpl* render_surface = layer->GetRenderSurface();
- DCHECK(render_surface);
- return layer->is_drawn_render_surface_layer_list_member()
- ? render_surface->screen_space_transform()
- : property_trees
- ->ToScreenSpaceTransformWithoutSurfaceContentsScale(
- render_surface->TransformTreeIndex(),
- render_surface->EffectTreeIndex());
-}
-
static bool PointIsClippedByAncestorClipNode(
const gfx::PointF& screen_space_point,
const LayerImpl* layer) {
@@ -1901,15 +1852,6 @@ static bool PointIsClippedByAncestorClipNode(
return true;
}
}
- const LayerImpl* clip_node_owner =
- layer->layer_tree_impl()->LayerById(clip_node->owning_layer_id);
- RenderSurfaceImpl* render_surface = clip_node_owner->GetRenderSurface();
- if (render_surface &&
- !PointHitsRect(screen_space_point,
- SurfaceScreenSpaceTransform(clip_node_owner),
- render_surface->content_rect(), NULL)) {
- return true;
- }
}
return false;
}
@@ -2013,7 +1955,7 @@ LayerTreeImpl::FindFirstScrollingLayerOrDrawnScrollbarThatIsHitByPoint(
struct HitTestVisibleScrollableOrTouchableFunctor {
bool operator()(LayerImpl* layer) const {
return layer->scrollable() ||
- layer->is_drawn_render_surface_layer_list_member() ||
+ layer->contributes_to_drawn_render_surface() ||
!layer->touch_event_handler_region().IsEmpty();
}
};
diff --git a/chromium/cc/trees/layer_tree_impl.h b/chromium/cc/trees/layer_tree_impl.h
index 1d785f86e4e..ccff3c2447b 100644
--- a/chromium/cc/trees/layer_tree_impl.h
+++ b/chromium/cc/trees/layer_tree_impl.h
@@ -54,6 +54,35 @@ typedef std::vector<UIResourceRequest> UIResourceRequestQueue;
typedef SyncedProperty<AdditionGroup<float>> SyncedBrowserControls;
typedef SyncedProperty<AdditionGroup<gfx::Vector2dF>> SyncedElasticOverscroll;
+class LayerTreeLifecycle {
+ public:
+ enum LifecycleState {
+ kNotSyncing,
+
+ // The following states are the steps performed when syncing properties to
+ // this tree (see: LayerTreeHost::FinishCommitOnImplThread or
+ // LayerTreeHostImpl::ActivateSyncTree).
+ kBeginningSync,
+ kSyncedPropertyTrees,
+ kSyncedLayerProperties,
+ kLastSyncState = kSyncedLayerProperties,
+
+ // TODO(pdr): Add states to cover more than just the synchronization steps.
+ };
+
+ void AdvanceTo(LifecycleState);
+
+ bool AllowsPropertyTreeAccess() const {
+ return state_ == kNotSyncing || state_ >= kSyncedPropertyTrees;
+ }
+ bool AllowsLayerPropertyAccess() const {
+ return state_ == kNotSyncing || state_ >= kSyncedLayerProperties;
+ }
+
+ private:
+ LifecycleState state_ = kNotSyncing;
+};
+
class CC_EXPORT LayerTreeImpl {
public:
// This is the number of times a fixed point has to be hit continuously by a
@@ -92,10 +121,10 @@ class CC_EXPORT LayerTreeImpl {
BeginFrameArgs CurrentBeginFrameArgs() const;
base::TimeDelta CurrentBeginFrameInterval() const;
gfx::Rect DeviceViewport() const;
- gfx::Size DrawViewportSize() const;
const gfx::Rect ViewportRectForTilePriority() const;
std::unique_ptr<ScrollbarAnimationController>
- CreateScrollbarAnimationController(int scroll_layer_id);
+ CreateScrollbarAnimationController(ElementId scroll_element_id,
+ float initial_opacity);
void DidAnimateScrollOffset();
bool use_gpu_rasterization() const;
GpuRasterizationStatus GetGpuRasterizationStatus() const;
@@ -122,7 +151,7 @@ class CC_EXPORT LayerTreeImpl {
LayerImpl* root_layer_for_testing() {
return layer_list_.empty() ? nullptr : layer_list_[0];
}
- RenderSurfaceImpl* RootRenderSurface() const;
+ const RenderSurfaceImpl* RootRenderSurface() const;
bool LayerListIsEmpty() const;
void SetRootLayerForTesting(std::unique_ptr<LayerImpl>);
void OnCanDrawStateChangedForTree();
@@ -130,10 +159,14 @@ class CC_EXPORT LayerTreeImpl {
std::unique_ptr<OwnedLayerImplList> DetachLayers();
void SetPropertyTrees(PropertyTrees* property_trees);
- PropertyTrees* property_trees() { return &property_trees_; }
-
- void UpdatePropertyTreesForBoundsDelta();
+ PropertyTrees* property_trees() {
+ // TODO(pdr): We should enable this DCHECK because it will catch uses of
+ // stale property trees, but it currently fails too many existing tests.
+ // DCHECK(lifecycle().AllowsPropertyTreeAccess());
+ return &property_trees_;
+ }
+ void PushPropertyTreesTo(LayerTreeImpl* tree_impl);
void PushPropertiesTo(LayerTreeImpl* tree_impl);
void MoveChangeTrackingToLayers();
@@ -145,10 +178,6 @@ class CC_EXPORT LayerTreeImpl {
LayerImplList::reverse_iterator rbegin();
LayerImplList::reverse_iterator rend();
- // TODO(crbug.com/702832): This won't be needed if overlay scrollbars have
- // element ids.
- void AddToOpacityAnimationsMap(int id, float opacity);
-
void SetTransformMutated(ElementId element_id,
const gfx::Transform& transform);
void SetOpacityMutated(ElementId element_id, float opacity);
@@ -173,29 +202,44 @@ class CC_EXPORT LayerTreeImpl {
hud_layer_ = layer_impl;
}
- LayerImpl* InnerViewportScrollLayer() const;
- // This function may return NULL, it is the caller's responsibility to check.
- LayerImpl* OuterViewportScrollLayer() const;
gfx::ScrollOffset TotalScrollOffset() const;
gfx::ScrollOffset TotalMaxScrollOffset() const;
- LayerImpl* InnerViewportContainerLayer() const;
- LayerImpl* OuterViewportContainerLayer() const;
ScrollNode* CurrentlyScrollingNode();
const ScrollNode* CurrentlyScrollingNode() const;
int LastScrolledScrollNodeIndex() const;
void SetCurrentlyScrollingNode(ScrollNode* node);
void ClearCurrentlyScrollingNode();
- void SetViewportLayersFromIds(int overscroll_elasticity_layer,
- int page_scale_layer_id,
- int inner_viewport_scroll_layer_id,
- int outer_viewport_scroll_layer_id);
+ struct ViewportLayerIds {
+ int overscroll_elasticity = Layer::INVALID_ID;
+ int page_scale = Layer::INVALID_ID;
+ int inner_viewport_container = Layer::INVALID_ID;
+ int outer_viewport_container = Layer::INVALID_ID;
+ int inner_viewport_scroll = Layer::INVALID_ID;
+ int outer_viewport_scroll = Layer::INVALID_ID;
+ };
+ void SetViewportLayersFromIds(const ViewportLayerIds& viewport_layer_ids);
void ClearViewportLayers();
- LayerImpl* OverscrollElasticityLayer() {
- return LayerById(overscroll_elasticity_layer_id_);
+ LayerImpl* OverscrollElasticityLayer() const {
+ return LayerById(viewport_layer_ids_.overscroll_elasticity);
+ }
+ LayerImpl* PageScaleLayer() const {
+ return LayerById(viewport_layer_ids_.page_scale);
+ }
+ LayerImpl* InnerViewportContainerLayer() const {
+ return LayerById(viewport_layer_ids_.inner_viewport_container);
+ }
+ LayerImpl* OuterViewportContainerLayer() const {
+ return LayerById(viewport_layer_ids_.outer_viewport_container);
+ }
+ LayerImpl* InnerViewportScrollLayer() const {
+ return LayerById(viewport_layer_ids_.inner_viewport_scroll);
}
- LayerImpl* PageScaleLayer() { return LayerById(page_scale_layer_id_); }
+ LayerImpl* OuterViewportScrollLayer() const {
+ return LayerById(viewport_layer_ids_.outer_viewport_scroll);
+ }
+
void ApplySentScrollAndScaleDeltasFromAbortedCommit();
SkColor background_color() const { return background_color_; }
@@ -208,7 +252,8 @@ class CC_EXPORT LayerTreeImpl {
has_transparent_background_ = transparent;
}
- void UpdatePropertyTreeScrollingAndAnimationFromMainThread();
+ void UpdatePropertyTreeScrollingAndAnimationFromMainThread(
+ bool is_impl_side_update);
void SetPageScaleOnActiveTree(float active_page_scale);
void PushPageScaleFromMainThread(float page_scale_factor,
float min_page_scale_factor,
@@ -294,7 +339,7 @@ class CC_EXPORT LayerTreeImpl {
void set_ui_resource_request_queue(UIResourceRequestQueue queue);
- const LayerImplList& RenderSurfaceLayerList() const;
+ const RenderSurfaceList& GetRenderSurfaceList() const;
const Region& UnoccludedScreenSpaceRegion() const;
// These return the size of the root scrollable area and the size of
@@ -395,7 +440,7 @@ class CC_EXPORT LayerTreeImpl {
void RegisterScrollbar(ScrollbarLayerImplBase* scrollbar_layer);
void UnregisterScrollbar(ScrollbarLayerImplBase* scrollbar_layer);
- ScrollbarSet ScrollbarsFor(int scroll_layer_id) const;
+ ScrollbarSet ScrollbarsFor(ElementId scroll_element_id) const;
void RegisterScrollLayer(LayerImpl* layer);
void UnregisterScrollLayer(LayerImpl* layer);
@@ -465,8 +510,12 @@ class CC_EXPORT LayerTreeImpl {
void ClearLayerList();
void BuildLayerListForTesting();
+ void HandleScrollbarShowRequestsFromMain();
+
+ void InvalidateRegionForImages(
+ const PaintImageIdFlatSet& images_to_invalidate);
- void InvalidateRegionForImages(const ImageIdFlatSet& images_to_invalidate);
+ LayerTreeLifecycle& lifecycle() { return lifecycle_; }
protected:
float ClampPageScaleFactorToLimits(float page_scale_factor) const;
@@ -477,7 +526,6 @@ class CC_EXPORT LayerTreeImpl {
float max_page_scale_factor);
bool IsViewportLayerId(int id) const;
void UpdateScrollbars(int scroll_layer_id, int clip_layer_id);
- void ShowScrollbars();
void DidUpdatePageScale();
void PushBrowserControls(const float* top_controls_shown_ratio);
bool ClampBrowserControlsShownRatio();
@@ -492,10 +540,8 @@ class CC_EXPORT LayerTreeImpl {
bool has_transparent_background_;
int last_scrolled_scroll_node_index_;
- int overscroll_elasticity_layer_id_;
- int page_scale_layer_id_;
- int inner_viewport_scroll_layer_id_;
- int outer_viewport_scroll_layer_id_;
+
+ ViewportLayerIds viewport_layer_ids_;
LayerSelection selection_;
@@ -532,18 +578,21 @@ class CC_EXPORT LayerTreeImpl {
// derived from LayerImpl::scroll_clip_layer_ and exists to avoid O(n) walks.)
std::unordered_map<int, int> clip_scroll_map_;
- // Maps scroll layer ids to scrollbar layer ids. For each scroll layer, there
- // may be 1 or 2 scrollbar layers (for vertical and horizontal). (This is
- // derived from ScrollbarLayerImplBase::scroll_layer_id_ and exists to avoid
- // O(n) walks.)
- std::multimap<int, int> scrollbar_map_;
+ struct ScrollbarLayerIds {
+ int horizontal = Layer::INVALID_ID;
+ int vertical = Layer::INVALID_ID;
+ };
+ // Each scroll layer can have up to two scrollbar layers (vertical and
+ // horizontal). This mapping is maintained as part of scrollbar registration.
+ base::flat_map<ElementId, ScrollbarLayerIds>
+ element_id_to_scrollbar_layer_ids_;
std::vector<PictureLayerImpl*> picture_layers_;
LayerImplList surface_layers_;
- // List of visible layers for the most recently prepared frame.
- LayerImplList render_surface_layer_list_;
- // After drawing the |render_surface_layer_list_| the areas in this region
+ // List of render surfaces for the most recently prepared frame.
+ RenderSurfaceList render_surface_list_;
+ // After drawing the |render_surface_list_| the areas in this region
// would not be fully covered by opaque content.
Region unoccluded_screen_space_region_;
@@ -581,6 +630,10 @@ class CC_EXPORT LayerTreeImpl {
std::unique_ptr<PendingPageScaleAnimation> pending_page_scale_animation_;
+ // Tracks the lifecycle which is used for enforcing dependencies between
+ // lifecycle states. See: |LayerTreeLifecycle|.
+ LayerTreeLifecycle lifecycle_;
+
private:
DISALLOW_COPY_AND_ASSIGN(LayerTreeImpl);
};
diff --git a/chromium/cc/trees/layer_tree_impl_unittest.cc b/chromium/cc/trees/layer_tree_impl_unittest.cc
index 3b0cbeec663..836ba530118 100644
--- a/chromium/cc/trees/layer_tree_impl_unittest.cc
+++ b/chromium/cc/trees/layer_tree_impl_unittest.cc
@@ -36,8 +36,8 @@ class LayerTreeImplTest : public testing::Test {
LayerImpl* root_layer() { return impl_test_.root_layer_for_testing(); }
- const LayerImplList& RenderSurfaceLayerList() const {
- return host_impl().active_tree()->RenderSurfaceLayerList();
+ const RenderSurfaceList& GetRenderSurfaceList() const {
+ return host_impl().active_tree()->GetRenderSurfaceList();
}
void ExecuteCalculateDrawProperties(LayerImpl* root_layer) {
@@ -45,9 +45,9 @@ class LayerTreeImplTest : public testing::Test {
// empty.
DCHECK(!root_layer->bounds().IsEmpty());
- render_surface_layer_list_impl_.clear();
+ render_surface_list_impl_.clear();
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root_layer, root_layer->bounds(), &render_surface_layer_list_impl_);
+ root_layer, root_layer->bounds(), &render_surface_list_impl_);
inputs.can_adjust_raster_scales = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
}
@@ -105,7 +105,7 @@ class LayerTreeImplTest : public testing::Test {
host_impl().SetViewportSize(root->bounds());
host_impl().active_tree()->SetRootLayerForTesting(std::move(root));
host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
- CHECK_EQ(1u, RenderSurfaceLayerList().size());
+ CHECK_EQ(1u, GetRenderSurfaceList().size());
gfx::PointF test_point = gfx::PointF(1.f, 1.f);
LayerImpl* result_layer =
@@ -117,7 +117,7 @@ class LayerTreeImplTest : public testing::Test {
private:
LayerTestCommon::LayerImplTest impl_test_;
- std::vector<LayerImpl*> render_surface_layer_list_impl_;
+ RenderSurfaceList render_surface_list_impl_;
};
TEST_F(LayerTreeImplTest, HitTestingForSingleLayer) {
@@ -130,8 +130,8 @@ TEST_F(LayerTreeImplTest, HitTestingForSingleLayer) {
host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
// Sanity check the scenario we just created.
- ASSERT_EQ(1u, RenderSurfaceLayerList().size());
- ASSERT_EQ(1u, root_layer()->GetRenderSurface()->layer_list().size());
+ ASSERT_EQ(1u, GetRenderSurfaceList().size());
+ ASSERT_EQ(1, GetRenderSurface(root_layer())->num_contributors());
// Hit testing for a point outside the layer should return a null pointer.
gfx::PointF test_point(101.f, 101.f);
@@ -199,8 +199,8 @@ TEST_F(LayerTreeImplTest, HitTestingForSingleLayerAndHud) {
host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
// Sanity check the scenario we just created.
- ASSERT_EQ(1u, RenderSurfaceLayerList().size());
- ASSERT_EQ(2u, root_layer()->GetRenderSurface()->layer_list().size());
+ ASSERT_EQ(1u, GetRenderSurfaceList().size());
+ ASSERT_EQ(2, GetRenderSurface(root_layer())->num_contributors());
// Hit testing for a point inside HUD, but outside root should return null
gfx::PointF test_point(101.f, 101.f);
@@ -244,8 +244,8 @@ TEST_F(LayerTreeImplTest, HitTestingForUninvertibleTransform) {
host_impl().SetViewportSize(root->bounds());
host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
// Sanity check the scenario we just created.
- ASSERT_EQ(1u, RenderSurfaceLayerList().size());
- ASSERT_EQ(1u, root_layer()->GetRenderSurface()->layer_list().size());
+ ASSERT_EQ(1u, GetRenderSurfaceList().size());
+ ASSERT_EQ(1, GetRenderSurface(root_layer())->num_contributors());
ASSERT_FALSE(root_layer()->ScreenSpaceTransform().IsInvertible());
// Hit testing any point should not hit the layer. If the invertible matrix is
@@ -299,8 +299,8 @@ TEST_F(LayerTreeImplTest, HitTestingForSinglePositionedLayer) {
host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
// Sanity check the scenario we just created.
- ASSERT_EQ(1u, RenderSurfaceLayerList().size());
- ASSERT_EQ(1u, root_layer()->GetRenderSurface()->layer_list().size());
+ ASSERT_EQ(1u, GetRenderSurfaceList().size());
+ ASSERT_EQ(1, GetRenderSurface(root_layer())->num_contributors());
// Hit testing for a point outside the layer should return a null pointer.
gfx::PointF test_point(49.f, 49.f);
@@ -344,8 +344,8 @@ TEST_F(LayerTreeImplTest, HitTestingForSingleRotatedLayer) {
host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
// Sanity check the scenario we just created.
- ASSERT_EQ(1u, RenderSurfaceLayerList().size());
- ASSERT_EQ(1u, root_layer()->GetRenderSurface()->layer_list().size());
+ ASSERT_EQ(1u, GetRenderSurfaceList().size());
+ ASSERT_EQ(1, GetRenderSurface(root_layer())->num_contributors());
// Hit testing for points outside the layer.
// These corners would have been inside the un-transformed layer, but they
@@ -461,37 +461,6 @@ TEST_F(LayerTreeImplTest, HitTestingSiblings) {
EXPECT_EQ(3, result_layer->id());
}
-TEST_F(LayerTreeImplTest, HitTestingPointOutsideMaxTextureSize) {
- gfx::Transform identity_matrix;
- int max_texture_size =
- host_impl().active_tree()->resource_provider()->max_texture_size();
- gfx::Size bounds(max_texture_size + 100, max_texture_size + 100);
-
- LayerImpl* root = root_layer();
- root->SetBounds(bounds);
-
- std::unique_ptr<LayerImpl> surface =
- LayerImpl::Create(host_impl().active_tree(), 2);
- surface->SetBounds(bounds);
- surface->SetMasksToBounds(true);
- surface->SetDrawsContent(true);
- surface->test_properties()->force_render_surface = true;
-
- root->test_properties()->AddChild(std::move(surface));
- host_impl().SetViewportSize(root->bounds());
- host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
-
- gfx::PointF test_point(max_texture_size - 50, max_texture_size - 50);
- LayerImpl* result_layer =
- host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
- EXPECT_TRUE(result_layer);
-
- test_point = gfx::PointF(max_texture_size + 50, max_texture_size + 50);
- result_layer =
- host_impl().active_tree()->FindLayerThatIsHitByPoint(test_point);
- EXPECT_FALSE(result_layer);
-}
-
TEST_F(LayerTreeImplTest, HitTestingForSinglePerspectiveLayer) {
// perspective_projection_about_center * translation_by_z is designed so that
// the 100 x 100 layer becomes 50 x 50, and remains centered at (50, 50).
@@ -512,8 +481,8 @@ TEST_F(LayerTreeImplTest, HitTestingForSinglePerspectiveLayer) {
host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
// Sanity check the scenario we just created.
- ASSERT_EQ(1u, RenderSurfaceLayerList().size());
- ASSERT_EQ(1u, root_layer()->GetRenderSurface()->layer_list().size());
+ ASSERT_EQ(1u, GetRenderSurfaceList().size());
+ ASSERT_EQ(1, GetRenderSurface(root_layer())->num_contributors());
// Hit testing for points outside the layer.
// These corners would have been inside the un-transformed layer, but they
@@ -570,9 +539,10 @@ TEST_F(LayerTreeImplTest, HitTestingForSimpleClippedLayer) {
host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
// Sanity check the scenario we just created.
- ASSERT_EQ(1u, RenderSurfaceLayerList().size());
- ASSERT_EQ(1u, root_layer()->GetRenderSurface()->layer_list().size());
- ASSERT_EQ(456, root_layer()->GetRenderSurface()->layer_list().at(0)->id());
+ ASSERT_EQ(1u, GetRenderSurfaceList().size());
+ ASSERT_EQ(1, GetRenderSurface(root_layer())->num_contributors());
+ LayerImpl* child_layer = host_impl().active_tree()->LayerById(456);
+ EXPECT_TRUE(child_layer->contributes_to_drawn_render_surface());
// Hit testing for a point outside the layer should return a null pointer.
// Despite the child layer being very large, it should be clipped to the root
@@ -747,9 +717,10 @@ TEST_F(LayerTreeImplTest, HitTestingForNonClippingIntermediateLayer) {
host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
// Sanity check the scenario we just created.
- ASSERT_EQ(1u, RenderSurfaceLayerList().size());
- ASSERT_EQ(1u, root_layer()->GetRenderSurface()->layer_list().size());
- ASSERT_EQ(456, root_layer()->GetRenderSurface()->layer_list().at(0)->id());
+ ASSERT_EQ(1u, GetRenderSurfaceList().size());
+ ASSERT_EQ(1, GetRenderSurface(root_layer())->num_contributors());
+ LayerImpl* child_layer = host_impl().active_tree()->LayerById(456);
+ EXPECT_TRUE(child_layer->contributes_to_drawn_render_surface());
// Hit testing for a point outside the layer should return a null pointer.
gfx::PointF test_point(69.f, 69.f);
@@ -827,14 +798,14 @@ TEST_F(LayerTreeImplTest, HitTestingForMultipleLayers) {
ASSERT_TRUE(child1);
ASSERT_TRUE(child2);
ASSERT_TRUE(grand_child1);
- ASSERT_EQ(1u, RenderSurfaceLayerList().size());
+ ASSERT_EQ(1u, GetRenderSurfaceList().size());
- RenderSurfaceImpl* root_render_surface = root->GetRenderSurface();
- ASSERT_EQ(4u, root_render_surface->layer_list().size());
- ASSERT_EQ(1, root_render_surface->layer_list().at(0)->id()); // root layer
- ASSERT_EQ(2, root_render_surface->layer_list().at(1)->id()); // child1
- ASSERT_EQ(4, root_render_surface->layer_list().at(2)->id()); // grand_child1
- ASSERT_EQ(3, root_render_surface->layer_list().at(3)->id()); // child2
+ RenderSurfaceImpl* root_render_surface = GetRenderSurface(root);
+ ASSERT_EQ(4, root_render_surface->num_contributors());
+ EXPECT_TRUE(root_layer()->contributes_to_drawn_render_surface());
+ EXPECT_TRUE(child1->contributes_to_drawn_render_surface());
+ EXPECT_TRUE(child2->contributes_to_drawn_render_surface());
+ EXPECT_TRUE(grand_child1->contributes_to_drawn_render_surface());
// Nothing overlaps the root at (1, 1), so hit testing there should find
// the root layer.
@@ -979,7 +950,7 @@ TEST_F(LayerTreeImplTest, HitTestingForMultipleLayersAtVaryingDepths) {
ASSERT_TRUE(child1);
ASSERT_TRUE(child2);
ASSERT_TRUE(grand_child1);
- ASSERT_EQ(1u, RenderSurfaceLayerList().size());
+ ASSERT_EQ(1u, GetRenderSurfaceList().size());
// Nothing overlaps the root_layer at (1, 1), so hit testing there should find
// the root layer.
@@ -1176,21 +1147,21 @@ TEST_F(LayerTreeImplTest, HitTestingForMultipleLayerLists) {
ASSERT_TRUE(child1);
ASSERT_TRUE(child2);
ASSERT_TRUE(grand_child1);
- ASSERT_TRUE(child1->GetRenderSurface());
- ASSERT_TRUE(child2->GetRenderSurface());
- ASSERT_TRUE(grand_child1->GetRenderSurface());
- ASSERT_EQ(4u, RenderSurfaceLayerList().size());
+ ASSERT_TRUE(GetRenderSurface(child1));
+ ASSERT_TRUE(GetRenderSurface(child2));
+ ASSERT_TRUE(GetRenderSurface(grand_child1));
+ ASSERT_EQ(4u, GetRenderSurfaceList().size());
// The root surface has the root layer, and child1's and child2's render
// surfaces.
- ASSERT_EQ(3u, root->GetRenderSurface()->layer_list().size());
+ ASSERT_EQ(3, GetRenderSurface(root)->num_contributors());
// The child1 surface has the child1 layer and grand_child1's render surface.
- ASSERT_EQ(2u, child1->GetRenderSurface()->layer_list().size());
- ASSERT_EQ(1u, child2->GetRenderSurface()->layer_list().size());
- ASSERT_EQ(1u, grand_child1->GetRenderSurface()->layer_list().size());
- ASSERT_EQ(1, RenderSurfaceLayerList().at(0)->id()); // root layer
- ASSERT_EQ(2, RenderSurfaceLayerList()[1]->id()); // child1
- ASSERT_EQ(4, RenderSurfaceLayerList().at(2)->id()); // grand_child1
- ASSERT_EQ(3, RenderSurfaceLayerList()[3]->id()); // child2
+ ASSERT_EQ(2, GetRenderSurface(child1)->num_contributors());
+ ASSERT_EQ(1, GetRenderSurface(child2)->num_contributors());
+ ASSERT_EQ(1, GetRenderSurface(grand_child1)->num_contributors());
+ EXPECT_TRUE(root_layer()->contributes_to_drawn_render_surface());
+ EXPECT_TRUE(child1->contributes_to_drawn_render_surface());
+ EXPECT_TRUE(grand_child1->contributes_to_drawn_render_surface());
+ EXPECT_TRUE(child2->contributes_to_drawn_render_surface());
// Nothing overlaps the root at (1, 1), so hit testing there should find
// the root layer.
@@ -1251,8 +1222,8 @@ TEST_F(LayerTreeImplTest, HitCheckingTouchHandlerRegionsForSingleLayer) {
host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
// Sanity check the scenario we just created.
- ASSERT_EQ(1u, RenderSurfaceLayerList().size());
- ASSERT_EQ(1u, root->GetRenderSurface()->layer_list().size());
+ ASSERT_EQ(1u, GetRenderSurfaceList().size());
+ ASSERT_EQ(1, GetRenderSurface(root)->num_contributors());
// Hit checking for any point should return a null pointer for a layer without
// any touch event handler regions.
@@ -1328,8 +1299,8 @@ TEST_F(LayerTreeImplTest,
host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
// Sanity check the scenario we just created.
- ASSERT_EQ(1u, RenderSurfaceLayerList().size());
- ASSERT_EQ(1u, root->GetRenderSurface()->layer_list().size());
+ ASSERT_EQ(1u, GetRenderSurfaceList().size());
+ ASSERT_EQ(1, GetRenderSurface(root)->num_contributors());
ASSERT_FALSE(root->ScreenSpaceTransform().IsInvertible());
// Hit checking any point should not hit the touch handler region on the
@@ -1395,8 +1366,8 @@ TEST_F(LayerTreeImplTest,
host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
// Sanity check the scenario we just created.
- ASSERT_EQ(1u, RenderSurfaceLayerList().size());
- ASSERT_EQ(1u, root->GetRenderSurface()->layer_list().size());
+ ASSERT_EQ(1u, GetRenderSurfaceList().size());
+ ASSERT_EQ(1, GetRenderSurface(root)->num_contributors());
// Hit checking for a point outside the layer should return a null pointer.
gfx::PointF test_point(49.f, 49.f);
@@ -1468,8 +1439,10 @@ TEST_F(LayerTreeImplTest,
host_impl().SetViewportSize(scaled_bounds_for_root);
host_impl().active_tree()->SetDeviceScaleFactor(device_scale_factor);
- host_impl().active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 1, 1,
- Layer::INVALID_ID);
+ LayerTreeImpl::ViewportLayerIds viewport_ids;
+ viewport_ids.page_scale = 1;
+ viewport_ids.inner_viewport_scroll = 1;
+ host_impl().active_tree()->SetViewportLayersFromIds(viewport_ids);
host_impl().active_tree()->BuildLayerListAndPropertyTreesForTesting();
host_impl().active_tree()->PushPageScaleFromMainThread(
page_scale_factor, page_scale_factor, max_page_scale_factor);
@@ -1480,8 +1453,8 @@ TEST_F(LayerTreeImplTest,
// The visible content rect for test_layer is actually 100x100, even though
// its layout size is 50x50, positioned at 25x25.
LayerImpl* test_layer = root->test_properties()->children[0];
- ASSERT_EQ(1u, RenderSurfaceLayerList().size());
- ASSERT_EQ(1u, root->GetRenderSurface()->layer_list().size());
+ ASSERT_EQ(1u, GetRenderSurfaceList().size());
+ ASSERT_EQ(1, GetRenderSurface(root)->num_contributors());
// Check whether the child layer fits into the root after scaled.
EXPECT_EQ(gfx::Rect(test_layer->bounds()), test_layer->visible_layer_rect());
@@ -1607,9 +1580,10 @@ TEST_F(LayerTreeImplTest, HitCheckingTouchHandlerRegionsForSimpleClippedLayer) {
host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
// Sanity check the scenario we just created.
- ASSERT_EQ(1u, RenderSurfaceLayerList().size());
- ASSERT_EQ(1u, root->GetRenderSurface()->layer_list().size());
- ASSERT_EQ(456, root->GetRenderSurface()->layer_list().at(0)->id());
+ ASSERT_EQ(1u, GetRenderSurfaceList().size());
+ ASSERT_EQ(1, GetRenderSurface(root)->num_contributors());
+ LayerImpl* child_layer = host_impl().active_tree()->LayerById(456);
+ EXPECT_TRUE(child_layer->contributes_to_drawn_render_surface());
// Hit checking for a point outside the layer should return a null pointer.
// Despite the child layer being very large, it should be clipped to the root
@@ -1694,8 +1668,10 @@ TEST_F(LayerTreeImplTest,
host_impl().SetViewportSize(scaled_bounds_for_root);
host_impl().active_tree()->SetDeviceScaleFactor(device_scale_factor);
- host_impl().active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 1, 1,
- Layer::INVALID_ID);
+ LayerTreeImpl::ViewportLayerIds viewport_ids;
+ viewport_ids.page_scale = 1;
+ viewport_ids.inner_viewport_scroll = 1;
+ host_impl().active_tree()->SetViewportLayersFromIds(viewport_ids);
host_impl().active_tree()->BuildLayerListAndPropertyTreesForTesting();
host_impl().active_tree()->PushPageScaleFromMainThread(
page_scale_factor, page_scale_factor, max_page_scale_factor);
@@ -1703,7 +1679,7 @@ TEST_F(LayerTreeImplTest,
host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
// Sanity check the scenario we just created.
- ASSERT_EQ(2u, RenderSurfaceLayerList().size());
+ ASSERT_EQ(2u, GetRenderSurfaceList().size());
// Hit checking for a point outside the layer should return a null pointer.
// Despite the child layer being very large, it should be clipped to the root
@@ -1760,10 +1736,12 @@ TEST_F(LayerTreeImplTest, HitCheckingTouchHandlerOverlappingRegions) {
host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
// Sanity check the scenario we just created.
- ASSERT_EQ(1u, RenderSurfaceLayerList().size());
- ASSERT_EQ(2u, root->GetRenderSurface()->layer_list().size());
- ASSERT_EQ(123, root->GetRenderSurface()->layer_list().at(0)->id());
- ASSERT_EQ(1234, root->GetRenderSurface()->layer_list().at(1)->id());
+ ASSERT_EQ(1u, GetRenderSurfaceList().size());
+ ASSERT_EQ(2, GetRenderSurface(root)->num_contributors());
+ LayerImpl* touch_layer = host_impl().active_tree()->LayerById(123);
+ LayerImpl* notouch_layer = host_impl().active_tree()->LayerById(1234);
+ EXPECT_TRUE(touch_layer->contributes_to_drawn_render_surface());
+ EXPECT_TRUE(notouch_layer->contributes_to_drawn_render_surface());
gfx::PointF test_point(35.f, 35.f);
LayerImpl* result_layer =
@@ -1816,10 +1794,10 @@ TEST_F(LayerTreeImplTest, HitTestingTouchHandlerRegionsForLayerThatIsNotDrawn) {
host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
LayerImpl* test_layer = root->test_properties()->children[0];
- // As test_layer doesn't draw content, the layer list of root's render surface
- // should contain only the root layer.
- ASSERT_EQ(1u, RenderSurfaceLayerList().size());
- ASSERT_EQ(1u, root->GetRenderSurface()->layer_list().size());
+ // As test_layer doesn't draw content, it shouldn't contribute content to the
+ // root surface.
+ ASSERT_EQ(1u, GetRenderSurfaceList().size());
+ EXPECT_FALSE(test_layer->contributes_to_drawn_render_surface());
// Hit testing for a point outside the test layer should return null pointer.
// We also implicitly check that the updated screen space transform of a layer
@@ -1837,7 +1815,7 @@ TEST_F(LayerTreeImplTest, HitTestingTouchHandlerRegionsForLayerThatIsNotDrawn) {
host_impl().active_tree()->FindLayerThatIsHitByPointInTouchHandlerRegion(
test_point);
EXPECT_FALSE(result_layer);
- EXPECT_FALSE(test_layer->is_drawn_render_surface_layer_list_member());
+ EXPECT_FALSE(test_layer->contributes_to_drawn_render_surface());
EXPECT_TRANSFORMATION_MATRIX_EQ(
expected_screen_space_transform,
draw_property_utils::ScreenSpaceTransform(
@@ -1859,7 +1837,7 @@ TEST_F(LayerTreeImplTest, HitTestingTouchHandlerRegionsForLayerThatIsNotDrawn) {
test_point);
ASSERT_TRUE(result_layer);
ASSERT_EQ(test_layer, result_layer);
- EXPECT_FALSE(result_layer->is_drawn_render_surface_layer_list_member());
+ EXPECT_FALSE(result_layer->contributes_to_drawn_render_surface());
EXPECT_TRANSFORMATION_MATRIX_EQ(
expected_screen_space_transform,
draw_property_utils::ScreenSpaceTransform(
@@ -1876,8 +1854,8 @@ TEST_F(LayerTreeImplTest, SelectionBoundsForSingleLayer) {
host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
// Sanity check the scenario we just created.
- ASSERT_EQ(1u, RenderSurfaceLayerList().size());
- ASSERT_EQ(1u, root->GetRenderSurface()->layer_list().size());
+ ASSERT_EQ(1u, GetRenderSurfaceList().size());
+ ASSERT_EQ(1, GetRenderSurface(root)->num_contributors());
LayerSelection input;
@@ -1957,7 +1935,7 @@ TEST_F(LayerTreeImplTest, SelectionBoundsForPartialOccludedLayers) {
host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
// Sanity check the scenario we just created.
- ASSERT_EQ(1u, RenderSurfaceLayerList().size());
+ ASSERT_EQ(1u, GetRenderSurfaceList().size());
LayerSelection input;
input.start.type = gfx::SelectionBound::LEFT;
@@ -2084,18 +2062,19 @@ TEST_F(LayerTreeImplTest, SelectionBoundsForScaledLayers) {
root->bounds(), device_scale_factor * page_scale_factor);
host_impl().SetViewportSize(scaled_bounds_for_root);
- host_impl().active_tree()->SetViewportLayersFromIds(0, root->id(), 0, 0);
+ LayerTreeImpl::ViewportLayerIds viewport_ids;
+ viewport_ids.page_scale = root->id();
+ host_impl().active_tree()->SetViewportLayersFromIds(viewport_ids);
host_impl().active_tree()->SetDeviceScaleFactor(device_scale_factor);
host_impl().active_tree()->SetPageScaleOnActiveTree(page_scale_factor);
- host_impl().active_tree()->SetViewportLayersFromIds(Layer::INVALID_ID, 1, 1,
- Layer::INVALID_ID);
+
host_impl().active_tree()->PushPageScaleFromMainThread(
page_scale_factor, page_scale_factor, page_scale_factor);
host_impl().active_tree()->SetPageScaleOnActiveTree(page_scale_factor);
host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
// Sanity check the scenario we just created.
- ASSERT_EQ(1u, RenderSurfaceLayerList().size());
+ ASSERT_EQ(1u, GetRenderSurfaceList().size());
LayerSelection input;
input.start.type = gfx::SelectionBound::LEFT;
@@ -2263,7 +2242,7 @@ TEST_F(LayerTreeImplTest, HitTestingCorrectLayerWheelListener) {
host_impl().SetViewportSize(root->bounds());
host_impl().UpdateNumChildrenAndDrawPropertiesForActiveTree();
- CHECK_EQ(1u, RenderSurfaceLayerList().size());
+ CHECK_EQ(1u, GetRenderSurfaceList().size());
gfx::PointF test_point = gfx::PointF(1.f, 1.f);
LayerImpl* result_layer =
diff --git a/chromium/cc/trees/layer_tree_settings.h b/chromium/cc/trees/layer_tree_settings.h
index 90348788b5e..5191cdc20e3 100644
--- a/chromium/cc/trees/layer_tree_settings.h
+++ b/chromium/cc/trees/layer_tree_settings.h
@@ -50,7 +50,6 @@ class CC_EXPORT LayerTreeSettings {
};
ScrollbarAnimator scrollbar_animator = NO_ANIMATOR;
base::TimeDelta scrollbar_fade_delay;
- base::TimeDelta scrollbar_fade_out_resize_delay;
base::TimeDelta scrollbar_fade_duration;
base::TimeDelta scrollbar_thinning_duration;
SkColor solid_color_scrollbar_color = SK_ColorWHITE;
@@ -79,11 +78,6 @@ class CC_EXPORT LayerTreeSettings {
bool ignore_root_layer_flings = false;
size_t scheduled_raster_task_limit = 32;
bool use_occlusion_for_tile_prioritization = false;
-
- // TODO(khushalsagar): Enable for all client and remove this flag if possible.
- // See crbug/com/696864.
- bool image_decode_tasks_enabled = false;
-
bool use_layer_lists = false;
int max_staging_buffer_usage_in_bytes = 32 * 1024 * 1024;
ManagedMemoryPolicy gpu_memory_policy;
@@ -112,6 +106,11 @@ class CC_EXPORT LayerTreeSettings {
// Indicates the case when a sub-frame gets its own LayerTree because it's
// rendered in a different process from its ancestor frames.
bool is_layer_tree_for_subframe = false;
+
+ // Determines whether we disallow non-exact matches when finding resources
+ // in ResourcePool. Only used for layout or pixel tests, as non-deterministic
+ // resource sizes can lead to floating point error and noise in these tests.
+ bool disallow_non_exact_resource_reuse = false;
};
} // namespace cc
diff --git a/chromium/cc/trees/mutator_host.h b/chromium/cc/trees/mutator_host.h
index d454539c874..0c9825107da 100644
--- a/chromium/cc/trees/mutator_host.h
+++ b/chromium/cc/trees/mutator_host.h
@@ -116,7 +116,8 @@ class MutatorHost {
ElementId element_id,
const gfx::ScrollOffset& target_offset,
const gfx::ScrollOffset& current_offset,
- base::TimeDelta delayed_by) = 0;
+ base::TimeDelta delayed_by,
+ base::TimeDelta animation_start_offset) = 0;
virtual bool ImplOnlyScrollAnimationUpdateTarget(
ElementId element_id,
const gfx::Vector2dF& scroll_delta,
diff --git a/chromium/cc/trees/occlusion_tracker.cc b/chromium/cc/trees/occlusion_tracker.cc
index 523b01f830f..8aa513bfe17 100644
--- a/chromium/cc/trees/occlusion_tracker.cc
+++ b/chromium/cc/trees/occlusion_tracker.cc
@@ -221,16 +221,17 @@ static void ReduceOcclusionBelowSurface(
if (affected_area_in_target.IsEmpty())
return;
+ // The filter's bounds for asymmetric filters (ex: drop shadow) are
+ // relative to the target surface, which moves the pixels from outside of the
+ // clip to the filtered surface. As a result, |affected_area| needs to expand.
+ // Since we are concerned with the target surface, we need to swap the outsets
+ // before applying them to the filtered surface bounds.
int outset_top, outset_right, outset_bottom, outset_left;
contributing_surface->BackgroundFilters().GetOutsets(
- &outset_top, &outset_right, &outset_bottom, &outset_left);
-
- // The filter can move pixels from outside of the clip, so allow affected_area
- // to expand outside the clip. Notably the content we're concerned with here
- // is not the affected area, but rather stuff slightly outside it. Thus the
- // directions of the outsets are reversed from normal.
- affected_area_in_target.Inset(-outset_right, -outset_bottom, -outset_left,
- -outset_top);
+ &outset_bottom, &outset_left, &outset_top, &outset_right);
+
+ affected_area_in_target.Inset(-outset_left, -outset_top, -outset_right,
+ -outset_bottom);
SimpleEnclosedRegion affected_occlusion = *occlusion_from_inside_target;
affected_occlusion.Intersect(affected_area_in_target);
diff --git a/chromium/cc/trees/occlusion_tracker_unittest.cc b/chromium/cc/trees/occlusion_tracker_unittest.cc
index 8f635a30ccd..a0218f64497 100644
--- a/chromium/cc/trees/occlusion_tracker_unittest.cc
+++ b/chromium/cc/trees/occlusion_tracker_unittest.cc
@@ -19,6 +19,7 @@
#include "cc/test/fake_layer_tree_host.h"
#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/geometry_test_utils.h"
+#include "cc/test/layer_test_common.h"
#include "cc/test/test_occlusion_tracker.h"
#include "cc/test/test_task_graph_runner.h"
#include "cc/trees/layer_tree_host_common.h"
@@ -77,7 +78,8 @@ class TestOcclusionTrackerWithClip : public TestOcclusionTracker {
gfx::Rect UnoccludedSurfaceContentRect(const LayerImpl* layer,
const gfx::Rect& content_rect) const {
- RenderSurfaceImpl* surface = layer->GetRenderSurface();
+ const RenderSurfaceImpl* surface =
+ GetRenderSurface(const_cast<LayerImpl*>(layer));
return this->GetCurrentOcclusionForContributingSurface(
surface->draw_transform())
.GetUnoccludedContentRect(content_rect);
@@ -188,7 +190,7 @@ class OcclusionTrackerTest : public testing::Test {
void DestroyLayers() {
host_->host_impl()->active_tree()->SetRootLayerForTesting(nullptr);
- render_surface_layer_list_impl_.clear();
+ render_surface_list_impl_.clear();
mask_layers_.clear();
layer_iterator_.reset();
}
@@ -217,7 +219,7 @@ class OcclusionTrackerTest : public testing::Test {
root->layer_tree_impl()->property_trees()->needs_rebuild = true;
LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
- root, root->bounds(), &render_surface_layer_list_impl_);
+ root, root->bounds(), &render_surface_list_impl_);
inputs.can_adjust_raster_scales = true;
LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
@@ -247,7 +249,7 @@ class OcclusionTrackerTest : public testing::Test {
void EnterContributingSurface(LayerImpl* layer, OcclusionTracker* occlusion) {
ASSERT_EQ(layer_iterator_->target_render_surface(),
- layer->GetRenderSurface());
+ GetRenderSurface(layer));
ASSERT_TRUE(layer_iterator_->state() ==
EffectTreeLayerListIterator::State::TARGET_SURFACE);
occlusion->EnterLayer(*layer_iterator_);
@@ -260,7 +262,7 @@ class OcclusionTrackerTest : public testing::Test {
void LeaveContributingSurface(LayerImpl* layer, OcclusionTracker* occlusion) {
ASSERT_EQ(layer_iterator_->current_render_surface(),
- layer->GetRenderSurface());
+ GetRenderSurface(layer));
ASSERT_TRUE(layer_iterator_->state() ==
EffectTreeLayerListIterator::State::CONTRIBUTING_SURFACE);
occlusion->LeaveLayer(*layer_iterator_);
@@ -305,7 +307,7 @@ class OcclusionTrackerTest : public testing::Test {
std::unique_ptr<AnimationHost> animation_host_;
std::unique_ptr<FakeLayerTreeHost> host_;
// These hold ownership of the layers for the duration of the test.
- LayerImplList render_surface_layer_list_impl_;
+ RenderSurfaceList render_surface_list_impl_;
std::unique_ptr<EffectTreeLayerListIterator> layer_iterator_;
LayerList mask_layers_;
int next_layer_impl_id_;
diff --git a/chromium/cc/trees/property_tree.cc b/chromium/cc/trees/property_tree.cc
index 4d1ca75e387..f450baa7067 100644
--- a/chromium/cc/trees/property_tree.cc
+++ b/chromium/cc/trees/property_tree.cc
@@ -352,24 +352,25 @@ gfx::Vector2dF StickyPositionOffset(TransformTree* tree, TransformNode* node) {
return gfx::Vector2dF();
StickyPositionNodeData* sticky_data = tree->StickyPositionData(node->id);
const LayerStickyPositionConstraint& constraint = sticky_data->constraints;
+ auto& property_trees = *tree->property_trees();
ScrollNode* scroll_node =
- tree->property_trees()->scroll_tree.Node(sticky_data->scroll_ancestor);
- gfx::ScrollOffset scroll_offset =
- tree->property_trees()->scroll_tree.current_scroll_offset(
- scroll_node->owning_layer_id);
+ property_trees.scroll_tree.Node(sticky_data->scroll_ancestor);
+ TransformNode* transform_node =
+ property_trees.transform_tree.Node(scroll_node->transform_id);
+ const auto& scroll_offset = transform_node->scroll_offset;
+ DCHECK(property_trees.scroll_tree.current_scroll_offset(
+ scroll_node->owning_layer_id) == scroll_offset);
gfx::PointF scroll_position(scroll_offset.x(), scroll_offset.y());
- TransformNode* scroll_ancestor_transform_node =
- tree->Node(scroll_node->transform_id);
- if (scroll_ancestor_transform_node->scrolls) {
+ if (transform_node->scrolls) {
// The scroll position does not include snapping which shifts the scroll
// offset to align to a pixel boundary, we need to manually include it here.
// In this case, snapping is caused by a scroll.
- scroll_position -= scroll_ancestor_transform_node->snap_amount;
+ scroll_position -= transform_node->snap_amount;
}
gfx::RectF clip(
scroll_position,
- gfx::SizeF(tree->property_trees()->scroll_tree.scroll_clip_layer_bounds(
+ gfx::SizeF(property_trees.scroll_tree.scroll_clip_layer_bounds(
scroll_node->id)));
gfx::Vector2dF layer_offset(sticky_data->main_thread_offset);
@@ -824,7 +825,8 @@ void EffectTree::UpdateBackfaceVisibility(EffectNode* node,
if (parent_node && parent_node->hidden_by_backface_visibility) {
node->hidden_by_backface_visibility = true;
return;
- } else if (node->double_sided) {
+ }
+ if (node->double_sided) {
node->hidden_by_backface_visibility = false;
return;
}
@@ -870,11 +872,6 @@ EffectNode* EffectTree::FindNodeFromElementId(ElementId id) {
bool EffectTree::OnOpacityAnimated(ElementId id, float opacity) {
EffectNode* node = FindNodeFromElementId(id);
DCHECK(node);
- // TODO(crbug.com/706766): Avoid crash. Need more investigation for what is
- // calling this without setting element id.
- if (!node)
- return false;
-
if (node->opacity == opacity)
return false;
node->opacity = opacity;
@@ -888,11 +885,6 @@ bool EffectTree::OnFilterAnimated(ElementId id,
const FilterOperations& filters) {
EffectNode* node = FindNodeFromElementId(id);
DCHECK(node);
- // TODO(crbug.com/706766): Avoid crash. Need more investigation for what is
- // calling this without setting element id.
- if (!node)
- return false;
-
if (node->filters == filters)
return false;
node->filters = filters;
@@ -986,8 +978,9 @@ bool EffectTree::HasCopyRequests() const {
void EffectTree::ClearCopyRequests() {
for (auto& node : nodes()) {
- node.num_copy_requests_in_subtree = 0;
+ node.subtree_has_copy_request = false;
node.has_copy_request = false;
+ node.closest_ancestor_with_copy_request_id = EffectTree::kInvalidNodeId;
}
// Any copy requests that are still left will be aborted (sending an empty
@@ -996,33 +989,29 @@ void EffectTree::ClearCopyRequests() {
set_needs_update(true);
}
-int EffectTree::ClosestAncestorWithCopyRequest(int id) const {
- DCHECK_GE(id, EffectTree::kRootNodeId);
- const EffectNode* node = Node(id);
- while (node->id > EffectTree::kContentsRootNodeId) {
- if (node->has_copy_request)
- return node->id;
-
- node = parent(node);
+int EffectTree::LowestCommonAncestorWithRenderSurface(int id_1,
+ int id_2) const {
+ DCHECK(GetRenderSurface(id_1));
+ DCHECK(GetRenderSurface(id_2));
+ while (id_1 != id_2) {
+ if (id_1 < id_2)
+ id_2 = Node(id_2)->target_id;
+ else
+ id_1 = Node(id_1)->target_id;
}
- if (node->has_copy_request)
- return node->id;
- else
- return EffectTree::kInvalidNodeId;
+ return id_1;
}
void EffectTree::AddMaskLayerId(int id) {
mask_layer_ids_.push_back(id);
}
-void EffectTree::UpdateRenderSurfaces(LayerTreeImpl* layer_tree_impl,
- bool non_root_surfaces_enabled) {
+void EffectTree::UpdateRenderSurfaces(LayerTreeImpl* layer_tree_impl) {
for (int id = kContentsRootNodeId; id < static_cast<int>(size()); ++id) {
EffectNode* effect_node = Node(id);
bool needs_render_surface =
- id == kContentsRootNodeId ||
- (non_root_surfaces_enabled && effect_node->has_render_surface);
+ id == kContentsRootNodeId || effect_node->has_render_surface;
if (needs_render_surface == !!render_surfaces_[id])
continue;
@@ -1211,6 +1200,14 @@ void ScrollTree::CopyCompleteTreeState(const ScrollTree& other) {
}
#endif
+ScrollNode* ScrollTree::FindNodeFromElementId(ElementId id) {
+ auto iterator = property_trees()->element_id_to_scroll_node_index.find(id);
+ if (iterator == property_trees()->element_id_to_scroll_node_index.end())
+ return nullptr;
+
+ return Node(iterator->second);
+}
+
void ScrollTree::clear() {
PropertyTree<ScrollNode>::clear();
@@ -1349,11 +1346,9 @@ SyncedScrollOffset* ScrollTree::GetOrCreateSyncedScrollOffset(int layer_id) {
const SyncedScrollOffset* ScrollTree::GetSyncedScrollOffset(
int layer_id) const {
DCHECK(!property_trees()->is_main_thread);
- if (layer_id_to_synced_scroll_offset_map_.find(layer_id) ==
- layer_id_to_synced_scroll_offset_map_.end()) {
- return nullptr;
- }
- return layer_id_to_synced_scroll_offset_map_.at(layer_id).get();
+ auto it = layer_id_to_synced_scroll_offset_map_.find(layer_id);
+ return it != layer_id_to_synced_scroll_offset_map_.end() ? it->second.get()
+ : nullptr;
}
const gfx::ScrollOffset ScrollTree::current_scroll_offset(int layer_id) const {
@@ -1606,7 +1601,6 @@ PropertyTreesCachedData::~PropertyTreesCachedData() {}
PropertyTrees::PropertyTrees()
: needs_rebuild(true),
- non_root_surfaces_enabled(true),
can_adjust_raster_scales(true),
changed(false),
full_tree_damaged(false),
@@ -1631,13 +1625,10 @@ bool PropertyTrees::operator==(const PropertyTrees& other) const {
other.element_id_to_scroll_node_index &&
element_id_to_transform_node_index ==
other.element_id_to_transform_node_index &&
- always_use_active_tree_opacity_effect_ids ==
- other.always_use_active_tree_opacity_effect_ids &&
needs_rebuild == other.needs_rebuild && changed == other.changed &&
full_tree_damaged == other.full_tree_damaged &&
is_main_thread == other.is_main_thread &&
is_active == other.is_active &&
- non_root_surfaces_enabled == other.non_root_surfaces_enabled &&
can_adjust_raster_scales == other.can_adjust_raster_scales &&
sequence_number == other.sequence_number;
}
@@ -1647,15 +1638,12 @@ PropertyTrees& PropertyTrees::operator=(const PropertyTrees& from) {
effect_tree = from.effect_tree;
clip_tree = from.clip_tree;
scroll_tree = from.scroll_tree;
- always_use_active_tree_opacity_effect_ids =
- from.always_use_active_tree_opacity_effect_ids;
element_id_to_effect_node_index = from.element_id_to_effect_node_index;
element_id_to_scroll_node_index = from.element_id_to_scroll_node_index;
element_id_to_transform_node_index = from.element_id_to_transform_node_index;
needs_rebuild = from.needs_rebuild;
changed = from.changed;
full_tree_damaged = from.full_tree_damaged;
- non_root_surfaces_enabled = from.non_root_surfaces_enabled;
can_adjust_raster_scales = from.can_adjust_raster_scales;
sequence_number = from.sequence_number;
is_main_thread = from.is_main_thread;
@@ -1682,12 +1670,10 @@ void PropertyTrees::clear() {
element_id_to_effect_node_index.clear();
element_id_to_scroll_node_index.clear();
element_id_to_transform_node_index.clear();
- always_use_active_tree_opacity_effect_ids.clear();
needs_rebuild = true;
full_tree_damaged = false;
changed = false;
- non_root_surfaces_enabled = true;
can_adjust_raster_scales = true;
sequence_number++;
@@ -1729,22 +1715,6 @@ void PropertyTrees::SetInnerViewportScrollBoundsDelta(
inner_viewport_scroll_bounds_delta_ = bounds_delta;
}
-void PropertyTrees::PushOpacityIfNeeded(PropertyTrees* target_tree) {
- for (int id : target_tree->always_use_active_tree_opacity_effect_ids) {
- if (const EffectNode* source_effect_node =
- effect_tree.FindNodeFromOwningLayerId(id)) {
- EffectNode* target_effect_node =
- target_tree->effect_tree.UpdateNodeFromOwningLayerId(id);
- float source_opacity = source_effect_node->opacity;
- float target_opacity = target_effect_node->opacity;
- if (source_opacity == target_opacity)
- continue;
- target_effect_node->opacity = source_opacity;
- target_tree->effect_tree.set_needs_update(true);
- }
- }
-}
-
void PropertyTrees::RemoveIdFromIdToIndexMaps(int id) {
transform_tree.SetOwningLayerIdForNode(nullptr, id);
clip_tree.SetOwningLayerIdForNode(nullptr, id);
diff --git a/chromium/cc/trees/property_tree.h b/chromium/cc/trees/property_tree.h
index de5cc2823de..3ea602ad1c0 100644
--- a/chromium/cc/trees/property_tree.h
+++ b/chromium/cc/trees/property_tree.h
@@ -378,7 +378,10 @@ class CC_EXPORT EffectTree final : public PropertyTree<EffectNode> {
bool HasCopyRequests() const;
void ClearCopyRequests();
- int ClosestAncestorWithCopyRequest(int id) const;
+ // Given the ids of two effect nodes that have render surfaces, returns the
+ // id of the lowest common ancestor effect node that also has a render
+ // surface.
+ int LowestCommonAncestorWithRenderSurface(int id_1, int id_2) const;
void AddMaskLayerId(int id);
const std::vector<int>& mask_layer_ids() const { return mask_layer_ids_; }
@@ -391,8 +394,7 @@ class CC_EXPORT EffectTree final : public PropertyTree<EffectNode> {
return render_surfaces_[id].get();
}
- void UpdateRenderSurfaces(LayerTreeImpl* layer_tree_impl,
- bool non_root_surfaces_enabled);
+ void UpdateRenderSurfaces(LayerTreeImpl* layer_tree_impl);
bool ContributesToDrawnSurface(int id);
@@ -499,10 +501,12 @@ class CC_EXPORT ScrollTree final : public PropertyTree<ScrollNode> {
void CopyCompleteTreeState(const ScrollTree& other);
#endif
+ ScrollNode* FindNodeFromElementId(ElementId id);
+
private:
- using ScrollOffsetMap = std::unordered_map<int, gfx::ScrollOffset>;
+ using ScrollOffsetMap = base::flat_map<int, gfx::ScrollOffset>;
using SyncedScrollOffsetMap =
- std::unordered_map<int, scoped_refptr<SyncedScrollOffset>>;
+ base::flat_map<int, scoped_refptr<SyncedScrollOffset>>;
int currently_scrolling_node_id_;
@@ -639,20 +643,15 @@ class CC_EXPORT PropertyTrees final {
// from layer id to the respective property node. Completing that work is
// pending the launch of Slimming Paint v2 and reworking UI compositor logic
// to produce cc property trees and these maps.
- std::unordered_map<ElementId, int, ElementIdHash>
- element_id_to_effect_node_index;
- std::unordered_map<ElementId, int, ElementIdHash>
- element_id_to_scroll_node_index;
- std::unordered_map<ElementId, int, ElementIdHash>
- element_id_to_transform_node_index;
-
- std::vector<int> always_use_active_tree_opacity_effect_ids;
+ base::flat_map<ElementId, int> element_id_to_effect_node_index;
+ base::flat_map<ElementId, int> element_id_to_scroll_node_index;
+ base::flat_map<ElementId, int> element_id_to_transform_node_index;
+
TransformTree transform_tree;
EffectTree effect_tree;
ClipTree clip_tree;
ScrollTree scroll_tree;
bool needs_rebuild;
- bool non_root_surfaces_enabled;
bool can_adjust_raster_scales;
// Change tracking done on property trees needs to be preserved across commits
// (when they are not rebuild). We cache a global bool which stores whether
@@ -674,7 +673,6 @@ class CC_EXPORT PropertyTrees final {
void SetInnerViewportContainerBoundsDelta(gfx::Vector2dF bounds_delta);
void SetOuterViewportContainerBoundsDelta(gfx::Vector2dF bounds_delta);
void SetInnerViewportScrollBoundsDelta(gfx::Vector2dF bounds_delta);
- void PushOpacityIfNeeded(PropertyTrees* target_tree);
void RemoveIdFromIdToIndexMaps(int id);
void UpdateChangeTracking();
void PushChangeTrackingTo(PropertyTrees* tree);
diff --git a/chromium/cc/trees/property_tree_builder.cc b/chromium/cc/trees/property_tree_builder.cc
index 02fb9bd306c..a7efa0a7155 100644
--- a/chromium/cc/trees/property_tree_builder.cc
+++ b/chromium/cc/trees/property_tree_builder.cc
@@ -35,10 +35,10 @@ struct DataForRecursion {
PropertyTrees* property_trees;
LayerType* transform_tree_parent;
LayerType* transform_fixed_parent;
- int render_target;
int clip_tree_parent;
int effect_tree_parent;
int scroll_tree_parent;
+ int closest_ancestor_with_copy_request;
const LayerType* page_scale_layer;
const LayerType* inner_viewport_scroll_layer;
const LayerType* outer_viewport_scroll_layer;
@@ -54,21 +54,11 @@ struct DataForRecursion {
bool scroll_tree_parent_created_by_uninheritable_criteria;
const gfx::Transform* device_transform;
gfx::Transform compound_transform_since_render_target;
- bool axis_align_since_render_target;
+ bool animation_axis_aligned_since_render_target;
+ bool not_axis_aligned_since_last_clip;
SkColor safe_opaque_background_color;
};
-template <typename LayerType>
-struct DataForRecursionFromChild {
- int num_copy_requests_in_subtree;
-
- DataForRecursionFromChild() : num_copy_requests_in_subtree(0) {}
-
- void Merge(const DataForRecursionFromChild& data) {
- num_copy_requests_in_subtree += data.num_copy_requests_in_subtree;
- }
-};
-
static LayerPositionConstraint PositionConstraint(Layer* layer) {
return layer->position_constraint();
}
@@ -366,14 +356,6 @@ bool AddTransformNodeIfNeeded(
const bool has_surface = created_render_surface;
- // A transform node is needed to change the render target for subtree when
- // a scroll child's render target is different from the scroll parent's render
- // target.
- const bool scroll_child_has_different_target =
- ScrollParent(layer) &&
- Parent(layer)->effect_tree_index() !=
- ScrollParent(layer)->effect_tree_index();
-
const bool is_at_boundary_of_3d_rendering_context =
IsAtBoundaryOf3dRenderingContext(layer);
@@ -381,8 +363,7 @@ bool AddTransformNodeIfNeeded(
bool requires_node = is_root || is_snapped || has_significant_transform ||
has_any_transform_animation || has_surface || is_fixed ||
is_page_scale_layer || is_overscroll_elasticity_layer ||
- has_proxied_transform_related_property ||
- scroll_child_has_different_target || is_sticky ||
+ has_proxied_transform_related_property || is_sticky ||
is_at_boundary_of_3d_rendering_context;
int parent_index = TransformTree::kRootNodeId;
@@ -718,14 +699,6 @@ static inline bool HideLayerAndSubtree(LayerImpl* layer) {
return layer->test_properties()->hide_layer_and_subtree;
}
-static inline bool AlwaysUseActiveTreeOpacity(Layer* layer) {
- return layer->AlwaysUseActiveTreeOpacity();
-}
-
-static inline bool AlwaysUseActiveTreeOpacity(LayerImpl* layer) {
- return false;
-}
-
static inline bool HasCopyRequest(Layer* layer) {
return layer->HasCopyRequest();
}
@@ -745,10 +718,9 @@ static inline bool PropertyChanged(LayerImpl* layer) {
template <typename LayerType>
bool ShouldCreateRenderSurface(LayerType* layer,
gfx::Transform current_transform,
- bool axis_aligned) {
+ bool animation_axis_aligned) {
const bool preserves_2d_axis_alignment =
- (current_transform * Transform(layer)).Preserves2dAxisAlignment() &&
- axis_aligned && AnimationsPreserveAxisAlignment(layer);
+ current_transform.Preserves2dAxisAlignment() && animation_axis_aligned;
const bool is_root = !Parent(layer);
if (is_root)
return true;
@@ -858,6 +830,38 @@ static void TakeCopyRequests(
layer->test_properties()->copy_requests.clear();
}
+static void SetSubtreeHasCopyRequest(Layer* layer,
+ bool subtree_has_copy_request) {
+ layer->SetSubtreeHasCopyRequest(subtree_has_copy_request);
+}
+
+static void SetSubtreeHasCopyRequest(LayerImpl* layer,
+ bool subtree_has_copy_request) {
+ layer->test_properties()->subtree_has_copy_request = subtree_has_copy_request;
+}
+
+static bool SubtreeHasCopyRequest(Layer* layer) {
+ return layer->SubtreeHasCopyRequest();
+}
+
+static bool SubtreeHasCopyRequest(LayerImpl* layer) {
+ return layer->test_properties()->subtree_has_copy_request;
+}
+
+template <typename LayerType>
+bool UpdateSubtreeHasCopyRequestRecursive(LayerType* layer) {
+ bool subtree_has_copy_request = false;
+ if (HasCopyRequest(layer))
+ subtree_has_copy_request = true;
+ for (size_t i = 0; i < Children(layer).size(); ++i) {
+ LayerType* current_child = ChildAt(layer, i);
+ subtree_has_copy_request |=
+ UpdateSubtreeHasCopyRequestRecursive(current_child);
+ }
+ SetSubtreeHasCopyRequest(layer, subtree_has_copy_request);
+ return subtree_has_copy_request;
+}
+
template <typename LayerType>
bool AddEffectNodeIfNeeded(
const DataForRecursion<LayerType>& data_from_ancestor,
@@ -871,14 +875,27 @@ bool AddEffectNodeIfNeeded(
HasPotentiallyRunningFilterAnimation(layer);
const bool has_proxied_opacity =
!!(layer->mutable_properties() & MutableProperty::kOpacity);
- const bool should_create_render_surface = ShouldCreateRenderSurface(
- layer, data_from_ancestor.compound_transform_since_render_target,
- data_from_ancestor.axis_align_since_render_target);
- data_for_children->axis_align_since_render_target &=
+
+ data_for_children->animation_axis_aligned_since_render_target &=
AnimationsPreserveAxisAlignment(layer);
+ data_for_children->compound_transform_since_render_target *= Transform(layer);
+ const bool should_create_render_surface = ShouldCreateRenderSurface(
+ layer, data_for_children->compound_transform_since_render_target,
+ data_for_children->animation_axis_aligned_since_render_target);
+
+ bool not_axis_aligned_since_last_clip =
+ data_from_ancestor.not_axis_aligned_since_last_clip
+ ? true
+ : !AnimationsPreserveAxisAlignment(layer) ||
+ !Transform(layer).Preserves2dAxisAlignment();
+ // A non-axis aligned clip may need a render surface. So, we create an effect
+ // node.
+ bool has_non_axis_aligned_clip =
+ not_axis_aligned_since_last_clip && LayerClipsSubtree(layer);
bool requires_node = is_root || has_transparency ||
has_potential_opacity_animation || has_proxied_opacity ||
+ has_non_axis_aligned_clip ||
should_create_render_surface;
int parent_id = data_from_ancestor.effect_tree_parent;
@@ -886,38 +903,38 @@ bool AddEffectNodeIfNeeded(
if (!requires_node) {
layer->SetEffectTreeIndex(parent_id);
data_for_children->effect_tree_parent = parent_id;
- data_for_children->compound_transform_since_render_target *=
- Transform(layer);
return false;
}
- EffectNode node;
- node.owning_layer_id = layer->id();
- if (AlwaysUseActiveTreeOpacity(layer)) {
- data_for_children->property_trees->always_use_active_tree_opacity_effect_ids
- .push_back(node.owning_layer_id);
- }
+ EffectTree& effect_tree = data_for_children->property_trees->effect_tree;
+ int node_id = effect_tree.Insert(EffectNode(), parent_id);
+ EffectNode* node = effect_tree.back();
- node.opacity = Opacity(layer);
- node.blend_mode = BlendMode(layer);
- node.unscaled_mask_target_size = layer->bounds();
- node.has_render_surface = should_create_render_surface;
- node.has_copy_request = HasCopyRequest(layer);
- node.filters = Filters(layer);
- node.background_filters = BackgroundFilters(layer);
- node.filters_origin = FiltersOrigin(layer);
- node.has_potential_opacity_animation = has_potential_opacity_animation;
- node.has_potential_filter_animation = has_potential_filter_animation;
- node.double_sided = DoubleSided(layer);
- node.subtree_hidden = HideLayerAndSubtree(layer);
- node.is_currently_animating_opacity = OpacityIsAnimating(layer);
- node.is_currently_animating_filter = FilterIsAnimating(layer);
- node.effect_changed = PropertyChanged(layer);
+ node->owning_layer_id = layer->id();
+ node->opacity = Opacity(layer);
+ node->blend_mode = BlendMode(layer);
+ node->unscaled_mask_target_size = layer->bounds();
+ node->has_render_surface = should_create_render_surface;
+ node->has_copy_request = HasCopyRequest(layer);
+ node->filters = Filters(layer);
+ node->background_filters = BackgroundFilters(layer);
+ node->filters_origin = FiltersOrigin(layer);
+ node->has_potential_opacity_animation = has_potential_opacity_animation;
+ node->has_potential_filter_animation = has_potential_filter_animation;
+ node->double_sided = DoubleSided(layer);
+ node->subtree_hidden = HideLayerAndSubtree(layer);
+ node->is_currently_animating_opacity = OpacityIsAnimating(layer);
+ node->is_currently_animating_filter = FilterIsAnimating(layer);
+ node->effect_changed = PropertyChanged(layer);
+ node->subtree_has_copy_request = SubtreeHasCopyRequest(layer);
+ node->closest_ancestor_with_copy_request_id =
+ HasCopyRequest(layer)
+ ? node_id
+ : data_from_ancestor.closest_ancestor_with_copy_request;
- EffectTree& effect_tree = data_for_children->property_trees->effect_tree;
if (MaskLayer(layer)) {
- node.mask_layer_id = MaskLayer(layer)->id();
- effect_tree.AddMaskLayerId(node.mask_layer_id);
+ node->mask_layer_id = MaskLayer(layer)->id();
+ effect_tree.AddMaskLayerId(node->mask_layer_id);
}
if (!is_root) {
@@ -928,19 +945,23 @@ bool AddEffectNodeIfNeeded(
// In this case, we will create a transform node, so it's safe to use the
// next available id from the transform tree as this effect node's
// transform id.
- node.transform_id =
+ node->transform_id =
data_from_ancestor.property_trees->transform_tree.next_available_id();
}
- node.clip_id = data_from_ancestor.clip_tree_parent;
+ node->clip_id = data_from_ancestor.clip_tree_parent;
} else {
- // Root render surface acts the unbounded and untransformed to draw content
- // into. Transform node created from root layer (includes device scale
- // factor) and clip node created from root layer (include viewports) applies
- // to root render surface's content, but not root render surface itself.
- node.transform_id = TransformTree::kRootNodeId;
- node.clip_id = ClipTree::kViewportNodeId;
+ // The root render surface acts as the unbounded and untransformed
+ // surface into which content is drawn. The transform node created
+ // from the root layer (which includes device scale factor) and
+ // the clip node created from the root layer (which includes
+ // viewports) apply to the root render surface's content, but not
+ // to the root render surface itself.
+ node->transform_id = TransformTree::kRootNodeId;
+ node->clip_id = ClipTree::kViewportNodeId;
}
- int node_id = effect_tree.Insert(node, parent_id);
+
+ data_for_children->closest_ancestor_with_copy_request =
+ node->closest_ancestor_with_copy_request_id;
data_for_children->effect_tree_parent = node_id;
layer->SetEffectTreeIndex(node_id);
data_for_children->property_trees->effect_tree.SetOwningLayerIdForNode(
@@ -963,7 +984,7 @@ bool AddEffectNodeIfNeeded(
if (should_create_render_surface) {
data_for_children->compound_transform_since_render_target =
gfx::Transform();
- data_for_children->axis_align_since_render_target = true;
+ data_for_children->animation_axis_aligned_since_render_target = true;
}
return should_create_render_surface;
}
@@ -1082,7 +1103,7 @@ void SetBackfaceVisibilityTransform(LayerType* layer,
(Is3dSorted(layer) && is_at_boundary_of_3d_rendering_context);
layer->SetUseLocalTransformForBackfaceVisibility(use_local_transform);
- // A double-sided layer's backface can been shown when its visibile.
+ // A double-sided layer's backface can been shown when its visible.
if (DoubleSided(layer))
layer->SetShouldCheckBackfaceVisibility(false);
// The backface of a layer that uses local transform for backface visibility
@@ -1120,8 +1141,7 @@ static void SetLayerPropertyChangedForChild(LayerImpl* parent,
template <typename LayerType>
void BuildPropertyTreesInternal(
LayerType* layer,
- const DataForRecursion<LayerType>& data_from_parent,
- DataForRecursionFromChild<LayerType>* data_to_parent) {
+ const DataForRecursion<LayerType>& data_from_parent) {
layer->set_property_tree_sequence_number(
data_from_parent.property_trees->sequence_number);
@@ -1130,8 +1150,6 @@ void BuildPropertyTreesInternal(
bool created_render_surface =
AddEffectNodeIfNeeded(data_from_parent, layer, &data_for_children);
- if (created_render_surface)
- data_for_children.render_target = data_for_children.effect_tree_parent;
bool created_transform_node = AddTransformNodeIfNeeded(
data_from_parent, layer, created_render_surface, &data_for_children);
@@ -1143,14 +1161,21 @@ void BuildPropertyTreesInternal(
SetBackfaceVisibilityTransform(layer, created_transform_node);
SetSafeOpaqueBackgroundColor(data_from_parent, layer, &data_for_children);
+ bool not_axis_aligned_since_last_clip =
+ data_from_parent.not_axis_aligned_since_last_clip
+ ? true
+ : !AnimationsPreserveAxisAlignment(layer) ||
+ !Transform(layer).Preserves2dAxisAlignment();
+ bool has_non_axis_aligned_clip =
+ not_axis_aligned_since_last_clip && LayerClipsSubtree(layer);
+ data_for_children.not_axis_aligned_since_last_clip =
+ !has_non_axis_aligned_clip;
+
for (size_t i = 0; i < Children(layer).size(); ++i) {
LayerType* current_child = ChildAt(layer, i);
SetLayerPropertyChangedForChild(layer, current_child);
if (!ScrollParent(current_child)) {
- DataForRecursionFromChild<LayerType> data_from_child;
- BuildPropertyTreesInternal(current_child, data_for_children,
- &data_from_child);
- data_to_parent->Merge(data_from_child);
+ BuildPropertyTreesInternal(current_child, data_for_children);
} else {
// The child should be included in its scroll parent's list of scroll
// children.
@@ -1161,15 +1186,10 @@ void BuildPropertyTreesInternal(
if (ScrollChildren(layer)) {
for (LayerType* scroll_child : *ScrollChildren(layer)) {
DCHECK_EQ(ScrollParent(scroll_child), layer);
- DataForRecursionFromChild<LayerType> data_from_child;
DCHECK(Parent(scroll_child));
data_for_children.effect_tree_parent =
Parent(scroll_child)->effect_tree_index();
- data_for_children.render_target =
- Parent(scroll_child)->effect_tree_index();
- BuildPropertyTreesInternal(scroll_child, data_for_children,
- &data_from_child);
- data_to_parent->Merge(data_from_child);
+ BuildPropertyTreesInternal(scroll_child, data_for_children);
}
}
@@ -1183,16 +1203,6 @@ void BuildPropertyTreesInternal(
MaskLayer(layer)->SetEffectTreeIndex(layer->effect_tree_index());
MaskLayer(layer)->SetScrollTreeIndex(layer->scroll_tree_index());
}
-
- EffectNode* effect_node = data_for_children.property_trees->effect_tree.Node(
- data_for_children.effect_tree_parent);
-
- if (effect_node->owning_layer_id == layer->id()) {
- if (effect_node->has_copy_request)
- data_to_parent->num_copy_requests_in_subtree++;
- effect_node->num_copy_requests_in_subtree =
- data_to_parent->num_copy_requests_in_subtree;
- }
}
} // namespace
@@ -1246,10 +1256,11 @@ void BuildPropertyTreesTopLevelInternal(
data_for_recursion.property_trees = property_trees;
data_for_recursion.transform_tree_parent = nullptr;
data_for_recursion.transform_fixed_parent = nullptr;
- data_for_recursion.render_target = EffectTree::kRootNodeId;
data_for_recursion.clip_tree_parent = ClipTree::kRootNodeId;
data_for_recursion.effect_tree_parent = EffectTree::kInvalidNodeId;
data_for_recursion.scroll_tree_parent = ScrollTree::kRootNodeId;
+ data_for_recursion.closest_ancestor_with_copy_request =
+ EffectTree::kInvalidNodeId;
data_for_recursion.page_scale_layer = page_scale_layer;
data_for_recursion.inner_viewport_scroll_layer = inner_viewport_scroll_layer;
data_for_recursion.outer_viewport_scroll_layer = outer_viewport_scroll_layer;
@@ -1269,7 +1280,8 @@ void BuildPropertyTreesTopLevelInternal(
data_for_recursion.property_trees->clear();
data_for_recursion.compound_transform_since_render_target = gfx::Transform();
- data_for_recursion.axis_align_since_render_target = true;
+ data_for_recursion.animation_axis_aligned_since_render_target = true;
+ data_for_recursion.not_axis_aligned_since_last_clip = false;
data_for_recursion.property_trees->transform_tree.set_device_scale_factor(
device_scale_factor);
data_for_recursion.safe_opaque_background_color = color;
@@ -1282,8 +1294,7 @@ void BuildPropertyTreesTopLevelInternal(
data_for_recursion.property_trees->clip_tree.Insert(
root_clip, ClipTree::kRootNodeId);
- DataForRecursionFromChild<LayerType> data_from_child;
- BuildPropertyTreesInternal(root_layer, data_for_recursion, &data_from_child);
+ BuildPropertyTreesInternal(root_layer, data_for_recursion);
property_trees->needs_rebuild = false;
// The transform tree is kept up to date as it is built, but the
@@ -1333,6 +1344,8 @@ void PropertyTreeBuilder::BuildPropertyTrees(
SkColor color = root_layer->layer_tree_host()->background_color();
if (SkColorGetA(color) != 255)
color = SkColorSetA(color, 255);
+ if (root_layer->layer_tree_host()->has_copy_request())
+ UpdateSubtreeHasCopyRequestRecursive(root_layer);
BuildPropertyTreesTopLevelInternal(
root_layer, page_scale_layer, inner_viewport_scroll_layer,
outer_viewport_scroll_layer, overscroll_elasticity_layer,
@@ -1343,6 +1356,11 @@ void PropertyTreeBuilder::BuildPropertyTrees(
CheckScrollAndClipPointersForLayer(layer);
#endif
property_trees->ResetCachedData();
+ // During building property trees, all copy requests are moved from layers to
+ // effect tree, which are then pushed at commit to compositor thread and
+ // handled there. LayerTreeHost::has_copy_request is only required to
+ // decide if we want to create a effect node. So, it can be reset now.
+ root_layer->layer_tree_host()->SetHasCopyRequest(false);
}
void PropertyTreeBuilder::BuildPropertyTrees(
@@ -1365,6 +1383,7 @@ void PropertyTreeBuilder::BuildPropertyTrees(
SkColor color = root_layer->layer_tree_impl()->background_color();
if (SkColorGetA(color) != 255)
color = SkColorSetA(color, 255);
+ UpdateSubtreeHasCopyRequestRecursive(root_layer);
BuildPropertyTreesTopLevelInternal(
root_layer, page_scale_layer, inner_viewport_scroll_layer,
outer_viewport_scroll_layer, overscroll_elasticity_layer,
diff --git a/chromium/cc/trees/proxy_impl.cc b/chromium/cc/trees/proxy_impl.cc
index afced7e5c42..01a96109c89 100644
--- a/chromium/cc/trees/proxy_impl.cc
+++ b/chromium/cc/trees/proxy_impl.cc
@@ -126,10 +126,13 @@ void ProxyImpl::UpdateBrowserControlsStateOnImpl(
}
void ProxyImpl::InitializeCompositorFrameSinkOnImpl(
- CompositorFrameSink* compositor_frame_sink) {
+ CompositorFrameSink* compositor_frame_sink,
+ base::WeakPtr<ProxyMain> proxy_main_frame_sink_bound_weak_ptr) {
TRACE_EVENT0("cc", "ProxyImpl::InitializeCompositorFrameSinkOnImplThread");
DCHECK(IsImplThread());
+ proxy_main_frame_sink_bound_weak_ptr_ = proxy_main_frame_sink_bound_weak_ptr;
+
LayerTreeHostImpl* host_impl = layer_tree_host_impl_.get();
bool success = host_impl->InitializeRenderer(compositor_frame_sink);
MainThreadTaskRunner()->PostTask(
@@ -232,19 +235,26 @@ NOINLINE void ProxyImpl::DumpForBeginMainFrameHang() {
DCHECK(IsImplThread());
DCHECK(scheduler_);
- char stack_string[20000] = "";
- base::debug::Alias(&stack_string);
+ auto state = base::MakeUnique<base::trace_event::TracedValue>();
- std::unique_ptr<base::trace_event::ConvertableToTraceFormat> scheduler_state =
- scheduler_->AsValue();
- strncat(stack_string, scheduler_state->ToString().c_str(),
- arraysize(stack_string) - strlen(stack_string) - 1);
+ state->SetBoolean("commit_completion_waits_for_activation",
+ commit_completion_waits_for_activation_);
+ state->SetBoolean("commit_completion_event", !!commit_completion_event_);
+ state->SetBoolean("activation_completion_event",
+ !!activation_completion_event_);
- std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
- tile_manager_state =
- layer_tree_host_impl_->tile_manager()->ActivationStateAsValue();
- strncat(stack_string, tile_manager_state->ToString().c_str(),
- arraysize(stack_string) - strlen(stack_string) - 1);
+ state->BeginDictionary("scheduler_state");
+ scheduler_->AsValueInto(state.get());
+ state->EndDictionary();
+
+ state->BeginDictionary("tile_manager_state");
+ layer_tree_host_impl_->tile_manager()->ActivationStateAsValueInto(
+ state.get());
+ state->EndDictionary();
+
+ char stack_string[50000] = "";
+ base::debug::Alias(&stack_string);
+ strncpy(stack_string, state->ToString().c_str(), arraysize(stack_string) - 1);
base::debug::DumpWithoutCrashing();
}
@@ -307,7 +317,7 @@ void ProxyImpl::DidReceiveCompositorFrameAckOnImplThread() {
scheduler_->DidReceiveCompositorFrameAck();
MainThreadTaskRunner()->PostTask(
FROM_HERE, base::BindOnce(&ProxyMain::DidReceiveCompositorFrameAck,
- proxy_main_weak_ptr_));
+ proxy_main_frame_sink_bound_weak_ptr_));
}
void ProxyImpl::OnCanDrawStateChanged(bool can_draw) {
@@ -473,6 +483,11 @@ void ProxyImpl::DidFinishImplFrame() {
layer_tree_host_impl_->DidFinishImplFrame();
}
+void ProxyImpl::DidNotProduceFrame(const BeginFrameAck& ack) {
+ DCHECK(IsImplThread());
+ layer_tree_host_impl_->DidNotProduceFrame(ack);
+}
+
void ProxyImpl::ScheduledActionSendBeginMainFrame(const BeginFrameArgs& args) {
DCHECK(IsImplThread());
unsigned int begin_frame_id = nextBeginFrameId++;
@@ -602,6 +617,14 @@ void ProxyImpl::SendBeginMainFrameNotExpectedSoon() {
proxy_main_weak_ptr_));
}
+void ProxyImpl::ScheduledActionBeginMainFrameNotExpectedUntil(
+ base::TimeTicks time) {
+ DCHECK(IsImplThread());
+ MainThreadTaskRunner()->PostTask(
+ FROM_HERE, base::Bind(&ProxyMain::BeginMainFrameNotExpectedUntil,
+ proxy_main_weak_ptr_, time));
+}
+
DrawResult ProxyImpl::DrawInternal(bool forced_draw) {
TRACE_EVENT_SYNTHETIC_DELAY("cc.Draw");
diff --git a/chromium/cc/trees/proxy_impl.h b/chromium/cc/trees/proxy_impl.h
index 68edc334515..0953ae7a0e1 100644
--- a/chromium/cc/trees/proxy_impl.h
+++ b/chromium/cc/trees/proxy_impl.h
@@ -34,7 +34,8 @@ class CC_EXPORT ProxyImpl : public NON_EXPORTED_BASE(LayerTreeHostImplClient),
BrowserControlsState current,
bool animate);
void InitializeCompositorFrameSinkOnImpl(
- CompositorFrameSink* compositor_frame_sink);
+ CompositorFrameSink* compositor_frame_sink,
+ base::WeakPtr<ProxyMain> proxy_main_frame_sink_bound_weak_ptr);
void InitializeMutatorOnImpl(std::unique_ptr<LayerTreeMutator> mutator);
void MainThreadHasStoppedFlingingOnImpl();
void SetInputThrottledUntilCommitOnImpl(bool is_throttled);
@@ -97,6 +98,7 @@ class CC_EXPORT ProxyImpl : public NON_EXPORTED_BASE(LayerTreeHostImplClient),
// SchedulerClient implementation
void WillBeginImplFrame(const BeginFrameArgs& args) override;
void DidFinishImplFrame() override;
+ void DidNotProduceFrame(const BeginFrameAck& ack) override;
void ScheduledActionSendBeginMainFrame(const BeginFrameArgs& args) override;
DrawResult ScheduledActionDrawIfPossible() override;
DrawResult ScheduledActionDrawForced() override;
@@ -107,6 +109,8 @@ class CC_EXPORT ProxyImpl : public NON_EXPORTED_BASE(LayerTreeHostImplClient),
void ScheduledActionInvalidateCompositorFrameSink() override;
void ScheduledActionPerformImplSideInvalidation() override;
void SendBeginMainFrameNotExpectedSoon() override;
+ void ScheduledActionBeginMainFrameNotExpectedUntil(
+ base::TimeTicks time) override;
DrawResult DrawInternal(bool forced_draw);
@@ -149,6 +153,10 @@ class CC_EXPORT ProxyImpl : public NON_EXPORTED_BASE(LayerTreeHostImplClient),
// Used to post tasks to ProxyMain on the main thread.
base::WeakPtr<ProxyMain> proxy_main_weak_ptr_;
+ // A weak pointer to ProxyMain that is invalidated when CompositorFrameSink is
+ // released.
+ base::WeakPtr<ProxyMain> proxy_main_frame_sink_bound_weak_ptr_;
+
DISALLOW_COPY_AND_ASSIGN(ProxyImpl);
};
diff --git a/chromium/cc/trees/proxy_main.cc b/chromium/cc/trees/proxy_main.cc
index 6b06f0ee80f..8632105c293 100644
--- a/chromium/cc/trees/proxy_main.cc
+++ b/chromium/cc/trees/proxy_main.cc
@@ -36,6 +36,7 @@ ProxyMain::ProxyMain(LayerTreeHost* layer_tree_host,
commit_waits_for_activation_(false),
started_(false),
defer_commits_(false),
+ frame_sink_bound_weak_factory_(this),
weak_factory_(this) {
TRACE_EVENT0("cc", "ProxyMain::ProxyMain");
DCHECK(task_runner_provider_);
@@ -74,6 +75,12 @@ void ProxyMain::BeginMainFrameNotExpectedSoon() {
layer_tree_host_->BeginMainFrameNotExpectedSoon();
}
+void ProxyMain::BeginMainFrameNotExpectedUntil(base::TimeTicks time) {
+ TRACE_EVENT0("cc", "ProxyMain::BeginMainFrameNotExpectedUntil");
+ DCHECK(IsMainThread());
+ layer_tree_host_->BeginMainFrameNotExpectedUntil(time);
+}
+
void ProxyMain::DidCommitAndDrawFrame() {
DCHECK(IsMainThread());
layer_tree_host_->DidCommitAndDrawFrame();
@@ -288,9 +295,10 @@ bool ProxyMain::CommitToActiveTree() const {
void ProxyMain::SetCompositorFrameSink(
CompositorFrameSink* compositor_frame_sink) {
ImplThreadTaskRunner()->PostTask(
- FROM_HERE, base::BindOnce(&ProxyImpl::InitializeCompositorFrameSinkOnImpl,
- base::Unretained(proxy_impl_.get()),
- compositor_frame_sink));
+ FROM_HERE,
+ base::BindOnce(&ProxyImpl::InitializeCompositorFrameSinkOnImpl,
+ base::Unretained(proxy_impl_.get()), compositor_frame_sink,
+ frame_sink_bound_weak_factory_.GetWeakPtr()));
}
void ProxyMain::SetVisible(bool visible) {
@@ -469,6 +477,7 @@ bool ProxyMain::MainFrameWillHappenForTesting() {
void ProxyMain::ReleaseCompositorFrameSink() {
DCHECK(IsMainThread());
+ frame_sink_bound_weak_factory_.InvalidateWeakPtrs();
DebugScopedSetMainThreadBlocked main_thread_blocked(task_runner_provider_);
CompletionEvent completion;
ImplThreadTaskRunner()->PostTask(
diff --git a/chromium/cc/trees/proxy_main.h b/chromium/cc/trees/proxy_main.h
index 3d97276193a..e4ab354345e 100644
--- a/chromium/cc/trees/proxy_main.h
+++ b/chromium/cc/trees/proxy_main.h
@@ -42,6 +42,7 @@ class CC_EXPORT ProxyMain : public Proxy {
void DidReceiveCompositorFrameAck();
void BeginMainFrameNotExpectedSoon();
+ void BeginMainFrameNotExpectedUntil(base::TimeTicks time);
void DidCommitAndDrawFrame();
void SetAnimationEvents(std::unique_ptr<MutatorEvents> events);
void DidLoseCompositorFrameSink();
@@ -129,6 +130,10 @@ class CC_EXPORT ProxyMain : public Proxy {
// run before we destroy it on the impl thread.
std::unique_ptr<ProxyImpl> proxy_impl_;
+ // WeakPtrs generated by this factory will be invalidated when
+ // CompositorFrameSink is released.
+ base::WeakPtrFactory<ProxyMain> frame_sink_bound_weak_factory_;
+
base::WeakPtrFactory<ProxyMain> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ProxyMain);
diff --git a/chromium/cc/trees/scroll_node.cc b/chromium/cc/trees/scroll_node.cc
index 050dbf00294..3c8bcf78d02 100644
--- a/chromium/cc/trees/scroll_node.cc
+++ b/chromium/cc/trees/scroll_node.cc
@@ -16,9 +16,9 @@ ScrollNode::ScrollNode()
: id(ScrollTree::kInvalidNodeId),
parent_id(ScrollTree::kInvalidNodeId),
owning_layer_id(Layer::INVALID_ID),
- scrollable(false),
main_thread_scrolling_reasons(
MainThreadScrollingReason::kNotScrollingOnMain),
+ scrollable(false),
max_scroll_offset_affected_by_page_scale(false),
scrolls_inner_viewport(false),
scrolls_outer_viewport(false),
diff --git a/chromium/cc/trees/scroll_node.h b/chromium/cc/trees/scroll_node.h
index 4eefe42aff1..43841bf2f15 100644
--- a/chromium/cc/trees/scroll_node.h
+++ b/chromium/cc/trees/scroll_node.h
@@ -32,11 +32,6 @@ struct CC_EXPORT ScrollNode {
// composited layer list.
int owning_layer_id;
- // This is used for subtrees that should not be scrolled independently. For
- // example, when there is a layer that is not scrollable itself but is inside
- // a scrolling layer.
- bool scrollable;
-
uint32_t main_thread_scrolling_reasons;
Region non_fast_scrollable_region;
@@ -48,17 +43,21 @@ struct CC_EXPORT ScrollNode {
// Bounds of the overflow scrolling area.
gfx::Size bounds;
- bool max_scroll_offset_affected_by_page_scale;
- bool scrolls_inner_viewport;
- bool scrolls_outer_viewport;
+ // This is used for subtrees that should not be scrolled independently. For
+ // example, when there is a layer that is not scrollable itself but is inside
+ // a scrolling layer.
+ bool scrollable : 1;
+ bool max_scroll_offset_affected_by_page_scale : 1;
+ bool scrolls_inner_viewport : 1;
+ bool scrolls_outer_viewport : 1;
+ bool should_flatten : 1;
+ bool user_scrollable_horizontal : 1;
+ bool user_scrollable_vertical : 1;
// This offset is used when |scrollable| is false and there isn't a transform
// node already present that covers this offset.
gfx::Vector2dF offset_to_transform_parent;
- bool should_flatten;
- bool user_scrollable_horizontal;
- bool user_scrollable_vertical;
ElementId element_id;
int transform_id;
diff --git a/chromium/cc/trees/single_thread_proxy.cc b/chromium/cc/trees/single_thread_proxy.cc
index 07b5afa607a..1769c19fe60 100644
--- a/chromium/cc/trees/single_thread_proxy.cc
+++ b/chromium/cc/trees/single_thread_proxy.cc
@@ -52,6 +52,7 @@ SingleThreadProxy::SingleThreadProxy(LayerTreeHost* layer_tree_host,
inside_synchronous_composite_(false),
compositor_frame_sink_creation_requested_(false),
compositor_frame_sink_lost_(true),
+ frame_sink_bound_weak_factory_(this),
weak_factory_(this) {
TRACE_EVENT0("cc", "SingleThreadProxy::SingleThreadProxy");
DCHECK(task_runner_provider_);
@@ -123,6 +124,7 @@ void SingleThreadProxy::RequestNewCompositorFrameSink() {
void SingleThreadProxy::ReleaseCompositorFrameSink() {
compositor_frame_sink_lost_ = true;
+ frame_sink_bound_weak_factory_.InvalidateWeakPtrs();
if (scheduler_on_impl_thread_)
scheduler_on_impl_thread_->DidLoseCompositorFrameSink();
return layer_tree_host_impl_->ReleaseCompositorFrameSink();
@@ -141,6 +143,7 @@ void SingleThreadProxy::SetCompositorFrameSink(
}
if (success) {
+ frame_sink_bound_weak_ptr_ = frame_sink_bound_weak_factory_.GetWeakPtr();
layer_tree_host_->DidInitializeCompositorFrameSink();
if (scheduler_on_impl_thread_)
scheduler_on_impl_thread_->DidCreateAndInitializeCompositorFrameSink();
@@ -425,7 +428,12 @@ void SingleThreadProxy::DidReceiveCompositorFrameAckOnImplThread() {
"SingleThreadProxy::DidReceiveCompositorFrameAckOnImplThread");
if (scheduler_on_impl_thread_)
scheduler_on_impl_thread_->DidReceiveCompositorFrameAck();
- layer_tree_host_->DidReceiveCompositorFrameAck();
+ // We do a PostTask here because freeing resources in some cases (such as in
+ // TextureLayer) is PostTasked and we want to make sure ack is received after
+ // resources are returned.
+ task_runner_provider_->MainThreadTaskRunner()->PostTask(
+ FROM_HERE, base::Bind(&SingleThreadProxy::DidReceiveCompositorFrameAck,
+ frame_sink_bound_weak_ptr_));
}
void SingleThreadProxy::OnDrawForCompositorFrameSink(
@@ -624,6 +632,11 @@ void SingleThreadProxy::SendBeginMainFrameNotExpectedSoon() {
layer_tree_host_->BeginMainFrameNotExpectedSoon();
}
+void SingleThreadProxy::ScheduledActionBeginMainFrameNotExpectedUntil(
+ base::TimeTicks time) {
+ layer_tree_host_->BeginMainFrameNotExpectedUntil(time);
+}
+
void SingleThreadProxy::BeginMainFrame(const BeginFrameArgs& begin_frame_args) {
if (scheduler_on_impl_thread_) {
scheduler_on_impl_thread_->NotifyBeginMainFrameStarted(
@@ -794,4 +807,13 @@ void SingleThreadProxy::DidFinishImplFrame() {
#endif
}
+void SingleThreadProxy::DidNotProduceFrame(const BeginFrameAck& ack) {
+ DebugScopedSetImplThread impl(task_runner_provider_);
+ layer_tree_host_impl_->DidNotProduceFrame(ack);
+}
+
+void SingleThreadProxy::DidReceiveCompositorFrameAck() {
+ layer_tree_host_->DidReceiveCompositorFrameAck();
+}
+
} // namespace cc
diff --git a/chromium/cc/trees/single_thread_proxy.h b/chromium/cc/trees/single_thread_proxy.h
index 4a091950a27..54842c41bf2 100644
--- a/chromium/cc/trees/single_thread_proxy.h
+++ b/chromium/cc/trees/single_thread_proxy.h
@@ -62,6 +62,7 @@ class CC_EXPORT SingleThreadProxy : public Proxy,
// SchedulerClient implementation
void WillBeginImplFrame(const BeginFrameArgs& args) override;
void DidFinishImplFrame() override;
+ void DidNotProduceFrame(const BeginFrameAck& ack) override;
void ScheduledActionSendBeginMainFrame(const BeginFrameArgs& args) override;
DrawResult ScheduledActionDrawIfPossible() override;
DrawResult ScheduledActionDrawForced() override;
@@ -72,6 +73,8 @@ class CC_EXPORT SingleThreadProxy : public Proxy,
void ScheduledActionInvalidateCompositorFrameSink() override;
void ScheduledActionPerformImplSideInvalidation() override;
void SendBeginMainFrameNotExpectedSoon() override;
+ void ScheduledActionBeginMainFrameNotExpectedUntil(
+ base::TimeTicks time) override;
// LayerTreeHostImplClient implementation
void DidLoseCompositorFrameSinkOnImplThread() override;
@@ -122,6 +125,8 @@ class CC_EXPORT SingleThreadProxy : public Proxy,
bool ShouldComposite() const;
void ScheduleRequestNewCompositorFrameSink();
+ void DidReceiveCompositorFrameAck();
+
// Accessed on main thread only.
LayerTreeHost* layer_tree_host_;
LayerTreeHostSingleThreadClient* single_thread_client_;
@@ -158,6 +163,12 @@ class CC_EXPORT SingleThreadProxy : public Proxy,
// This is the callback for the scheduled RequestNewCompositorFrameSink.
base::CancelableClosure compositor_frame_sink_creation_callback_;
+ base::WeakPtr<SingleThreadProxy> frame_sink_bound_weak_ptr_;
+
+ // WeakPtrs generated by this factory will be invalidated when
+ // CompositorFrameSink is released.
+ base::WeakPtrFactory<SingleThreadProxy> frame_sink_bound_weak_factory_;
+
base::WeakPtrFactory<SingleThreadProxy> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(SingleThreadProxy);
diff --git a/chromium/cc/trees/transform_node.h b/chromium/cc/trees/transform_node.h
index 76f2a7c2ffc..2abfb1cc004 100644
--- a/chromium/cc/trees/transform_node.h
+++ b/chromium/cc/trees/transform_node.h
@@ -69,14 +69,27 @@ struct CC_EXPORT TransformNode {
// TODO(vollick): will be moved when accelerated effects are implemented.
bool needs_local_transform_update : 1;
+ // Whether this node or any ancestor has a potentially running
+ // (i.e., irrespective of exact timeline) transform animation or an
+ // invertible transform.
bool node_and_ancestors_are_animated_or_invertible : 1;
bool is_invertible : 1;
+ // Whether the transform from this node to the screen is
+ // invertible.
bool ancestors_are_invertible : 1;
+ // Whether this node has a potentially running (i.e., irrespective
+ // of exact timeline) transform animation.
bool has_potential_animation : 1;
+ // Whether this node has a currently running transform animation.
bool is_currently_animating : 1;
+ // Whether this node *or an ancestor* has a potentially running
+ // (i.e., irrespective of exact timeline) transform
+ // animation.
bool to_screen_is_potentially_animated : 1;
+ // Whether all animations on this transform node are simple
+ // translations.
bool has_only_translation_animations : 1;
// Flattening, when needed, is only applied to a node's inherited transform,
diff --git a/chromium/cc/trees/tree_synchronizer.cc b/chromium/cc/trees/tree_synchronizer.cc
index 52f1bb384c7..87efee06cab 100644
--- a/chromium/cc/trees/tree_synchronizer.cc
+++ b/chromium/cc/trees/tree_synchronizer.cc
@@ -74,6 +74,25 @@ std::unique_ptr<LayerImpl> ReuseOrCreateLayerImpl(OwnedLayerImplMap* old_layers,
return layer_impl;
}
+#if DCHECK_IS_ON()
+template <typename LayerType>
+static void AssertValidPropertyTreeIndices(LayerType* layer) {
+ DCHECK(layer);
+ DCHECK_NE(layer->transform_tree_index(), TransformTree::kInvalidNodeId);
+ DCHECK_NE(layer->effect_tree_index(), EffectTree::kInvalidNodeId);
+ DCHECK_NE(layer->clip_tree_index(), ClipTree::kInvalidNodeId);
+ DCHECK_NE(layer->scroll_tree_index(), ScrollTree::kInvalidNodeId);
+}
+
+static bool LayerHasValidPropertyTreeIndices(LayerImpl* layer) {
+ DCHECK(layer);
+ return layer->transform_tree_index() != TransformTree::kInvalidNodeId &&
+ layer->effect_tree_index() != EffectTree::kInvalidNodeId &&
+ layer->clip_tree_index() != ClipTree::kInvalidNodeId &&
+ layer->scroll_tree_index() != ScrollTree::kInvalidNodeId;
+}
+#endif
+
template <typename LayerTreeType>
void PushLayerList(OwnedLayerImplMap* old_layers,
LayerTreeType* host,
@@ -83,6 +102,15 @@ void PushLayerList(OwnedLayerImplMap* old_layers,
std::unique_ptr<LayerImpl> layer_impl(
ReuseOrCreateLayerImpl(old_layers, layer, tree_impl));
+#if DCHECK_IS_ON()
+ // Every layer should have valid property tree indices
+ AssertValidPropertyTreeIndices(layer);
+ // Every layer_impl should either have valid property tree indices already
+ // or the corresponding layer should push them onto layer_impl.
+ DCHECK(LayerHasValidPropertyTreeIndices(layer_impl.get()) ||
+ host->LayerNeedsPushPropertiesForTesting(layer));
+#endif
+
tree_impl->AddToLayerList(layer_impl.get());
tree_impl->AddLayer(std::move(layer_impl));
}
diff --git a/chromium/cc/trees/tree_synchronizer_unittest.cc b/chromium/cc/trees/tree_synchronizer_unittest.cc
index cbae4e4aea1..1def71a2b67 100644
--- a/chromium/cc/trees/tree_synchronizer_unittest.cc
+++ b/chromium/cc/trees/tree_synchronizer_unittest.cc
@@ -165,6 +165,7 @@ TEST_F(TreeSynchronizerTest, SyncSimpleTreeFromEmpty) {
layer_tree_root->AddChild(Layer::Create());
host_->SetRootLayer(layer_tree_root);
+ host_->BuildPropertyTreesForTesting();
TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(),
host_->active_tree());
@@ -186,6 +187,7 @@ TEST_F(TreeSynchronizerTest, SyncSimpleTreeReusingLayers) {
int second_layer_impl_id = layer_tree_root->children()[1]->id();
host_->SetRootLayer(layer_tree_root);
+ host_->BuildPropertyTreesForTesting();
TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(),
host_->active_tree());
@@ -206,6 +208,7 @@ TEST_F(TreeSynchronizerTest, SyncSimpleTreeReusingLayers) {
// Synchronize again. After the sync the trees should be equivalent and we
// should have created and destroyed one LayerImpl.
+ host_->BuildPropertyTreesForTesting();
TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(),
host_->active_tree());
layer_impl_tree_root = host_->active_tree()->root_layer_for_testing();
@@ -236,6 +239,7 @@ TEST_F(TreeSynchronizerTest, SyncSimpleTreeAndTrackStackingOrderChange) {
host_->SetRootLayer(layer_tree_root);
+ host_->BuildPropertyTreesForTesting();
TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(),
host_->active_tree());
LayerImpl* layer_impl_tree_root =
@@ -252,12 +256,15 @@ TEST_F(TreeSynchronizerTest, SyncSimpleTreeAndTrackStackingOrderChange) {
// re-insert the layer and sync again.
child2->RemoveFromParent();
layer_tree_root->AddChild(child2);
+ host_->BuildPropertyTreesForTesting();
TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(),
host_->active_tree());
layer_impl_tree_root = host_->active_tree()->root_layer_for_testing();
ExpectTreesAreIdentical(layer_tree_root.get(), layer_impl_tree_root,
host_->active_tree());
+ host_->active_tree()->SetPropertyTrees(
+ layer_tree_root->layer_tree_host()->property_trees());
TreeSynchronizer::PushLayerProperties(layer_tree_root->layer_tree_host(),
host_->active_tree());
@@ -284,9 +291,9 @@ TEST_F(TreeSynchronizerTest, SyncSimpleTreeAndProperties) {
gfx::Size second_child_bounds = gfx::Size(25, 53);
layer_tree_root->children()[1]->SetBounds(second_child_bounds);
- layer_tree_root->children()[1]->SavePaintProperties();
int second_child_id = layer_tree_root->children()[1]->id();
+ host_->BuildPropertyTreesForTesting();
TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(),
host_->active_tree());
LayerImpl* layer_impl_tree_root =
@@ -335,6 +342,7 @@ TEST_F(TreeSynchronizerTest, ReuseLayerImplsAfterStructuralChange) {
scoped_refptr<Layer> layer_d = layer_b->children()[1];
host_->SetRootLayer(layer_tree_root);
+ host_->BuildPropertyTreesForTesting();
TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(),
host_->active_tree());
@@ -363,6 +371,7 @@ TEST_F(TreeSynchronizerTest, ReuseLayerImplsAfterStructuralChange) {
// After another synchronize our trees should match and we should not have
// destroyed any LayerImpls
+ host_->BuildPropertyTreesForTesting();
TreeSynchronizer::SynchronizeTrees(layer_tree_root.get(),
host_->active_tree());
layer_impl_tree_root = host_->active_tree()->root_layer_for_testing();
@@ -392,6 +401,7 @@ TEST_F(TreeSynchronizerTest, SyncSimpleTreeThenDestroy) {
int old_tree_first_child_layer_id = old_layer_tree_root->children()[0]->id();
int old_tree_second_child_layer_id = old_layer_tree_root->children()[1]->id();
+ host_->BuildPropertyTreesForTesting();
TreeSynchronizer::SynchronizeTrees(old_layer_tree_root.get(),
host_->active_tree());
LayerImpl* layer_impl_tree_root =
@@ -411,6 +421,7 @@ TEST_F(TreeSynchronizerTest, SyncSimpleTreeThenDestroy) {
scoped_refptr<Layer> new_layer_tree_root = Layer::Create();
host_->SetRootLayer(new_layer_tree_root);
+ host_->BuildPropertyTreesForTesting();
TreeSynchronizer::SynchronizeTrees(new_layer_tree_root.get(),
host_->active_tree());
layer_impl_tree_root = host_->active_tree()->root_layer_for_testing();
@@ -493,7 +504,7 @@ TEST_F(TreeSynchronizerTest, SynchronizeCurrentlyScrollingNode) {
transient_scroll_layer->AddChild(scroll_clip_layer);
scroll_clip_layer->AddChild(scroll_layer);
- ElementId scroll_element_id = ElementId(5, 4);
+ ElementId scroll_element_id = ElementId(5);
scroll_layer->SetElementId(scroll_element_id);
transient_scroll_layer->SetScrollClipLayerId(
@@ -540,7 +551,7 @@ TEST_F(TreeSynchronizerTest, SynchronizeScrollTreeScrollOffsetMap) {
scoped_refptr<Layer> transient_scroll_clip_layer = Layer::Create();
scoped_refptr<Layer> transient_scroll_layer = Layer::Create();
- ElementId scroll_element_id = ElementId(5, 4);
+ ElementId scroll_element_id = ElementId(5);
scroll_layer->SetElementId(scroll_element_id);
layer_tree_root->AddChild(transient_scroll_clip_layer);